Repository: iosifpeterfi/openCAPWAP-OpenWRT Branch: master Commit: 1c1984d6cf7f Files: 167 Total size: 2.2 MB Directory structure: gitextract_iujx8crt/ ├── .gitignore ├── AC.c ├── ACAppsProtocol.h ├── ACBinding.c ├── ACBinding.h ├── ACConfigFile.c ├── ACConfigureState.c ├── ACDataCheckState.c ├── ACDiscoveryState.c ├── ACInterface.c ├── ACInterface.h ├── ACJoinState.c ├── ACMainLoop.c ├── ACMultiHomedSocket.c ├── ACMultiHomedSocket.h ├── ACProtocol.c ├── ACProtocol.h ├── ACProtocol_User.c ├── ACRetransmission.c ├── ACRunState.c ├── ACSettingsFile.c ├── ACipcHostapd.c ├── ACipcHostapd.h ├── COPYING ├── CWAC.h ├── CWBinding.c ├── CWBinding.h ├── CWCommon.c ├── CWCommon.h ├── CWConfigFile.c ├── CWConfigFile.h ├── CWErrorHandling.c ├── CWErrorHandling.h ├── CWFreqPayloads.h ├── CWList.c ├── CWList.h ├── CWLog.c ├── CWLog.h ├── CWNetwork.c ├── CWNetwork.h ├── CWOpenSSLBio.c ├── CWProtocol.c ├── CWProtocol.h ├── CWRandom.c ├── CWRandom.h ├── CWSafeList.c ├── CWSafeList.h ├── CWSecurity.c ├── CWSecurity.h ├── CWStevens.c ├── CWStevens.h ├── CWThread.c ├── CWThread.h ├── CWTimer.h ├── CWVendorPayloads.h ├── CWVendorPayloadsAC.c ├── CWVendorPayloadsWTP.c ├── CWWTP.h ├── Doxyfile ├── INSTALL.rst ├── Makefile.am ├── Makefile.bcm ├── Makefile.glibc ├── Makefile.uclibc ├── MakefileMac ├── README.md ├── WTP.c ├── WTPBcmDriverInteraction.c ├── WTPBcmDriverInteraction.h ├── WTPBcmFrameReceive.c ├── WTPBcmFrameReceive.h ├── WTPBinding.c ├── WTPBinding.h ├── WTPConfigFile.c ├── WTPConfigureState.c ├── WTPDataCheckState.c ├── WTPDiscoveryState.c ├── WTPDriverInteraction.c ├── WTPFrameReceive.c ├── WTPFrameReceive.h ├── WTPFreqStatsReceive.c ├── WTPFreqStatsReceive.h ├── WTPJoinState.c ├── WTPProtocol.c ├── WTPProtocol.h ├── WTPProtocol_User.c ├── WTPRetransmission.c ├── WTPRunState.c ├── WTPRunStateCheck.c ├── WTPSettingsFile.c ├── WTPStatsReceive.c ├── WTPStatsReceive.h ├── WTPSulkingState.c ├── WTPipcHostapd.c ├── WTPipcHostapd.h ├── WTPmacDriverInteraction.c ├── WTPmacDriverInteraction.h ├── WTPmacFrameReceive.c ├── WTPmacFrameReceive.h ├── WUA.c ├── WUM.h ├── capwap_bugfix_0.01 ├── changeLog-0.92 ├── changeLog-0.93 ├── changeLog-0.93.3 ├── client.pem ├── common.h ├── config.ac ├── config.wtp ├── configure.ac ├── debian-install.sh ├── hostapd_wrapper/ │ ├── README.rst │ ├── hostapd-capwap.patch │ ├── hostapd.conf-ac │ ├── hostapd.conf-wtp │ ├── hostapd2/ │ │ ├── README.Debian │ │ ├── hostapd-20130302-linux.patch │ │ ├── hostapd-20130302.tar.bz2 │ │ ├── hostapd_linux.conf │ │ ├── hostapd_linux_ac.conf │ │ └── linux-ac.sh │ ├── hostapd_ac.conf │ ├── hostapd_wtp.conf │ └── src/ │ ├── capwap/ │ │ ├── capwap_mgmt_frame_ac.c │ │ ├── capwap_mgmt_frame_ac.h │ │ ├── capwap_mgmt_frame_wtp.c │ │ ├── capwap_mgmt_frame_wtp.h │ │ ├── file_conf_ac.h │ │ ├── file_conf_wtp.h │ │ ├── ipc_capwap_ac.c │ │ ├── ipc_capwap_ac.h │ │ ├── ipc_capwap_wtp.c │ │ ├── ipc_capwap_wtp.h │ │ ├── smac_code.h │ │ ├── switch_8023_80211.c │ │ └── switch_8023_80211.h │ └── drivers/ │ ├── driver_capwap.c │ ├── driver_capwap_wtp.c │ ├── linux_ioctl_fake.c │ ├── linux_ioctl_fake.h │ ├── netlink_fake.c │ └── netlink_fake.h ├── ieee802_11_defs.h ├── modifiche_daniele.txt ├── modifiche_uci_frequency_2009.txt ├── os.h ├── packages/ │ ├── Debian-6/ │ │ ├── hostapd-cw_2.0-1_all.deb │ │ ├── nltiny_2.0-1_all.deb │ │ └── opencapwap_0.99b-1_all.deb │ └── FC18/ │ └── x86_64/ │ ├── README.FC18 │ ├── capwap-ac-0.9b-3.fc18.x86_64.rpm │ ├── hostapd-capwap-20130302-3.fc18.x86_64.rpm │ └── libnl-tiny-2.0-1.fc18.x86_64.rpm ├── root.pem ├── server.pem ├── settings.ac.txt ├── settings.wtp.txt ├── smac_code.h ├── tap.c ├── tap.h ├── timerlib.c ├── timerlib.h ├── wireless_copy.h └── wum/ ├── README ├── wum.c ├── wumLib.c └── wumLib.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *~ *.o *.lo *.la m4 .deps .libs # # binaries # AC WTP WUA # # autoconf files # Makefile Makefile.in aclocal.m4 autom4te.cache/ compile config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh missing stamp-h1 ================================================ FILE: AC.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #include "CWCommon.h" #include "tap.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /*_________________________________________________________*/ /* *******************___VARIABLES___******************* */ CWThreadMutex gCreateIDMutex; /* array that stores per WTPs infos */ CWWTPManager gWTPs[CW_MAX_WTP]; CWThreadMutex gWTPsMutex; int gEnabledLog; int gMaxLogFileSize; char gLogFileName[] = AC_LOG_FILE_NAME; /* number of active WTPs */ int gActiveWTPs = 0; CWThreadMutex gActiveWTPsMutex; /* max WTPs */ int gMaxWTPs; /* The Radio MAC Field of the discovery response */ int gRMACField = 2; /* The Wireless Field of the discovery response */ int gWirelessField = 0; /* DTLS Policy for data channel */ int gDTLSPolicy = DTLS_ENABLED_DATA; /* special socket to handle multiple network interfaces */ CWMultiHomedSocket gACSocket; /* AC's network interfaces */ CWProtocolNetworkInterface *gInterfaces = NULL; int gInterfacesCount = 0; /* DTLS Context */ CWSecurityContext gACSecurityContext; int gActiveStations = 0; /* max stations */ int gLimit; char **gMulticastGroups; int gMulticastGroupsCount; CWAuthSecurity gACDescriptorSecurity; int gACHWVersion; int gACSWVersion; char *gACName = NULL; int gDiscoveryTimer = 20; int gEchoRequestTimer = CW_ECHO_INTERVAL_DEFAULT; /* PROVVISORIO: Il valore e' scelto a caso */ int gIdleTimeout = 10; /*_________________________________________________________*/ /* *******************___FUNCTIONS___******************* */ void usage(void) { } int main(int argc, char * const argv[]) { int run_daemon = 1; int c; #ifdef CW_DEBUGGING const struct rlimit rlim = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY }; /* unlimited size for cores */ setrlimit(RLIMIT_CORE, &rlim); #endif while (-1 != (c = getopt(argc, argv, "hf"))) { switch(c) { case 'h': usage(); exit(1); break; case 'f': run_daemon = 0; break; default: usage(); exit(1); break; } } /* Daemon Mode */ if (run_daemon) if (daemon(1, 0) != 0) { fprintf(stderr, "daemon failed: %s\n", strerror(errno)); exit(1); } CWACInit(); CWCreateConnectionWithHostapdAC(); CWACEnterMainLoop(); CWACDestroy(); CWLogCloseFile(); return 0; } int CWACSemPostForOpenSSLHack(void *s) { CWThreadTimedSem *semPtr = (CWThreadTimedSem *) s; if (!CWThreadTimedSemIsZero(semPtr)) { CWLog("This Semaphore's Value should really be 0"); /* note: we can consider setting the value to 0 and going on, * that is what we do here */ if (!CWErr(CWThreadTimedSemSetValue(semPtr, 0))) return 0; } if (!CWErr(CWThreadTimedSemPost(semPtr))) { return 0; } return 1; } void CWACInit() { int i; CWNetworkLev4Address *addresses = NULL; struct sockaddr_in *IPv4Addresses = NULL; CWLogInitFile(AC_LOG_FILE_NAME); #ifndef CW_SINGLE_THREAD CWDebugLog("Use Threads"); #else CWDebugLog("Don't Use Threads"); #endif CWErrorHandlingInitLib(); if (!CWParseSettingsFile()) { fprintf(stderr,"Can't load AC settings file\n"); exit(1); } CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); if (timer_init() == 0) { fprintf(stderr,"Can't init timer module\n"); exit(1); } if (!CWErr(CWParseConfigFile())) { /* error starting */ fprintf(stderr,"Can't load AC config file\n"); exit(1); } CWDebugLog("Starting AC"); CWDebugLog("Waiting for WTPs to enter join state"); sleep(CW_NEIGHBORDEAD_INTERVAL_DEFAULT+CW_ECHO_INTERVAL_DEFAULT); if ( #ifndef CW_NO_DTLS !CWErr(CWSecurityInitLib()) || #endif !CWErr(CWNetworkInitSocketServerMultiHomed (&gACSocket, CW_CONTROL_PORT, gMulticastGroups, gMulticastGroupsCount)) || !CWErr(CWNetworkGetInterfaceAddresses(&gACSocket, &addresses, &IPv4Addresses)) || !CWErr(CWCreateThreadMutex(&gWTPsMutex)) || !CWErr(CWCreateThreadMutex(&gActiveWTPsMutex))) { /* error starting */ CWLog("Can't start AC"); exit(1); } #ifndef CW_NO_DTLS if (gACDescriptorSecurity == CW_X509_CERTIFICATE) { if (!CWErr(CWSecurityInitContext(&gACSecurityContext, "root.pem", "server.pem", "prova", CW_FALSE, CWACSemPostForOpenSSLHack))) { CWLog("Can't start AC"); exit(1); } } else { /* preshared */ if (!CWErr(CWSecurityInitContext(&gACSecurityContext, NULL, NULL, NULL, CW_FALSE, CWACSemPostForOpenSSLHack))) { CWLog("Can't start AC"); exit(1); } } #endif CW_FREE_OBJECTS_ARRAY(gMulticastGroups, gMulticastGroupsCount); for (i = 0; i < gMaxWTPs; i++) { gWTPs[i].isNotFree = CW_FALSE; if (!gWTPs[i].tap_fd) { init_AC_tap_interface(i); } } /* store network interface's addresses */ gInterfacesCount = CWNetworkCountInterfaceAddresses(&gACSocket); CWLog("Found %d Network Interface(s)", gInterfacesCount); if (gInterfacesCount <= 0) { CWLog("Can't start AC"); exit(1); } CW_CREATE_ARRAY_ERR(gInterfaces, gInterfacesCount, CWProtocolNetworkInterface, CWLog("Out of Memory"); return; ); for (i = 0; i < gInterfacesCount; i++) { gInterfaces[i].WTPCount = 0; CW_COPY_NET_ADDR_PTR(&(gInterfaces[i].addr), ((CWNetworkLev4Address *) & ((addresses)[i]))); if (IPv4Addresses != NULL) { CW_COPY_NET_ADDR_PTR(&(gInterfaces[i].addrIPv4), &((IPv4Addresses)[i])); } } CW_FREE_OBJECT(addresses); CW_FREE_OBJECT(IPv4Addresses); if (!CWErr(CWCreateThreadMutex(&gCreateIDMutex))) { exit(1); } CWLog("AC Started"); } void CWCreateConnectionWithHostapdAC() { CWThread thread_ipc_with_ac_hostapd; if (!CWErr(CWCreateThread(&thread_ipc_with_ac_hostapd, CWACipc_with_ac_hostapd, NULL))) { CWLog("Error starting Thread that receive command and 802.11 frame from hostapd (WTP side)"); exit(1); } } void CWACDestroy() { CWNetworkCloseMultiHomedSocket(&gACSocket); /* for(i = 0; i < CW_MAX_WTP; i++) { //CW_FREE_OBJECT(gWTPs[i].addr); } */ #ifndef CW_NO_DTLS CWSslCleanUp(); #endif CWDestroyThreadMutex(&gWTPsMutex); CWDestroyThreadMutex(&gCreateIDMutex); CWDestroyThreadMutex(&gActiveWTPsMutex); CW_FREE_OBJECT(gACName); CW_FREE_OBJECT(gInterfaces); CWLog("AC Destroyed"); } unsigned int CWGetSeqNum() { static unsigned int seqNum = 0; unsigned int r; if (!CWThreadMutexLock(&gCreateIDMutex)) { CWDebugLog("Error Locking a mutex"); } r = seqNum; if (seqNum == CW_MAX_SEQ_NUM) seqNum = 0; else seqNum++; CWThreadMutexUnlock(&gCreateIDMutex); return r; } int CWGetFragmentID() { static int fragID = 0; int r; if (!CWThreadMutexLock(&gCreateIDMutex)) { CWDebugLog("Error Locking a mutex"); } r = fragID; if (fragID == CW_MAX_FRAGMENT_ID) fragID = 0; else fragID++; CWThreadMutexUnlock(&gCreateIDMutex); return r; } ================================================ FILE: ACAppsProtocol.h ================================================ /* * appsToAcProtocol.h * * * Created by Antonio Davoli on 03/03/09. * Copyright 2009 La Sapienza. All rights reserved. * */ /* Macro Definition */ /* AC Request Message */ /**************************************** * For LIST, QUIT (without argument) * * * * 0 7 * * +-+-+-+-+-+-+-+-+ * * | Cmd_msg | * * +-+-+-+-+-+-+-+-+ * * * ****************************************/ /* CMD_MSG Types */ #define FULL_CLIENT_CONNECTED -1 #define CONNECTION_OK 1 #define QUIT_MSG 0 #define LIST_MSG 1 #define CONF_UPDATE_MSG 2 /******************************************************************************************************************************** * List Response Message: * * * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * | Active# | WTP_ID 1 | NameLength 1 | WTP Name 1 | ... | WTP ID N | NameLength N | WTP Name N | * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * * * where N is equal to Active# (Number of Active WTPs) * ********************************************************************************************************************************/ /******************************************************************************************************** * For CONF_UPDATE_MSG type: * * * * 0 7 15 23 X * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * | cmd_msg | msg_elem | WPT Index | Message Specific Payload | * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * * ********************************************************************************************************/ #define PAYLOAD_START ((sizeof(unsigned char)*2) + sizeof(int)) #define ALL_ACTIVE_WTPS -1 #define MSG_ELEMENT_TYPE_OFDM 1 #define MSG_ELEMENT_TYPE_VENDOR_UCI 2 #define MSG_ELEMENT_TYPE_VENDOR_WUM 3 /**************************************************************************************** * Message Specific Payload for MSG_ELEMENT_TYPE_OFDM TYPE (802.11 Binding Version) * * * * 0 1 2 3 * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * | Radio ID | Reserved | Current Chan | Band Support | * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * | TI Threshold | * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * * ****************************************************************************************/ /* Radio ID is filled in the creation message funcion (inside the AC) */ ================================================ FILE: ACBinding.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Daniele De Sanctis (danieledesanctis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWACInitBinding(int i) { int j; bindingValues *aux; CW_CREATE_OBJECT_ERR(aux, bindingValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (gWTPs[i].WTPProtocolManager).bindingValuesPtr = (void *)aux; CW_CREATE_ARRAY_ERR(aux->qosValues, NUM_QOS_PROFILES, WTPQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); //Init default values for (j = 0; j < NUM_QOS_PROFILES; j++) { aux->qosValues[j].cwMin = gDefaultQosValues[j].cwMin; aux->qosValues[j].cwMax = gDefaultQosValues[j].cwMax; aux->qosValues[j].AIFS = gDefaultQosValues[j].AIFS; aux->qosValues[j].queueDepth = 0; aux->qosValues[j].dot1PTag = 0; aux->qosValues[j].DSCPTag = 0; } return CW_TRUE; } CWBool CWMergeQosValues(int WTPIndex) { int i; bindingValues *aux; aux = (bindingValues *) (gWTPs[WTPIndex].WTPProtocolManager).bindingValuesPtr; for (i = 0; i < NUM_QOS_PROFILES; i++) { if (gWTPs[WTPIndex].qosValues[i].cwMin == UNUSED_QOS_VALUE) { gWTPs[WTPIndex].qosValues[i].cwMin = aux->qosValues[i].cwMin; } if (gWTPs[WTPIndex].qosValues[i].cwMax == UNUSED_QOS_VALUE) { gWTPs[WTPIndex].qosValues[i].cwMax = aux->qosValues[i].cwMax; } if (gWTPs[WTPIndex].qosValues[i].AIFS == UNUSED_QOS_VALUE) { gWTPs[WTPIndex].qosValues[i].AIFS = aux->qosValues[i].AIFS; } } return CW_TRUE; } /****************************************************************** * 2009 Updates: * * Functions for management of Configuration Update * * Request with OFDM Message Element * ******************************************************************/ CWBool CWMergeOFDMValues(int WTPIndex) { OFDMControlValues *aux; aux = (OFDMControlValues *) (gWTPs[WTPIndex].WTPProtocolManager).bindingValuesPtr; if (gWTPs[WTPIndex].ofdmValues->currentChan == UNUSED_OFDM_VALUE) gWTPs[WTPIndex].ofdmValues->currentChan = aux->currentChan; if (gWTPs[WTPIndex].ofdmValues->BandSupport == UNUSED_OFDM_VALUE) gWTPs[WTPIndex].ofdmValues->BandSupport = aux->BandSupport; if (gWTPs[WTPIndex].ofdmValues->TIThreshold == UNUSED_OFDM_VALUE) gWTPs[WTPIndex].ofdmValues->TIThreshold = aux->TIThreshold; return CW_TRUE; } CWBool CWAssembleWTPOFDM(CWProtocolMessage * msgPtr, int radioID) { const int totalMessageLength = BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL_LENGTH; int *iPtr; OFDMControlValues *valuesPtr; CWLog("Assembling Binding Configuration Update Request [OFDM CASE]..."); if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } if (!CWMergeOFDMValues(*iPtr)) { return CW_FALSE; } valuesPtr = gWTPs[*iPtr].ofdmValues; /* create message */ CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, totalMessageLength, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, radioID); CWProtocolStore32(msgPtr, valuesPtr->currentChan); CWProtocolStore8(msgPtr, valuesPtr->BandSupport); CWProtocolStore32(msgPtr, valuesPtr->TIThreshold); CWLog("Assembling Binding Configuration Update Request [OFDM CASE]: Message Assembled."); return CWAssembleMsgElem(msgPtr, BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL); } CWBool CWAssembleWTPQoS(CWProtocolMessage * msgPtr, int radioID, int tagPackets) { const int headerLength = 2; const int messageBodyLength = 32; const int totalMessageLength = headerLength + messageBodyLength; int i; int *iPtr; WTPQosValues *valuesPtr; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } if (!CWMergeQosValues(*iPtr)) { return CW_FALSE; } valuesPtr = gWTPs[*iPtr].qosValues; // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, totalMessageLength, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, radioID); CWProtocolStore8(msgPtr, tagPackets); for (i = 0; i < NUM_QOS_PROFILES; i++) { CWProtocolStore8(msgPtr, valuesPtr[i].queueDepth); CWProtocolStore16(msgPtr, valuesPtr[i].cwMin); CWProtocolStore16(msgPtr, valuesPtr[i].cwMax); CWProtocolStore8(msgPtr, valuesPtr[i].AIFS); CWProtocolStore8(msgPtr, valuesPtr[i].dot1PTag); CWProtocolStore8(msgPtr, valuesPtr[i].DSCPTag); } return CWAssembleMsgElem(msgPtr, BINDING_MSG_ELEMENT_TYPE_WTP_QOS); } CWBool CWBindingAssembleConfigureResponse(CWProtocolMessage ** msgElems, int *msgElemCountPtr) { CWWTPRadiosInfo radiosInfo; int *iPtr; const int tagPackets = 0; int k = -1, radioCount, radioID, j; if (msgElems == NULL || msgElemCountPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } //Calculate the number of msg Elements *msgElemCountPtr = 0; radiosInfo = gWTPs[*iPtr].WTPProtocolManager.radiosInfo; radioCount = radiosInfo.radioCount; *msgElemCountPtr = radioCount; CWLog("Assembling Binding Configuration Response..."); //Reserve memory for msg Elements CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(*msgElems, *msgElemCountPtr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!CWThreadMutexLock(&(gWTPs[*iPtr].interfaceMutex))) { CWLog("Error locking a mutex"); CWCloseThread(); } //Fill gWTPs[*iPtr].qosValues with default settings gWTPs[*iPtr].qosValues = gDefaultQosValues; for (j = 0; j < radioCount; j++) { radioID = radiosInfo.radiosInfo[j].radioID; // Assemble WTP QoS Message Element for each radio if (!(CWAssembleWTPQoS(&(*msgElems[++k]), radioID, tagPackets))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(*msgElems[i]); } CW_FREE_OBJECT(*msgElems); CWThreadMutexUnlock(&(gWTPs[*iPtr].interfaceMutex)); return CW_FALSE; // error will be handled by the caller } } gWTPs[*iPtr].qosValues = NULL; CWThreadMutexUnlock(&(gWTPs[*iPtr].interfaceMutex)); CWLog("Binding Configuration Response Assembled"); return CW_TRUE; } /****************************************************************** * 2009 Updates: * * Added new switch case for ofdm message management * ******************************************************************/ CWBool CWBindingAssembleConfigurationUpdateRequest(CWProtocolMessage ** msgElems, int *msgElemCountPtr, int BindingMsgElement) { CWWTPRadiosInfo radiosInfo; int *iPtr; const int tagPackets = 0; int k = -1, radioCount, radioID, j; if (msgElems == NULL || msgElemCountPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } *msgElemCountPtr = 0; radiosInfo = gWTPs[*iPtr].WTPProtocolManager.radiosInfo; radioCount = radiosInfo.radioCount; *msgElemCountPtr = radioCount; CWLog("Assembling Binding Configuration Update Request..."); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(*msgElems, *msgElemCountPtr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* Selection of type of Conf Update Request */ switch (BindingMsgElement) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS:{ for (j = 0; j < radioCount; j++) { radioID = radiosInfo.radiosInfo[j].radioID; // Assemble Message Elements if (!(CWAssembleWTPQoS(&(*msgElems[++k]), radioID, tagPackets))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(*msgElems[i]); } CW_FREE_OBJECT(*msgElems); return CW_FALSE; // error will be handled by the caller } } break; } case BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL:{ for (j = 0; j < radioCount; j++) { radioID = radiosInfo.radiosInfo[j].radioID; /* Assemble Message Elements */ if (!(CWAssembleWTPOFDM(&(*msgElems[++k]), radioID))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(*msgElems[i]); } CW_FREE_OBJECT(*msgElems); return CW_FALSE; // error will be handled by the caller } } break; } default:{ return CW_FALSE; // error will be handled by the caller } } CWLog("Binding Configuration Update Request Assembled"); return CW_TRUE; } CWBool CWBindingSaveConfigurationUpdateResponse(CWProtocolResultCode resultCode, int WTPIndex) { int i; bindingValues *aux = (bindingValues *) gWTPs[WTPIndex].WTPProtocolManager.bindingValuesPtr; if (resultCode == CW_PROTOCOL_SUCCESS) { if (gWTPs[WTPIndex].qosValues != NULL) { for (i = 0; i < NUM_QOS_PROFILES; i++) { aux->qosValues[i].cwMin = gWTPs[WTPIndex].qosValues[i].cwMin; aux->qosValues[i].cwMax = gWTPs[WTPIndex].qosValues[i].cwMax; aux->qosValues[i].AIFS = gWTPs[WTPIndex].qosValues[i].AIFS; } } } return CW_TRUE; } ================================================ FILE: ACBinding.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_ACBinding_HEADER__ #define __CAPWAP_ACBinding_HEADER__ CWBool CWACInitBinding(int i); CWBool CWBindingAssembleConfigureResponse(CWProtocolMessage ** msgElems, int *msgElemCountPtr); /**************************************************** * 2009 Update: * * The field BindingMsgElement has been added for * * the multiple type of Message Element. * ****************************************************/ CWBool CWBindingAssembleConfigurationUpdateRequest(CWProtocolMessage ** msgElems, int *msgElemCountPtr, int BindingMsgElement); CWBool CWBindingSaveConfigurationUpdateResponse(CWProtocolResultCode resultCode, int WTPIndex); #endif ================================================ FILE: ACConfigFile.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif const char *CW_CONFIG_FILE = "/etc/capwap/config.ac"; CWBool CWConfigFileInitLib() { gConfigValuesCount = 11; CW_CREATE_ARRAY_ERR(gConfigValues, gConfigValuesCount, CWConfigValue, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); gConfigValues[0].type = CW_INTEGER; gConfigValues[0].code = ""; gConfigValues[0].value.int_value = 0; gConfigValues[1].type = CW_INTEGER; gConfigValues[1].code = ""; gConfigValues[1].value.int_value = 0; gConfigValues[2].type = CW_INTEGER; gConfigValues[2].code = ""; gConfigValues[2].value.int_value = 0; gConfigValues[3].type = CW_INTEGER; gConfigValues[3].code = ""; gConfigValues[3].value.int_value = 0; gConfigValues[4].type = CW_STRING; gConfigValues[4].code = ""; gConfigValues[4].value.str_value = NULL; gConfigValues[5].type = CW_STRING; gConfigValues[5].code = ""; gConfigValues[5].value.str_value = NULL; gConfigValues[6].type = CW_STRING_ARRAY; gConfigValues[6].code = ""; gConfigValues[6].endCode = ""; gConfigValues[6].value.str_array_value = NULL; gConfigValues[6].count = 0; gConfigValues[7].type = CW_INTEGER; gConfigValues[7].code = ""; gConfigValues[7].value.int_value = 0; gConfigValues[8].type = CW_STRING; gConfigValues[8].code = ""; gConfigValues[8].value.str_value = NULL; gConfigValues[9].type = CW_INTEGER; gConfigValues[9].code = ""; gConfigValues[9].value.int_value = 0; gConfigValues[10].type = CW_INTEGER; gConfigValues[10].code = ""; gConfigValues[10].value.int_value = DEFAULT_LOG_SIZE; return CW_TRUE; } CWBool CWConfigFileDestroyLib() { int i; /* save the preferences we read */ gACHWVersion = gConfigValues[0].value.int_value; gACSWVersion = gConfigValues[1].value.int_value; gLimit = gConfigValues[2].value.int_value; gMaxWTPs = gConfigValues[3].value.int_value; #ifndef CW_NO_DTLS if (gConfigValues[4].value.str_value != NULL && !strcmp(gConfigValues[4].value.str_value, "PRESHARED")) { gACDescriptorSecurity = CW_PRESHARED; } else { /* default */ gACDescriptorSecurity = CW_X509_CERTIFICATE; } #endif if (gConfigValues[5].value.str_value != NULL) { CW_CREATE_STRING_FROM_STRING_ERR(gACName, (gConfigValues[5].value.str_value), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); //CW_FREE_OBJECT(gACName); } /* avoid to allocate 0 bytes */ if (gConfigValues[6].count) { CW_CREATE_ARRAY_ERR(gMulticastGroups, gConfigValues[6].count, char *, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < gConfigValues[6].count; i++) { CW_CREATE_STRING_FROM_STRING_ERR(gMulticastGroups[i], (gConfigValues[6].value.str_array_value)[i], return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } } gMulticastGroupsCount = gConfigValues[6].count; CW_PRINT_STRING_ARRAY(gMulticastGroups, gMulticastGroupsCount); gCWForceMTU = gConfigValues[7].value.int_value; if (gConfigValues[8].value.str_value != NULL && !strcmp(gConfigValues[8].value.str_value, "IPv6")) { gNetworkPreferredFamily = CW_IPv6; } else { /* default */ gNetworkPreferredFamily = CW_IPv4; } for (i = 0; i < gConfigValuesCount; i++) { if (gConfigValues[i].type == CW_STRING) { CW_FREE_OBJECT(gConfigValues[i].value.str_value); } else if (gConfigValues[i].type == CW_STRING_ARRAY) { CW_FREE_OBJECTS_ARRAY((gConfigValues[i].value.str_array_value), gConfigValues[i].count); } } gEnabledLog = gConfigValues[9].value.int_value; gMaxLogFileSize = gConfigValues[10].value.int_value; CW_FREE_OBJECT(gConfigValues); return CW_TRUE; } ================================================ FILE: ACConfigureState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif int gCWChangeStatePendingTimer = CW_CHANGE_STATE_INTERVAL_DEFAULT; CWBool CWAssembleConfigureResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum); CWBool CWParseConfigureRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWProtocolConfigureRequestValues * valuesPtr, unsigned char *, unsigned char *, char *, int); CWBool CWSaveConfigureRequestMessage(CWProtocolConfigureRequestValues * configureRequest, CWWTPProtocolManager * WTPProtocolManager); CWBool ACEnterConfigure(int WTPIndex, CWProtocolMessage * msgPtr) { /*** tmp Radio Info ***/ unsigned char tmp_RadioInformationABGN; unsigned char tmp_SuppRates[8]; char tmp_MultiDomCapa[6]; int seqNum; CWProtocolConfigureRequestValues configureRequest; CWLog("\n"); CWLog("######### Configure State #########"); if (!(CWParseConfigureRequestMessage(msgPtr->msg, msgPtr->offset, &seqNum, &configureRequest, &tmp_RadioInformationABGN, tmp_SuppRates, tmp_MultiDomCapa, WTPIndex))) { /* note: we can kill our thread in case of out-of-memory * error to free some space. * we can see this just calling CWErrorGetLastErrorCode() */ return CW_FALSE; } CWLog("Configure Request Received"); if (!(CWSaveConfigureRequestMessage(&configureRequest, &(gWTPs[WTPIndex].WTPProtocolManager)))) { return CW_FALSE; } /* Store Radio Info in gWTPs */ gWTPs[WTPIndex].RadioInformationABGN = tmp_RadioInformationABGN; memcpy(gWTPs[WTPIndex].SuppRates, tmp_SuppRates, 8); memcpy(gWTPs[WTPIndex].MultiDomCapa, tmp_MultiDomCapa, 6); /* Store Radio Info in gWTPs */ if (!(CWAssembleConfigureResponse(&(gWTPs[WTPIndex].messages), &(gWTPs[WTPIndex].messagesCount), gWTPs[WTPIndex].pathMTU, seqNum))) { return CW_FALSE; } if (!CWACSendFragments(WTPIndex)) { return CW_FALSE; } CWLog("Configure Response Sent"); /* start Change State Pending timer */ if (!CWErr(CWTimerRequest(gCWChangeStatePendingTimer, &(gWTPs[WTPIndex].thread), &(gWTPs[WTPIndex].currentTimer), CW_CRITICAL_TIMER_EXPIRED_SIGNAL))) { CWCloseThread(); } gWTPs[WTPIndex].currentState = CW_ENTER_DATA_CHECK; return CW_TRUE; } CWBool CWParseConfigureRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWProtocolConfigureRequestValues * valuesPtr, unsigned char *tmp_RadioInformationABGN, unsigned char *tmp_SuppRates, char *tmp_MultiDomCapa, int WTPIndex) { CWControlHeaderValues controlVal; int i, j; int offsetTillMessages; CWProtocolMessage completeMsg; if (msg == NULL || seqNumPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parsing Configure Request..."); completeMsg.msg = msg; completeMsg.offset = 0; if (!(CWParseControlHeader(&completeMsg, &controlVal))) /* will be handled by the caller */ return CW_FALSE; /* Join Request in Configure state - WTP might have been restarted */ if (controlVal.messageTypeValue == CW_MSG_TYPE_VALUE_JOIN_REQUEST ){ gWTPs[WTPIndex].currentState = CW_ENTER_JOIN; return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is Join Request in Configure State - switching state"); } /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_CONFIGURE_REQUEST) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Configure Request (maybe it is Image Data Request)"); *seqNumPtr = controlVal.seqNum; /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; /* valuesPtr->WTPRadioInfo.radiosCount=0; */ valuesPtr->ACinWTP.count = 0; valuesPtr->radioAdminInfoCount = 0; /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); /*CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ switch (elemType) { case CW_MSG_ELEMENT_AC_NAME_CW_TYPE: if (!(CWParseACName(&completeMsg, elemLen, &(valuesPtr->ACName)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_AC_NAME_INDEX_CW_TYPE: /* just count how many radios we have, * so we can allocate the array */ valuesPtr->ACinWTP.count++; completeMsg.offset += elemLen; break; case CW_MSG_ELEMENT_RADIO_ADMIN_STATE_CW_TYPE: /* just count how many radios we have, * so we can allocate the array */ (valuesPtr->radioAdminInfoCount)++; completeMsg.offset += elemLen; break; case CW_MSG_ELEMENT_STATISTICS_TIMER_CW_TYPE: if (!(CWParseWTPStatisticsTimer(&completeMsg, elemLen, &(valuesPtr->StatisticsTimer)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_REBOOT_STATISTICS_CW_TYPE: CW_CREATE_OBJECT_ERR(valuesPtr->WTPRebootStatistics, WTPRebootStatisticsInfo, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWParseWTPRebootStatistics(&completeMsg, elemLen, valuesPtr->WTPRebootStatistics))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE: if (!(CWParseWTPRadioInformation(&completeMsg, elemLen, tmp_RadioInformationABGN))) return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_MULTI_DOMAIN_CAPABILITY_CW_TYPE: if (!(CWParseWTPMultiDomainCapability(&completeMsg, elemLen, tmp_MultiDomCapa))) return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_SUPPORTED_RATES_CW_TYPE: if (!(CWParseWTPSupportedRates(&completeMsg, elemLen, tmp_SuppRates))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); /* actually read each radio info */ CW_CREATE_ARRAY_ERR((valuesPtr->ACinWTP).ACNameIndex, (valuesPtr->ACinWTP).count, CWACNameWithIndexValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_ARRAY_ERR(valuesPtr->radioAdminInfo, valuesPtr->radioAdminInfoCount, CWRadioAdminInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); i = 0; j = 0; completeMsg.offset = offsetTillMessages; while (completeMsg.offset - offsetTillMessages < controlVal.msgElemsLen) { unsigned short int type = 0; unsigned short int len = 0; CWParseFormatMsgElem(&completeMsg, &type, &len); switch (type) { case CW_MSG_ELEMENT_AC_NAME_INDEX_CW_TYPE: if (!(CWParseACNameWithIndex(&completeMsg, len, &(valuesPtr->ACinWTP.ACNameIndex[i])))) /* will be handled by the caller */ return CW_FALSE; i++; break; case CW_MSG_ELEMENT_RADIO_ADMIN_STATE_CW_TYPE: if (!(CWParseWTPRadioAdminState(&completeMsg, len, &(valuesPtr->radioAdminInfo[j])))) /* will be handled by the caller */ return CW_FALSE; j++; break; default: completeMsg.offset += len; break; } } CWDebugLog("Configure Request Parsed"); return CW_TRUE; } CWBool CWAssembleConfigureResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum) { CWProtocolMessage *msgElems = NULL; const int MsgElemCount = 6; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Assembling Configure Response..."); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, MsgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* Assemble Message Elements */ if ((!(CWAssembleMsgElemACIPv4List(&(msgElems[++k])))) || (!(CWAssembleMsgElemACIPv6List(&(msgElems[++k])))) || (!(CWAssembleMsgElemCWTimer(&(msgElems[++k])))) || /*(!(CWAssembleMsgElemRadioOperationalState(-1, &(msgElems[++k])))) || */ (!(CWAssembleMsgElemDecryptErrorReportPeriod(&(msgElems[++k])))) || (!(CWAssembleMsgElemIdleTimeout(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPFallback(&(msgElems[++k])))) ) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } if (!CWBindingAssembleConfigureResponse(&msgElemsBinding, &msgElemBindingCount)) { int i; for (i = 0; i <= MsgElemCount; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; } /*CWDebugLog("~~~~~ msg count: %d ", msgElemBindingCount); */ if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CONFIGURE_RESPONSE, msgElems, MsgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWDebugLog("Configure Response Assembled"); return CW_TRUE; } CWBool CWSaveConfigureRequestMessage(CWProtocolConfigureRequestValues * configureRequest, CWWTPProtocolManager * WTPProtocolManager) { CWDebugLog("Saving Configure Request..."); CW_FREE_OBJECT(WTPProtocolManager->ACName); if ((configureRequest->ACName) != NULL) WTPProtocolManager->ACName = configureRequest->ACName; CW_FREE_OBJECT((WTPProtocolManager->ACNameIndex).ACNameIndex); WTPProtocolManager->ACNameIndex = configureRequest->ACinWTP; CW_FREE_OBJECT((WTPProtocolManager->radioAdminInfo).radios); (WTPProtocolManager->radioAdminInfo).radiosCount = configureRequest->radioAdminInfoCount; (WTPProtocolManager->radioAdminInfo).radios = configureRequest->radioAdminInfo; WTPProtocolManager->StatisticsTimer = configureRequest->StatisticsTimer; /* CW_FREE_OBJECT((WTPProtocolManager->WTPRadioInfo).radios); WTPProtocolManager->WTPRadioInfo = configureRequest->WTPRadioInfo; */ CW_FREE_OBJECT(WTPProtocolManager->WTPRebootStatistics); WTPProtocolManager->WTPRebootStatistics = configureRequest->WTPRebootStatistics; CWDebugLog("Configure Request Saved"); return CW_TRUE; } ================================================ FILE: ACDataCheckState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool ACEnterDataCheck(int WTPIndex, CWProtocolMessage * msgPtr) { /*CWProtocolMessage *messages = NULL; */ int seqNum; CWProtocolChangeStateEventRequestValues *changeStateEvent; CWLog("\n"); CWDebugLog("######### Status Event #########"); /* Destroy ChangeStatePending timer */ if (!CWErr(CWTimerCancel(&(gWTPs[WTPIndex].currentTimer)))) { CWCloseThread(); } CW_CREATE_OBJECT_ERR(changeStateEvent, CWProtocolChangeStateEventRequestValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWParseChangeStateEventRequestMessage(msgPtr->msg, msgPtr->offset, &seqNum, changeStateEvent))) { /* note: we can kill our thread in case of out-of-memory * error to free some space. * we can see this just calling CWErrorGetLastErrorCode() */ return CW_FALSE; } CWLog("Change State Event Received"); if (!(CWSaveChangeStateEventRequestMessage(changeStateEvent, &(gWTPs[WTPIndex].WTPProtocolManager)))) return CW_FALSE; if (!(CWAssembleChangeStateEventResponse(&(gWTPs[WTPIndex].messages), &(gWTPs[WTPIndex].messagesCount), gWTPs[WTPIndex].pathMTU, seqNum))) { return CW_FALSE; } if (!CWACSendFragments(WTPIndex)) { return CW_FALSE; } /* Start NeighbourDeadInterval timer */ if (!CWErr(CWTimerRequest(gCWNeighborDeadInterval, &(gWTPs[WTPIndex].thread), &(gWTPs[WTPIndex].currentTimer), CW_CRITICAL_TIMER_EXPIRED_SIGNAL))) { CWCloseThread(); } CWLog("Change State Event Response Sent"); gWTPs[WTPIndex].currentState = CW_ENTER_RUN; gWTPs[WTPIndex].subState = CW_WAITING_REQUEST; CWACsend_command_to_hostapd_SEND_WLAN(WTPIndex); return CW_TRUE; } CWBool CWParseChangeStateEventRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWProtocolChangeStateEventRequestValues * valuesPtr) { CWProtocolMessage completeMsg; CWControlHeaderValues controlVal; int i; int offsetTillMessages; if (msg == NULL || seqNumPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parsing Change State Event Request..."); completeMsg.msg = msg; completeMsg.offset = 0; if (!(CWParseControlHeader(&completeMsg, &controlVal))) /* will be handled by the caller */ return CW_FALSE; /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_REQUEST) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Change State Event Request"); *seqNumPtr = controlVal.seqNum; /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; valuesPtr->radioOperationalInfo.radiosCount = 0; /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); /*CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ switch (elemType) { case CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE: /* just count how many radios we have, * so we can allocate the array */ valuesPtr->radioOperationalInfo.radiosCount++; completeMsg.offset += elemLen; break; case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: if (!(CWParseResultCode(&completeMsg, elemLen, &(valuesPtr->resultCode)))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CW_CREATE_ARRAY_ERR(valuesPtr->radioOperationalInfo.radios, valuesPtr->radioOperationalInfo.radiosCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); completeMsg.offset = offsetTillMessages; i = 0; while (completeMsg.offset - offsetTillMessages < controlVal.msgElemsLen) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &type, &len); switch (type) { case CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE: if (! (CWParseWTPRadioOperationalState (&completeMsg, len, &(valuesPtr->radioOperationalInfo.radios[i])))) /* will be handled by the caller */ return CW_FALSE; i++; break; default: completeMsg.offset += len; break; } } CWDebugLog("Change State Event Request Parsed"); return CW_TRUE; } CWBool CWAssembleChangeStateEventResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Assembling Change State Event Response..."); /*CW_CREATE_ARRAY_ERR(msgElems, * msgElemCount, * CWProtocolMessage, * return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); */ if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWDebugLog("Change State Event Response Assembled"); return CW_TRUE; } ================================================ FILE: ACDiscoveryState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ __inline__ int CWACGetHWVersion(); __inline__ int CWACGetSWVersion(); __inline__ int CWACGetStations(); __inline__ int CWACGetLimit(); __inline__ int CWACGetActiveWTPs(); __inline__ int CWACGetMaxWTPs(); __inline__ int CWACGetSecurity(); __inline__ char *CWACGetName(); __inline__ int CWACGetInterfacesCount(); /*_________________________________________________________*/ /* *******************___FUNCTIONS___******************* */ /* send Discovery Response to the host at the specified address */ CWBool CWAssembleDiscoveryResponse(CWProtocolMessage ** messagesPtr, int seqNum) { CWProtocolMessage *msgElems = NULL; int msgElemCount = 4; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; int fragmentsNum; int k = -1; if (messagesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (CWACSupportIPv6()) { msgElemCount++; } CWLog("Send Discovery Response"); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* Assemble Message Elements */ if ((!(CWAssembleMsgElemACDescriptor(&(msgElems[++k])))) || (!(CWAssembleMsgElemACName(&(msgElems[++k])))) || (!(CWAssembleMsgElemCWControlIPv4Addresses(&(msgElems[++k])))) || (!(CWAssembleMsgElemACWTPRadioInformation(&(msgElems[++k])))) /*(CWACSupportIPv6() && (!(CWAssembleMsgElemCWControlIPv6Addresses(&(msgElems[++k]))))) */ ) { CWErrorHandleLast(); int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } return CWAssembleMessage(messagesPtr, &fragmentsNum, 0, seqNum, CW_MSG_TYPE_VALUE_DISCOVERY_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount); } CWBool CWParseDiscoveryRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWDiscoveryRequestValues * valuesPtr) { CWControlHeaderValues controlVal; CWProtocolTransportHeaderValues transportVal; unsigned char RadioInfoABGN; int offsetTillMessages; CWProtocolMessage completeMsg; if (msg == NULL || seqNumPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parse Discovery Request"); completeMsg.msg = msg; completeMsg.offset = 0; CWBool dataFlag = CW_FALSE; if (!(CWParseTransportHeader(&completeMsg, &transportVal, &dataFlag, NULL))) /* will be handled by the caller */ return CW_FALSE; if (!(CWParseControlHeader(&completeMsg, &controlVal))) /* will be handled by the caller */ return CW_FALSE; /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_DISCOVERY_REQUEST) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Discovery Request as Expected"); *seqNumPtr = controlVal.seqNum; /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; /* (*valuesPtr).radios.radiosCount = 0; */ /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); /* CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ switch (elemType) { case CW_MSG_ELEMENT_DISCOVERY_TYPE_CW_TYPE: if (!(CWParseDiscoveryType(&completeMsg, elemLen, valuesPtr))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_BOARD_DATA_CW_TYPE: if (!(CWParseWTPBoardData(&completeMsg, elemLen, &(valuesPtr->WTPBoardData)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_DESCRIPTOR_CW_TYPE: if (!(CWParseWTPDescriptor(&completeMsg, elemLen, &(valuesPtr->WTPDescriptor)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_FRAME_TUNNEL_MODE_CW_TYPE: if (!(CWParseWTPFrameTunnelMode(&completeMsg, elemLen, &(valuesPtr->frameTunnelMode)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_MAC_TYPE_CW_TYPE: if (!(CWParseWTPMACType(&completeMsg, elemLen, &(valuesPtr->MACType)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE: if (!(CWParseWTPRadioInformation(&completeMsg, elemLen, &RadioInfoABGN))) return CW_FALSE; break; /*case CW_MSG_ELEMENT_WTP_RADIO_INFO_CW_TYPE: // just count how many radios we have, so we can allocate the array (*valuesPtr).radios.radiosCount++; completeMsg.offset += elemLen; break; */ default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } /*CWDebugLog("bytes: %d/%d", (completeMsg.offset-offsetTillMessages), controlVal.msgElemsLen); */ } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); /* // actually read each radio info CW_CREATE_ARRAY_ERR((*valuesPtr).radios.radios, (*valuesPtr).radios.radiosCount, CWRadioInformationValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); i = 0; completeMsg.offset = offsetTillMessages; while(i < (*valuesPtr).radios.radiosCount && (completeMsg.offset-offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int type=0;// = CWProtocolRetrieve32(&completeMsg); unsigned short int len=0;// = CWProtocolRetrieve16(&completeMsg); CWParseFormatMsgElem(&completeMsg,&type,&len); switch(type) { case CW_MSG_ELEMENT_WTP_RADIO_INFO_CW_TYPE: if(!(CWParseWTPRadioInfo(&completeMsg, len, &(valuesPtr->radios), i))) return CW_FALSE; // will be handled by the caller i++; break; default: completeMsg.offset += len; break; } } */ return CW_TRUE; } void CWDestroyDiscoveryRequestValues(CWDiscoveryRequestValues * valPtr) { int i; if (valPtr == NULL) return; for (i = 0; i < (valPtr->WTPDescriptor.vendorInfos).vendorInfosCount; i++) { CW_FREE_OBJECT(((valPtr->WTPDescriptor.vendorInfos).vendorInfos)[i].valuePtr); } CW_FREE_OBJECT((valPtr->WTPDescriptor.vendorInfos).vendorInfos); /* * BUG ML11 * * 10/10/2009 - Donato Capitella */ for (i = 0; i < valPtr->WTPBoardData.vendorInfosCount; i++) { CW_FREE_OBJECT(valPtr->WTPBoardData.vendorInfos[i].valuePtr); } CW_FREE_OBJECT(valPtr->WTPBoardData.vendorInfos); /*CW_FREE_OBJECT((valPtr->radios).radios); */ } ================================================ FILE: ACInterface.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * Authors : Antonio Davoli (antonio.davoli@gmail.com) * Donato Capitella (d.capitella@gmail.com) ************************************************************************************************/ #include "CWAC.h" #include "ACAppsProtocol.h" #include "CWVendorPayloads.h" #include "WUM.h" #define LIST_CMD "LIST" #define SCAN_CMD "SCAN" #define QUIT_CMD "QUIT" #define LISTEN_PORT 1235 #define COMMAND_BUFFER_SIZE 5120 #define WTP_LIST_BUFFER_SIZE 1024 #define CMD_TYPE_SIZE sizeof(unsigned char) int is_valid_wtp_index(int index); int Readn(int sock, void *buf, size_t n); /******************************************************************** * Now the only parameter need by the application thread manager * * is the index of socket. * ********************************************************************/ typedef struct { int index; } CWInterfaceThreadArg; /************************************************************************ * CWOFDMSetValues provide to set the command values (type, parameters, * * output socket) on the correct wtp structure. * ************************************************************************/ int CWOFDMSetValues(int selection, int socketIndex, OFDMControlValues * ofdmValues) { CWThreadMutexLock(&(gWTPs[selection].interfaceMutex)); gWTPs[selection].ofdmValues = ofdmValues; gWTPs[selection].interfaceCommand = OFDM_CONTROL_CMD; gWTPs[selection].applicationIndex = socketIndex; CWSignalThreadCondition(&gWTPs[selection].interfaceWait); CWWaitThreadCondition(&gWTPs[selection].interfaceComplete, &gWTPs[selection].interfaceMutex); CWThreadMutexUnlock(&(gWTPs[selection].interfaceMutex)); return 0; } int CWVendorSetValues(int selection, int socketIndex, CWProtocolVendorSpecificValues * vendorValues) { CWThreadMutexLock(&(gWTPs[selection].interfaceMutex)); gWTPs[selection].vendorValues = vendorValues; gWTPs[selection].interfaceCommand = UCI_CONTROL_CMD; gWTPs[selection].applicationIndex = socketIndex; CWSignalThreadCondition(&gWTPs[selection].interfaceWait); CWWaitThreadCondition(&gWTPs[selection].interfaceComplete, &gWTPs[selection].interfaceMutex); CWThreadMutexUnlock(&(gWTPs[selection].interfaceMutex)); return 0; } int CWWumSetValues(int selection, int socketIndex, CWProtocolVendorSpecificValues * vendorValues) { CWThreadMutexLock(&(gWTPs[selection].interfaceMutex)); gWTPs[selection].vendorValues = vendorValues; gWTPs[selection].interfaceCommand = WTP_UPDATE_CMD; gWTPs[selection].applicationIndex = socketIndex; CWSignalThreadCondition(&gWTPs[selection].interfaceWait); CWWaitThreadCondition(&gWTPs[selection].interfaceComplete, &gWTPs[selection].interfaceMutex); CWThreadMutexUnlock(&(gWTPs[selection].interfaceMutex)); return 0; } /************************************************************************ * CWManageApplication is the function that provide the management of * * interaction with a single application. * * -------------------------------------------------------------------- * * The messages used are defined in ACAppsProtocol.h * ************************************************************************/ CW_THREAD_RETURN_TYPE CWManageApplication(void *arg) { int socketIndex = ((CWInterfaceThreadArg *) arg)->index; CWSocket sock = appsManager.appSocket[socketIndex]; int n, connected = htonl(CONNECTION_OK), gActiveWTPsTemp; char commandBuffer[COMMAND_BUFFER_SIZE]; char wtpListBuffer[WTP_LIST_BUFFER_SIZE]; int payload_size; int i, nameLength, numActiveWTPs = 0, wtpIndex; int iTosend, nLtoSend; unsigned char cmd_msg, msg_elem; OFDMControlValues *ofdmValues; CWProtocolVendorSpecificValues *vendorValues; CWVendorUciValues *uciValues; CWVendorWumValues *wumValues; /******************************************************************************** * Write on application socket that connection setting is happened correctly. * ********************************************************************************/ if (Writen(sock, &connected, sizeof(int)) < 0) { CWLog("Error on writing on application socket "); return NULL; } /* * Before starting, make sure to detach the thread because the parent * doesn't do a join and we risk resource leaks. * * ref -> BUG-TRL01 * 15/10/2009 - Donato Capitella */ pthread_detach(pthread_self()); // no need here to check return value /************************ * Thread Main Loop * ************************/ CW_REPEAT_FOREVER { memset(commandBuffer, 0, COMMAND_BUFFER_SIZE); /**************************************** * Waiting for client commands * ****************************************/ if ((n = Readn(sock, &cmd_msg, CMD_TYPE_SIZE)) > 0) { if (cmd_msg == QUIT_MSG) { /**************************************************** * Quit Message: Clean socket information * ****************************************************/ goto quit_manage; } if (cmd_msg == LIST_MSG) { /**************************************** * Manage LIST command * * ------------------------------------ * * 1. Get Number of active WTPs, * * 2. Create Message Answer, * * 3. Send To client socket. * ****************************************/ if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) { CWLog("Error locking the mutex"); return NULL; } gActiveWTPsTemp = gActiveWTPs; CWThreadMutexUnlock(&gActiveWTPsMutex); if (gActiveWTPsTemp > 0) for (i = 0; i < gMaxWTPs; i++) if (gWTPs[i].isNotFree) if (!gWTPs[i].WTPProtocolManager.name) gActiveWTPsTemp -= 1; numActiveWTPs = htonl(gActiveWTPsTemp); memset(wtpListBuffer, 0, sizeof(wtpListBuffer)); payload_size = 0; memcpy(wtpListBuffer, &numActiveWTPs, sizeof(int)); payload_size = sizeof(int); if (gActiveWTPsTemp > 0) { for (i = 0; i < gMaxWTPs; i++) { if (gWTPs[i].isNotFree) { if (!gWTPs[i].WTPProtocolManager.name) continue; nameLength = strlen(gWTPs[i].WTPProtocolManager.name); iTosend = htonl(i); nLtoSend = htonl(nameLength); memcpy(wtpListBuffer + payload_size, &iTosend, sizeof(int)); payload_size += sizeof(int); memcpy(wtpListBuffer + payload_size, &nLtoSend, sizeof(int)); payload_size += sizeof(int); memcpy(wtpListBuffer + payload_size, gWTPs[i].WTPProtocolManager.name, strlen(gWTPs[i].WTPProtocolManager.name)); payload_size += strlen(gWTPs[i].WTPProtocolManager.name); } } } if (Writen(sock, wtpListBuffer, payload_size) < 0) CWLog("Error on write message on application socket"); } if (cmd_msg == CONF_UPDATE_MSG) { /**************************************** * Manage CONF command * * ------------------------------------ * * 1. Select the type of CONF_UPDATE, * * 2. Get Index of WTP, * * 3. Manage request. * ****************************************/ if ((n = Readn(sock, commandBuffer, sizeof(msg_elem) + sizeof(wtpIndex))) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } memcpy(&msg_elem, commandBuffer, sizeof(unsigned char)); /* CONF_UPDATE type */ memcpy(&wtpIndex, commandBuffer + sizeof(unsigned char), sizeof(int)); /* WTP Index */ wtpIndex = ntohl(wtpIndex); /* Check if WTP Index is valid */ if (!is_valid_wtp_index(wtpIndex)) { CWLog("WTP Index non valid!"); goto quit_manage; } switch (msg_elem) { case MSG_ELEMENT_TYPE_OFDM:{ /* Antonio Case */ CW_CREATE_OBJECT_ERR(ofdmValues, OFDMControlValues, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); if ((n = Readn(sock, ofdmValues, sizeof(OFDMControlValues))) < 0) { CWLog("Error while reading from socket"); goto quit_manage; } /**************************************************** * Two behaviors availables: * * - One message element For All WTPs Active * * - One message for a specific WTP * ****************************************************/ if (wtpIndex == ALL_ACTIVE_WTPS) { /* All wpts case */ if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) { CWLog("Error locking the mutex"); return NULL; } numActiveWTPs = gActiveWTPs; CWThreadMutexUnlock(&gActiveWTPsMutex); if (numActiveWTPs > 0) { for (i = 0; i < gMaxWTPs; i++) { if (gWTPs[i].isNotFree) { CWOFDMSetValues(i, socketIndex, ofdmValues); } } } } else /* One specific Wtp Case */ CWOFDMSetValues(wtpIndex, socketIndex, ofdmValues); CW_FREE_OBJECT(ofdmValues); break; } case MSG_ELEMENT_TYPE_VENDOR_UCI:{ /* Matteo Case */ /*Do stuff to parse uci payload */ int commandLength = 0; CW_CREATE_OBJECT_ERR(vendorValues, CWProtocolVendorSpecificValues, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); CW_CREATE_OBJECT_ERR(uciValues, CWVendorUciValues, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); vendorValues->vendorPayloadType = CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI; uciValues->response = NULL; if ((n = Readn(sock, commandBuffer, sizeof(unsigned char) + sizeof(int))) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } memcpy(&(uciValues->command), commandBuffer, sizeof(unsigned char)); memcpy(&commandLength, commandBuffer + sizeof(unsigned char), sizeof(int)); commandLength = ntohl(commandLength); if (commandLength > 0) { if ((n = Readn(sock, commandBuffer + sizeof(char) + sizeof(int), commandLength)) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } CW_CREATE_STRING_ERR(uciValues->commandArgs, commandLength, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); memcpy(uciValues->commandArgs, commandBuffer + sizeof(unsigned char) + sizeof(int), sizeof(char) * commandLength); uciValues->commandArgs[commandLength] = '\0'; } else uciValues->commandArgs = NULL; vendorValues->payload = uciValues; /**************************************************** * Two behaviors availables: * * - One message element For All WTPs Active * * - One message for a specific WTP * ****************************************************/ if (wtpIndex == ALL_ACTIVE_WTPS) { /* All wpts case */ if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) { CWLog("Error locking the mutex"); return NULL; } numActiveWTPs = gActiveWTPs; CWThreadMutexUnlock(&gActiveWTPsMutex); if (numActiveWTPs > 0) { for (i = 0; i < gMaxWTPs; i++) { if (gWTPs[i].isNotFree) { printf ("Sending UCI Configuration Message to: %d - %s \n", i, gWTPs[i].WTPProtocolManager.name); CWVendorSetValues(i, socketIndex, vendorValues); } } } } else /* One specific Wtp Case */ CWVendorSetValues(wtpIndex, socketIndex, vendorValues); break; } case MSG_ELEMENT_TYPE_VENDOR_WUM:{ /* Donato's Case */ CW_CREATE_OBJECT_ERR(vendorValues, CWProtocolVendorSpecificValues, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); CW_CREATE_OBJECT_ERR(wumValues, CWVendorWumValues, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); vendorValues->vendorPayloadType = CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM; /* * Read WTP Update Message fields into the wumValues structure */ if ((n = Readn(sock, &(wumValues->type), sizeof(unsigned char))) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } if (wumValues->type == WTP_UPDATE_REQUEST) { if ((n = Readn(sock, commandBuffer, 3 * sizeof(unsigned char) + sizeof(int))) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } memcpy(&(wumValues->_major_v_), commandBuffer, sizeof(unsigned char)); memcpy(&(wumValues->_minor_v_), commandBuffer + sizeof(unsigned char), sizeof(unsigned char)); memcpy(&(wumValues->_revision_v_), commandBuffer + 2 * sizeof(unsigned char), sizeof(unsigned char)); memcpy(&(wumValues->_pack_size_), commandBuffer + 3 * sizeof(unsigned char), sizeof(unsigned int)); wumValues->_pack_size_ = ntohl(wumValues->_pack_size_); } else if (wumValues->type == WTP_CUP_FRAGMENT) { int seqNum; int fragSize; /* Read sequence number and fragment size */ if ((n = Readn(sock, commandBuffer, 2 * sizeof(int))) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } memcpy(&seqNum, commandBuffer, sizeof(int)); memcpy(&fragSize, commandBuffer + sizeof(int), sizeof(int)); seqNum = ntohl(seqNum); fragSize = ntohl(fragSize); if (seqNum < 0) { CWLog("Update with sequence number < 0 not valid."); goto quit_manage; } if (fragSize <= 0) { CWLog("Update with fragment size <= 0 not valid."); goto quit_manage; } /* Read update package into buffer */ unsigned char *buf = malloc(fragSize); if (buf == NULL) { CWLog("Can't allocate memory"); goto quit_manage; } if ((n = Readn(sock, buf, fragSize)) < 0) { CWLog("Error while reading from socket."); goto quit_manage; } wumValues->_cup_ = buf; wumValues->_seq_num_ = seqNum; wumValues->_cup_fragment_size_ = fragSize; } vendorValues->payload = wumValues; /* Send Request */ if (wtpIndex == ALL_ACTIVE_WTPS) { /* All wpts case */ if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) { CWLog("Error locking the mutex"); return NULL; } numActiveWTPs = gActiveWTPs; CWThreadMutexUnlock(&gActiveWTPsMutex); if (numActiveWTPs > 0) { for (i = 0; i < gMaxWTPs; i++) { if (gWTPs[i].isNotFree) { printf ("Sending WUM Configuration Message to: %d - %s \n", i, gWTPs[i].WTPProtocolManager.name); CWWumSetValues(i, socketIndex, vendorValues); } } } } else /* One specific Wtp Case */ CWWumSetValues(wtpIndex, socketIndex, vendorValues); break; } default: /* Error Case: Not correct msg_elem type */ break; } } } else { CWLog("Error on receive application command (read socket)"); goto quit_manage; } } quit_manage: if (!CWErr(CWThreadMutexLock(&appsManager.numSocketFreeMutex))) { CWLog("Error locking numSocketFree Mutex"); return NULL; } appsManager.isFree[socketIndex] = CW_TRUE; appsManager.numSocketFree++; CWDestroyThreadMutex(&appsManager.socketMutex[socketIndex]); CWThreadMutexUnlock(&appsManager.numSocketFreeMutex); close(sock); return NULL; } /**************************************************************************** * CWInterface is the function that provide the interaction between AC and * * extern applications. Listen on main Inet familty socket and create a * * CWManageApplication thread for every client connected. * ****************************************************************************/ CW_THREAD_RETURN_TYPE CWInterface(void *arg) { CWSocket listen_sock, conn_sock; struct sockaddr_in servaddr; CWInterfaceThreadArg *argPtr; CWThread thread_id; int i, clientFull = htonl(FULL_CLIENT_CONNECTED), optValue = 1; /**************************************************** * Setup of Application Socket Management Structure * ****************************************************/ for (i = 0; i < MAX_APPS_CONNECTED_TO_AC; i++) appsManager.isFree[i] = CW_TRUE; appsManager.numSocketFree = MAX_APPS_CONNECTED_TO_AC; if (!CWErr(CWCreateThreadMutex(&appsManager.numSocketFreeMutex))) { CWLog("Error on mutex creation on appManager structure"); return NULL; } /**************************************************** * Setup (Creation and filling) of main socket * ****************************************************/ if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { CWLog("Error on socket creation on Interface"); return NULL; } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Not Extern: INADDR_ANY */ servaddr.sin_port = htons(LISTEN_PORT); if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &optValue, sizeof(int)) == -1) { CWLog("Error on socket creation on Interface"); return NULL; } /************************************ * Binding socket and Listen call * ************************************/ if (bind(listen_sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0) { CWLog("Error on Binding"); return NULL; } if (listen(listen_sock, MAX_APPS_CONNECTED_TO_AC) < 0) { CWLog("Error on LIsTsocket creation"); return NULL; } /******************************** * Main Loop * ********************************/ CW_REPEAT_FOREVER { if ((conn_sock = accept(listen_sock, (struct sockaddr *)NULL, NULL)) > 0) { /************************************************************************ * Check (with lock) the number of socket free at the moment of accept, * * if this value is greater than 0 will be spawn a new Manage thread. * ************************************************************************/ if (!CWErr(CWThreadMutexLock(&appsManager.numSocketFreeMutex))) { CWLog("Error locking numSocketFree Mutex"); return NULL; } if (appsManager.numSocketFree > 0) { CW_CREATE_OBJECT_ERR(argPtr, CWInterfaceThreadArg, { CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); return 0; } ); /************************************ * Search socket for application * ************************************/ for (i = 0; i < MAX_APPS_CONNECTED_TO_AC; i++) { if (appsManager.isFree[i] == CW_TRUE) { argPtr->index = i; appsManager.isFree[i] = CW_FALSE; appsManager.appSocket[i] = conn_sock; break; } } appsManager.numSocketFree--; CWThreadMutexUnlock(&appsManager.numSocketFreeMutex); if (!CWErr(CWCreateThreadMutex(&appsManager.socketMutex[argPtr->index]))) { CWLog("Error on mutex creation on appManager structure"); return NULL; } if (!CWErr(CWCreateThread(&thread_id, CWManageApplication, argPtr))) { CWLog("Error on thread CWManageApplication creation"); appsManager.isFree[argPtr->index] = CW_TRUE; close(conn_sock); CW_FREE_OBJECT(argPtr); /* * If we can't create the thread, we have to increment numSocketFree. * * ref -> BUG-LE01 * 15/10/2009 - Donato Capitella */ if (!CWErr(CWThreadMutexLock(&appsManager.numSocketFreeMutex))) { CWLog("Error locking numSocketFree Mutex"); return NULL; } appsManager.numSocketFree++; CWThreadMutexUnlock(&appsManager.numSocketFreeMutex); } } else { CWThreadMutexUnlock(&appsManager.numSocketFreeMutex); /**************************************************************** * There isn't space for another client, send error answer. * ***************************************************************/ if (Writen(conn_sock, &clientFull, sizeof(int)) < 0) { printf("Error on sending Error Message\n"); close(conn_sock); } } } else CWLog("Error on accept (applications) system call"); } CWDestroyThreadMutex(&appsManager.numSocketFreeMutex); close(listen_sock); } int is_valid_wtp_index(int wtpIndex) { if (wtpIndex < gMaxWTPs && gWTPs[wtpIndex].isNotFree) return CW_TRUE; return CW_FALSE; } /* * Steven's readn(). */ int readn(int fd, void *vptr, size_t n) { size_t nleft; ssize_t nread; char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nread = recv(fd, ptr, nleft, 0)) < 0) { if (errno == EINTR) nread = 0; /* and call read() again */ else return (-1); } else if (nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } return (n - nleft); /* return >= 0 */ } int Readn(int fd, void *ptr, size_t nbytes) { int n; if ((n = readn(fd, ptr, nbytes)) < 0) { CWLog("Error while reading data from socket."); return -1; } return n; } ================================================ FILE: ACInterface.h ================================================ /******************************************************************************************* * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria * * Informatica Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Daniele De Sanctis (danieledesanctis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * * Donato Capitella (d.capitella@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_ACInterface_HEADER__ #define __CAPWAP_ACInterface_HEADER__ //No Interface Command #define NO_CMD 0 //Manual setting for QoS values #define QOS_CMD 1 #define CLEAR_CONFIG_MSG_CMD 2 /* 2009 Update: Manual setting for OFDM values*/ #define OFDM_CONTROL_CMD 3 /*Update 2009: Manage UCI configuration command*/ #define UCI_CONTROL_CMD 4 /* Manage WTP Update Command */ #define WTP_UPDATE_CMD 5 #endif ================================================ FILE: ACJoinState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWAssembleJoinResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CWBool CWParseJoinRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWProtocolJoinRequestValues * valuesPtr); CWBool CWSaveJoinRequestMessage(CWProtocolJoinRequestValues * joinRequest, CWWTPProtocolManager * WTPProtocolManager); CWBool ACEnterJoin(int WTPIndex, CWProtocolMessage * msgPtr) { int seqNum; CWProtocolJoinRequestValues joinRequest; CWList msgElemList = NULL; CWLog("\n"); CWLog("######### Join State #########"); if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!(CWParseJoinRequestMessage(msgPtr->msg, msgPtr->offset, &seqNum, &joinRequest))) { /* note: we can kill our thread in case of out-of-memory * error to free some space. * we can see this just calling CWErrorGetLastErrorCode() */ return CW_FALSE; } // cancel waitJoin timer if (!CWTimerCancel(&(gWTPs[WTPIndex].currentTimer))) { return CW_FALSE; } CWBool ACIpv4List = CW_FALSE; CWBool ACIpv6List = CW_FALSE; CWBool resultCode = CW_TRUE; int resultCodeValue = CW_PROTOCOL_SUCCESS; /* CWBool sessionID = CW_FALSE; */ if (!(CWSaveJoinRequestMessage(&joinRequest, &(gWTPs[WTPIndex].WTPProtocolManager)))) { resultCodeValue = CW_PROTOCOL_FAILURE_RES_DEPLETION; } CWMsgElemData *auxData; if (ACIpv4List) { CW_CREATE_OBJECT_ERR(auxData, CWMsgElemData, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); auxData->type = CW_MSG_ELEMENT_AC_IPV4_LIST_CW_TYPE; auxData->value = 0; CWAddElementToList(&msgElemList, auxData); } if (ACIpv6List) { CW_CREATE_OBJECT_ERR(auxData, CWMsgElemData, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); auxData->type = CW_MSG_ELEMENT_AC_IPV6_LIST_CW_TYPE; auxData->value = 0; CWAddElementToList(&msgElemList, auxData); } if (resultCode) { CW_CREATE_OBJECT_ERR(auxData, CWMsgElemData, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); auxData->type = CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE; auxData->value = resultCodeValue; CWAddElementToList(&msgElemList, auxData); } /* if(sessionID){ CW_CREATE_OBJECT_ERR(auxData, CWMsgElemData, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); auxData->type = CW_MSG_ELEMENT_SESSION_ID_CW_TYPE; auxData->value = CWRandomIntInRange(0, INT_MAX); CWAddElementToList(&msgElemList,auxData); } */ /* random session ID */ if (!(CWAssembleJoinResponse(&(gWTPs[WTPIndex].messages), &(gWTPs[WTPIndex].messagesCount), gWTPs[WTPIndex].pathMTU, seqNum, msgElemList))) { CWDeleteList(&msgElemList, CWProtocolDestroyMsgElemData); return CW_FALSE; } CWDeleteList(&msgElemList, CWProtocolDestroyMsgElemData); if (!CWACSendFragments(WTPIndex)) { return CW_FALSE; } gWTPs[WTPIndex].currentState = CW_ENTER_CONFIGURE; return CW_TRUE; } /* * Assemble Join Response. */ CWBool CWAssembleJoinResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; int msgElemCount = 0; /* Result code is not included because it's already * in msgElemList. Control IPv6 to be added. */ const int mandatoryMsgElemCount = 4; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; int i; CWListElement *current; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL || msgElemList == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); msgElemCount = CWCountElementInList(msgElemList); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount + mandatoryMsgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWDebugLog("Assembling Join Response..."); if ((!(CWAssembleMsgElemACDescriptor(&(msgElems[++k])))) || (!(CWAssembleMsgElemACName(&(msgElems[++k])))) || (!(CWAssembleMsgElemCWControlIPv4Addresses(&(msgElems[++k])))) || (!(CWAssembleMsgElemACWTPRadioInformation(&(msgElems[++k])))) ) { CWErrorHandleLast(); int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } current = msgElemList; for (i = 0; i < msgElemCount; i++) { switch (((CWMsgElemData *) (current->data))->type) { case CW_MSG_ELEMENT_AC_IPV4_LIST_CW_TYPE: if (!(CWAssembleMsgElemACIPv4List(&(msgElems[++k])))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_AC_IPV6_LIST_CW_TYPE: if (!(CWAssembleMsgElemACIPv6List(&(msgElems[++k])))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: if (!(CWAssembleMsgElemResultCode(&(msgElems[++k]), ((CWMsgElemData *) current->data)->value))) goto cw_assemble_error; break; /* case CW_MSG_ELEMENT_SESSION_ID_CW_TYPE: if (!(CWAssembleMsgElemSessionID(&(msgElems[++k]), ((CWMsgElemData *) current->data)->value))) goto cw_assemble_error; break; */ default:{ int j; for (j = 0; j <= k; j++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[j]); } CW_FREE_OBJECT(msgElems); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element for Join Response Message"); break; } } current = current->next; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_JOIN_RESPONSE, msgElems, msgElemCount + mandatoryMsgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWDebugLog("Join Response Assembled"); return CW_TRUE; cw_assemble_error:{ int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } return CW_TRUE; } /* * Parses Join Request. */ CWBool CWParseJoinRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWProtocolJoinRequestValues * valuesPtr) { CWControlHeaderValues controlVal; int offsetTillMessages; CWProtocolMessage completeMsg; unsigned char RadioInfoABGN; if (msg == NULL || seqNumPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parse Join Request"); completeMsg.msg = msg; completeMsg.offset = 0; if (!(CWParseControlHeader(&completeMsg, &controlVal))) /* will be handled by the caller */ return CW_FALSE; /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_JOIN_REQUEST) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Join Request as Expected"); *seqNumPtr = controlVal.seqNum; /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); /* CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ switch (elemType) { case CW_MSG_ELEMENT_LOCATION_DATA_CW_TYPE: if (!(CWParseLocationData(&completeMsg, elemLen, &(valuesPtr->location)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_BOARD_DATA_CW_TYPE: if (!(CWParseWTPBoardData(&completeMsg, elemLen, &(valuesPtr->WTPBoardData)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_SESSION_ID_CW_TYPE: valuesPtr->sessionID = CWParseSessionID(&completeMsg, elemLen); break; case CW_MSG_ELEMENT_WTP_DESCRIPTOR_CW_TYPE: if (!(CWParseWTPDescriptor(&completeMsg, elemLen, &(valuesPtr->WTPDescriptor)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_IPV4_ADDRESS_CW_TYPE: if (!(CWParseWTPIPv4Address(&completeMsg, elemLen, valuesPtr))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_NAME_CW_TYPE: if (!(CWParseWTPName(&completeMsg, elemLen, &(valuesPtr->name)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_FRAME_TUNNEL_MODE_CW_TYPE: if (!(CWParseWTPFrameTunnelMode(&completeMsg, elemLen, &(valuesPtr->frameTunnelMode)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_MAC_TYPE_CW_TYPE: if (!(CWParseWTPMACType(&completeMsg, elemLen, &(valuesPtr->MACType)))) /* will be handled by the caller */ return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE: if (!(CWParseWTPRadioInformation(&completeMsg, elemLen, &RadioInfoABGN))) return CW_FALSE; break; default: completeMsg.offset += elemLen; CWLog("Unrecognized Message Element(%d) in Discovery response", elemType); break; } /*CWDebugLog("bytes: %d/%d", (completeMsg.offset-offsetTillMessages), controlVal.msgElemsLen); */ } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); return CW_TRUE; } CWBool CWSaveJoinRequestMessage(CWProtocolJoinRequestValues * joinRequest, CWWTPProtocolManager * WTPProtocolManager) { CWDebugLog("Saving Join Request..."); if (joinRequest == NULL || WTPProtocolManager == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((joinRequest->location) != NULL) { CW_FREE_OBJECT(WTPProtocolManager->locationData); WTPProtocolManager->locationData = joinRequest->location; } else return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((joinRequest->name) != NULL) { CW_FREE_OBJECT(WTPProtocolManager->name); WTPProtocolManager->name = joinRequest->name; } else return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_FREE_OBJECT((WTPProtocolManager->WTPBoardData).vendorInfos); WTPProtocolManager->WTPBoardData = joinRequest->WTPBoardData; WTPProtocolManager->sessionID = joinRequest->sessionID; WTPProtocolManager->ipv4Address = joinRequest->addr; WTPProtocolManager->descriptor = joinRequest->WTPDescriptor; WTPProtocolManager->radiosInfo.radioCount = (joinRequest->WTPDescriptor).radiosInUse; CW_FREE_OBJECT(WTPProtocolManager->radiosInfo.radiosInfo); CW_CREATE_ARRAY_ERR(WTPProtocolManager->radiosInfo.radiosInfo, WTPProtocolManager->radiosInfo.radioCount, CWWTPRadioInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); int i; for (i = 0; i < WTPProtocolManager->radiosInfo.radioCount; i++) { WTPProtocolManager->radiosInfo.radiosInfo[i].radioID = i; /*WTPProtocolManager->radiosInfo.radiosInfo[i].stationCount = 0; */ /* default value for CAPWAP */ WTPProtocolManager->radiosInfo.radiosInfo[i].adminState = ENABLED; WTPProtocolManager->radiosInfo.radiosInfo[i].adminCause = AD_NORMAL; WTPProtocolManager->radiosInfo.radiosInfo[i].operationalState = DISABLED; WTPProtocolManager->radiosInfo.radiosInfo[i].operationalCause = OP_NORMAL; WTPProtocolManager->radiosInfo.radiosInfo[i].TxQueueLevel = 0; WTPProtocolManager->radiosInfo.radiosInfo[i].wirelessLinkFramesPerSec = 0; } CWDebugLog("Join Request Saved"); return CW_TRUE; } ================================================ FILE: ACMainLoop.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Daniele De Sanctis (danieledesanctis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include "CWAC.h" #include "CWStevens.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /* index of the current thread in the global array */ CWThreadSpecific gIndexSpecific; int gCWWaitJoin = CW_WAIT_JOIN_DEFAULT; CW_THREAD_RETURN_TYPE CWManageWTP(void *arg); CW_THREAD_RETURN_TYPE CWManageTimers(void *arg); void CWCriticalTimerExpiredHandler(int arg); void CWSoftTimerExpiredHandler(int arg); void CWACManageIncomingPacket(CWSocket sock, unsigned char *buf, int len, int incomingInterfaceIndex, CWNetworkLev4Address * addrPtr, CWBool dataFlag); void _CWCloseThread(int i); void CWResetWTPProtocolManager(CWWTPProtocolManager * WTPProtocolManager); CWWTPManager *CWWTPByName(const char *addr); int CWWTPByAddress(CWNetworkLev4Address * addressPtr, CWSocket sock); void CWACEnterMainLoop() { struct sigaction act; CWLog("AC enters in the MAIN_LOOP"); /* set signals * all the thread we spawn will inherit these settings */ /* * BUG UMR03 * * 20/10/2009 - Donato Capitella */ sigemptyset(&act.sa_mask); act.sa_flags = 0; /* called when a timer requested by the thread has expired */ act.sa_handler = CWCriticalTimerExpiredHandler; sigaction(CW_CRITICAL_TIMER_EXPIRED_SIGNAL, &act, NULL); act.sa_flags = 0; /* called when a timer requested by the thread has expired */ act.sa_handler = CWSoftTimerExpiredHandler; sigaction(CW_SOFT_TIMER_EXPIRED_SIGNAL, &act, NULL); /* signals will be unblocked by the threads that needs timers */ CWThreadSetSignals(SIG_BLOCK, 2, CW_CRITICAL_TIMER_EXPIRED_SIGNAL, CW_SOFT_TIMER_EXPIRED_SIGNAL); if (!(CWThreadCreateSpecific(&gIndexSpecific, NULL))) { CWLog("Critical Error With Thread Data"); exit(1); } CWThread thread_interface; if (!CWErr(CWCreateThread(&thread_interface, CWInterface, NULL))) { CWLog("Error starting Interface Thread"); exit(1); } CW_REPEAT_FOREVER { /* CWACManageIncomingPacket will be called * when a new packet is ready to be read */ if (!CWErr(CWNetworkUnsafeMultiHomed(&gACSocket, CWACManageIncomingPacket, CW_FALSE))) exit(1); } } /* argument passed to the thread func */ typedef struct { int index; CWSocket sock; int interfaceIndex; } CWACThreadArg; /* * This callback function is called when there is something to read in a * CWMultiHomedSocket (see ACMultiHomed.c). * * Params: sock, is the socket that can receive the packet and it can be * used to reply. * buf, (array of len chars) contains the packet which is ready * on the socket's queue (obtained with MSG_PEEK). * incomingInterfaceIndex, is the index (different from the system * index, see ACMultiHomed.c) of the interface * the packet was sent to, in the array returned * by CWNetworkGetInterfaceAddresses. If the * packet was sent to a broadcast/multicast address, * incomingInterfaceIndex is -1. */ void CWACManageIncomingPacket(CWSocket sock, unsigned char *buf, int readBytes, int incomingInterfaceIndex, CWNetworkLev4Address * addrPtr, CWBool dataFlag) { int WTPIndex = 0; char *pData; /* check if sender address is known */ WTPIndex = CWWTPByAddress(addrPtr, sock); if (WTPIndex >= 0) { /* known WTP */ /* Clone data packet */ CW_CREATE_OBJECT_SIZE_ERR(pData, readBytes, { CWLog("Out Of Memory"); return; } ); memcpy(pData, buf, readBytes); CWLockSafeList(gWTPs[WTPIndex].packetReceiveList); CWAddElementToSafeListTailwitDataFlag(gWTPs[WTPIndex].packetReceiveList, pData, readBytes, dataFlag); CWUnlockSafeList(gWTPs[WTPIndex].packetReceiveList); if (dataFlag) CW_COPY_NET_ADDR_PTR(&(gWTPs[WTPIndex].dataAddress), addrPtr); } else { /* unknown WTP */ int seqNum; CWDiscoveryRequestValues values; if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) exit(1); CWThreadMutexUnlock(&gActiveWTPsMutex); if (gActiveWTPs >= gMaxWTPs) { CWLog("Too many WTPs"); return; } CWLog("\n"); if (CWErr(CWParseDiscoveryRequestMessage(buf, readBytes, &seqNum, &values))) { CWProtocolMessage *msgPtr; CWLog("\n"); CWLog("######### Discovery State #########"); CWUseSockNtop(addrPtr, CWLog("CAPWAP Discovery Request from %s", str); ); /* don't add this WTP to our list to minimize DoS * attacks (will be added after join) */ /* destroy useless values */ CWDestroyDiscoveryRequestValues(&values); /* send response to WTP * note: we can consider reassembling only changed part * AND/OR do this in a new thread. */ if (!CWErr(CWAssembleDiscoveryResponse(&msgPtr, seqNum))) { /* * note: maybe an out-of-memory memory error * can be resolved without exit()-ing by * killing some thread or doing other funky * things. */ CWLog("Critical Error Assembling Discovery Response"); exit(1); } if (!CWErr(CWNetworkSendUnsafeUnconnected(sock, addrPtr, (*msgPtr).msg, (*msgPtr).offset))) { CWLog("Critical Error Sending Discovery Response"); exit(1); } CW_FREE_PROTOCOL_MESSAGE(*msgPtr); CW_FREE_OBJECT(msgPtr); } else { /* this isn't a Discovery Request */ int i; CWACThreadArg *argPtr; CWUseSockNtop(addrPtr, CWDebugLog("Possible Client Hello from %s", str); ); if (!CWErr(CWThreadMutexLock(&gWTPsMutex))) exit(1); /* look for the first free slot */ for (i = 0; i < gMaxWTPs && gWTPs[i].isNotFree; i++) ; CW_COPY_NET_ADDR_PTR(&(gWTPs[i].address), addrPtr); if (dataFlag) CW_COPY_NET_ADDR_PTR(&(gWTPs[i].dataAddress), addrPtr); gWTPs[i].isNotFree = CW_TRUE; gWTPs[i].isRequestClose = CW_FALSE; CWThreadMutexUnlock(&gWTPsMutex); /* Capwap receive packets list */ if (!CWErr(CWCreateSafeList(&gWTPs[i].packetReceiveList))) { if (!CWErr(CWThreadMutexLock(&gWTPsMutex))) exit(1); gWTPs[i].isNotFree = CW_FALSE; CWThreadMutexUnlock(&gWTPsMutex); return; } CWSetMutexSafeList(gWTPs[i].packetReceiveList, &gWTPs[i].interfaceMutex); CWSetConditionSafeList(gWTPs[i].packetReceiveList, &gWTPs[i].interfaceWait); CW_CREATE_OBJECT_ERR(argPtr, CWACThreadArg, { CWLog("Out Of Memory"); return; } ); argPtr->index = i; argPtr->sock = sock; argPtr->interfaceIndex = incomingInterfaceIndex; /* * If the packet was addressed to a broadcast address, * just choose an interface we like (note: we can consider * a bit load balancing instead of hard-coding 0-indexed * interface). Btw, Join Request should not really be * accepted if addressed to a broadcast address, so we * could simply discard the packet and go on. * If you leave this code, the WTP Count will increase * for the interface we hard-code here, even if it is not * necessary the interface we use to send packets to that * WTP. If we really want to accept Join Request from * broadcast address, we can consider asking to the kernel * which interface will be used to send the packet to a * specific address (if it remains the same) and than * increment WTPCount for that interface instead of 0-indexed one. */ if (argPtr->interfaceIndex < 0) argPtr->interfaceIndex = 0; /* create the thread that will manage this WTP */ if (!CWErr(CWCreateThread(&(gWTPs[i].thread), CWManageWTP, argPtr))) { CW_FREE_OBJECT(argPtr); if (!CWErr(CWThreadMutexLock(&gWTPsMutex))) exit(1); CWDestroySafeList(&gWTPs[i].packetReceiveList); gWTPs[i].isNotFree = CW_FALSE; CWThreadMutexUnlock(&gWTPsMutex); return; } /* Clone data packet */ CW_CREATE_OBJECT_SIZE_ERR(pData, readBytes, { CWLog("Out Of Memory"); return; } ); memcpy(pData, buf, readBytes); CWLockSafeList(gWTPs[i].packetReceiveList); CWAddElementToSafeListTailwitDataFlag(gWTPs[i].packetReceiveList, pData, readBytes, dataFlag); CWUnlockSafeList(gWTPs[i].packetReceiveList); } } } /* * Simple job: see if we have a thread that is serving address *addressPtr */ __inline__ int CWWTPByAddress(CWNetworkLev4Address * addressPtr, CWSocket sock) { int i; if (addressPtr == NULL) return -1; CWThreadMutexLock(&gWTPsMutex); for (i = 0; i < gMaxWTPs; i++) { if (gWTPs[i].isNotFree && &(gWTPs[i].address) != NULL && !sock_cmp_addr((struct sockaddr *)addressPtr, (struct sockaddr *)&(gWTPs[i].address), sizeof(CWNetworkLev4Address))) { /* we treat a WTP that sends packet to a different * AC's interface as a new WTP */ CWThreadMutexUnlock(&gWTPsMutex); return i; } } CWThreadMutexUnlock(&gWTPsMutex); return -1; } /* * Session's thread function: each thread will manage a single session * with one WTP. */ CW_THREAD_RETURN_TYPE CWManageWTP(void *arg) { int i = ((CWACThreadArg *) arg)->index; CWSocket sock = ((CWACThreadArg *) arg)->sock; int interfaceIndex = ((CWACThreadArg *) arg)->interfaceIndex; CW_FREE_OBJECT(arg); if (!(CWThreadSetSpecific(&gIndexSpecific, &i))) { CWLog("Critical Error with Thread Data"); _CWCloseThread(i); } if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) exit(1); gActiveWTPs++; gInterfaces[interfaceIndex].WTPCount++; CWUseSockNtop(((struct sockaddr *)&(gInterfaces[interfaceIndex].addr)), CWDebugLog("One more WTP on %s (%d)", str, interfaceIndex);); CWThreadMutexUnlock(&gActiveWTPsMutex); CWACInitBinding(i); gWTPs[i].interfaceIndex = interfaceIndex; gWTPs[i].socket = sock; gWTPs[i].fragmentsList = NULL; /* we're in the join state for this session */ gWTPs[i].currentState = CW_ENTER_JOIN; gWTPs[i].subState = CW_DTLS_HANDSHAKE_IN_PROGRESS; /**** ACInterface ****/ gWTPs[i].interfaceCommandProgress = CW_FALSE; gWTPs[i].interfaceCommand = NO_CMD; CWDestroyThreadMutex(&gWTPs[i].interfaceMutex); CWCreateThreadMutex(&gWTPs[i].interfaceMutex); CWDestroyThreadMutex(&gWTPs[i].interfaceSingleton); CWCreateThreadMutex(&gWTPs[i].interfaceSingleton); CWDestroyThreadCondition(&gWTPs[i].interfaceWait); CWCreateThreadCondition(&gWTPs[i].interfaceWait); CWDestroyThreadCondition(&gWTPs[i].interfaceComplete); CWCreateThreadCondition(&gWTPs[i].interfaceComplete); gWTPs[i].qosValues = NULL; /**** ACInterface ****/ gWTPs[i].messages = NULL; gWTPs[i].messagesCount = 0; gWTPs[i].isRetransmitting = CW_FALSE; gWTPs[i].retransmissionCount = 0; CWResetWTPProtocolManager(&(gWTPs[i].WTPProtocolManager)); CWLog("New Session"); /* start WaitJoin timer */ if (!CWErr(CWTimerRequest(gCWWaitJoin, &(gWTPs[i].thread), &(gWTPs[i].currentTimer), CW_CRITICAL_TIMER_EXPIRED_SIGNAL))) { CWCloseThread(); } #ifndef CW_NO_DTLS CWDebugLog("Init DTLS Session"); if (!CWErr(CWSecurityInitSessionServer(&gWTPs[i], sock, gACSecurityContext, &((gWTPs[i]).session), &(gWTPs[i].pathMTU)))) { CWTimerCancel(&(gWTPs[i].currentTimer)); CWCloseThread(); } #endif (gWTPs[i]).subState = CW_WAITING_REQUEST; if (gCWForceMTU > 0) gWTPs[i].pathMTU = gCWForceMTU; CWDebugLog("Path MTU for this Session: %d", gWTPs[i].pathMTU); CW_REPEAT_FOREVER { int readBytes; CWProtocolMessage msg; CWBool dataFlag = CW_FALSE; msg.msg = NULL; msg.offset = 0; /* Wait WTP action */ CWThreadMutexLock(&gWTPs[i].interfaceMutex); while ((gWTPs[i].isRequestClose == CW_FALSE) && (CWGetCountElementFromSafeList(gWTPs[i].packetReceiveList) == 0) && (gWTPs[i].interfaceCommand == NO_CMD)) { /*TODO: Check system */ CWWaitThreadCondition(&gWTPs[i].interfaceWait, &gWTPs[i].interfaceMutex); } CWThreadMutexUnlock(&gWTPs[i].interfaceMutex); if (gWTPs[i].isRequestClose) { CWLog("Request close thread"); _CWCloseThread(i); } CWThreadSetSignals(SIG_BLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); if (CWGetCountElementFromSafeList(gWTPs[i].packetReceiveList) > 0) { CWBool bCrypt = CW_FALSE; char *pBuffer; CWThreadMutexLock(&gWTPs[i].interfaceMutex); pBuffer = (char *)CWGetHeadElementFromSafeList(gWTPs[i].packetReceiveList, NULL); if (((pBuffer[0] & 0x0f) == CW_PACKET_CRYPT) && ((gWTPs[i].buf[0] & 0x0f) == CW_PACKET_CRYPT)) bCrypt = CW_TRUE; CWThreadMutexUnlock(&gWTPs[i].interfaceMutex); if (bCrypt) { #ifndef CW_NO_DTLS if (!CWErr(CWSecurityReceive(gWTPs[i].session, gWTPs[i].buf, CW_BUFFER_SIZE - 1, &readBytes))) { /* error */ CWDebugLog("Error during security receive"); CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); continue; } #else CWDebugLog("CAPWAP DTLS in not supported"); CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); continue; #endif } else { CWThreadMutexLock(&gWTPs[i].interfaceMutex); pBuffer = (char *)CWRemoveHeadElementFromSafeListwithDataFlag(gWTPs[i].packetReceiveList, &readBytes, &dataFlag); CWThreadMutexUnlock(&gWTPs[i].interfaceMutex); memcpy(gWTPs[i].buf, pBuffer, readBytes); CW_FREE_OBJECT(pBuffer); } if (!CWProtocolParseFragment(gWTPs[i].buf, readBytes, &(gWTPs[i].fragmentsList), &msg, &dataFlag, gWTPs[i].RadioMAC)) { if (CWErrorGetLastErrorCode() == CW_ERROR_NEED_RESOURCE) { CWDebugLog("Need At Least One More Fragment"); } else { CWErrorHandleLast(); } CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); continue; } switch (gWTPs[i].currentState) { case CW_ENTER_JOIN:{ /* we're inside the join state */ if (!ACEnterJoin(i, &msg)) { if (CWErrorGetLastErrorCode() == CW_ERROR_INVALID_FORMAT) { /* Log and ignore other messages */ CWErrorHandleLast(); CWLog("Received something different from a Join Request"); } else { /* critical error, close session */ CWErrorHandleLast(); CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); CWCloseThread(); } } break; } case CW_ENTER_CONFIGURE:{ if (!ACEnterConfigure(i, &msg)) { if (CWErrorGetLastErrorCode() == CW_ERROR_INVALID_FORMAT) { /* Log and ignore other messages */ CWErrorHandleLast(); CWLog("Received something different from a Configure Request"); } else { /* critical error, close session */ CWErrorHandleLast(); CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); CWCloseThread(); } } break; } case CW_ENTER_DATA_CHECK:{ if (!ACEnterDataCheck(i, &msg)) { if (CWErrorGetLastErrorCode() == CW_ERROR_INVALID_FORMAT) { /* Log and ignore other messages */ CWErrorHandleLast(); CWLog ("Received something different from a Change State Event Request"); } else { /* critical error, close session */ CWErrorHandleLast(); CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); CWCloseThread(); } } break; } case CW_ENTER_RUN:{ if (!ACEnterRun(i, &msg, dataFlag)) { if (CWErrorGetLastErrorCode() == CW_ERROR_INVALID_FORMAT) { /* Log and ignore other messages */ CWErrorHandleLast(); CWLog ("--> Received something different from a valid Run Message"); } else { /* critical error, close session */ CWLog("--> Critical Error... closing thread"); CWErrorHandleLast(); CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); CWCloseThread(); } } break; } default:{ CWLog("Not Handled Packet"); break; } } CW_FREE_PROTOCOL_MESSAGE(msg); } else { CWThreadMutexLock(&gWTPs[i].interfaceMutex); if (gWTPs[i].interfaceCommand != NO_CMD) { CWBool bResult = CW_FALSE; switch (gWTPs[i].interfaceCommand) { case QOS_CMD:{ int seqNum = CWGetSeqNum(); /* CWDebugLog("~~~~~~seq num in Check: %d~~~~~~", seqNum); */ if (CWAssembleConfigurationUpdateRequest(&(gWTPs[i].messages), &(gWTPs[i].messagesCount), gWTPs[i].pathMTU, seqNum, CONFIG_UPDATE_REQ_QOS_ELEMENT_TYPE)) { if (CWACSendAcknowledgedPacket (i, CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE, seqNum)) bResult = CW_TRUE; else CWACStopRetransmission(i); } break; } case CLEAR_CONFIG_MSG_CMD:{ int seqNum = CWGetSeqNum(); /* Clear Configuration Request */ if (CWAssembleClearConfigurationRequest(&(gWTPs[i].messages), &(gWTPs[i].messagesCount), gWTPs[i].pathMTU, seqNum)) { if (CWACSendAcknowledgedPacket (i, CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_RESPONSE, seqNum)) bResult = CW_TRUE; else CWACStopRetransmission(i); } break; } /******************************************************** * 2009 Update: * * New switch case for OFDM_CONTROL_CMD * ********************************************************/ case OFDM_CONTROL_CMD:{ int seqNum = CWGetSeqNum(); if (CWAssembleConfigurationUpdateRequest(&(gWTPs[i].messages), &(gWTPs[i].messagesCount), gWTPs[i].pathMTU, seqNum, CONFIG_UPDATE_REQ_OFDM_ELEMENT_TYPE)) { if (CWACSendAcknowledgedPacket (i, CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE, seqNum)) bResult = CW_TRUE; else CWACStopRetransmission(i); } break; } /*Update 2009 Added case to manage UCI configuration command */ case UCI_CONTROL_CMD:{ int seqNum = CWGetSeqNum(); if (CWAssembleConfigurationUpdateRequest(&(gWTPs[i].messages), &(gWTPs[i].messagesCount), gWTPs[i].pathMTU, seqNum, CONFIG_UPDATE_REQ_VENDOR_UCI_ELEMENT_TYPE)) { if (CWACSendAcknowledgedPacket (i, CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE, seqNum)) bResult = CW_TRUE; else CWACStopRetransmission(i); } break; } case WTP_UPDATE_CMD:{ int seqNum = CWGetSeqNum(); if (CWAssembleConfigurationUpdateRequest(&(gWTPs[i].messages), &(gWTPs[i].messagesCount), gWTPs[i].pathMTU, seqNum, CONFIG_UPDATE_REQ_VENDOR_WUM_ELEMENT_TYPE)) { if (CWACSendAcknowledgedPacket (i, CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE, seqNum)) bResult = CW_TRUE; else CWACStopRetransmission(i); } break; } } gWTPs[i].interfaceCommand = NO_CMD; if (bResult) gWTPs[i].interfaceCommandProgress = CW_TRUE; else { gWTPs[i].interfaceResult = 0; CWSignalThreadCondition(&gWTPs[i].interfaceComplete); CWDebugLog("Error sending command"); } } CWThreadMutexUnlock(&gWTPs[i].interfaceMutex); } CWThreadSetSignals(SIG_UNBLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); } } void _CWCloseThread(int i) { CWThreadSetSignals(SIG_BLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); /**** ACInterface ****/ gWTPs[i].qosValues = NULL; CWThreadMutexUnlock(&(gWTPs[i].interfaceMutex)); /**** ACInterface ****/ if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) exit(1); gInterfaces[gWTPs[i].interfaceIndex].WTPCount--; gActiveWTPs--; CWUseSockNtop(((struct sockaddr *)&(gInterfaces[gWTPs[i].interfaceIndex].addr)), CWLog("Remove WTP on Interface %s (%d)", str, gWTPs[i].interfaceIndex); ); CWThreadMutexUnlock(&gActiveWTPsMutex); CWDebugLog("Close Thread: %08x", (unsigned int)CWThreadSelf()); #ifndef CW_NO_DTLS if (gWTPs[i].subState != CW_DTLS_HANDSHAKE_IN_PROGRESS) { CWSecurityDestroySession(gWTPs[i].session); } #endif /* this will do nothing if the timer isn't active */ CWTimerCancel(&(gWTPs[i].currentTimer)); CWACStopRetransmission(i); if (gWTPs[i].interfaceCommandProgress == CW_TRUE) { CWThreadMutexLock(&gWTPs[i].interfaceMutex); gWTPs[i].interfaceResult = 1; gWTPs[i].interfaceCommandProgress = CW_FALSE; CWSignalThreadCondition(&gWTPs[i].interfaceComplete); CWThreadMutexUnlock(&gWTPs[i].interfaceMutex); } gWTPs[i].session = NULL; gWTPs[i].subState = CW_DTLS_HANDSHAKE_IN_PROGRESS; CWDeleteList(&(gWTPs[i].fragmentsList), CWProtocolDestroyFragment); /* CW_FREE_OBJECT(gWTPs[i].configureReqValuesPtr); */ CWCleanSafeList(gWTPs[i].packetReceiveList, free); CWDestroySafeList(gWTPs[i].packetReceiveList); CWThreadMutexLock(&gWTPsMutex); gWTPs[i].isNotFree = CW_FALSE; CWThreadMutexUnlock(&gWTPsMutex); CWExitThread(); } void CWCloseThread() { int *iPtr; if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { CWLog("Error Closing Thread"); return; } _CWCloseThread(*iPtr); } void CWCriticalTimerExpiredHandler(int arg) { int *iPtr; CWThreadSetSignals(SIG_BLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); CWDebugLog("Critical Timer Expired for Thread: %08x", (unsigned int)CWThreadSelf()); CWDebugLog("Abort Session"); /* CWCloseThread(); */ if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { CWLog("Error Handling Critical timer"); CWThreadSetSignals(SIG_UNBLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); return; } /* Request close thread */ gWTPs[*iPtr].isRequestClose = CW_TRUE; CWSignalThreadCondition(&gWTPs[*iPtr].interfaceWait); } void CWSoftTimerExpiredHandler(int arg) { int *iPtr; CWThreadSetSignals(SIG_BLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); CWDebugLog("Soft Timer Expired for Thread: %08x", (unsigned int)CWThreadSelf()); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { CWLog("Error Handling Soft timer"); CWThreadSetSignals(SIG_UNBLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); return; } if ((!gWTPs[*iPtr].isRetransmitting) || (gWTPs[*iPtr].messages == NULL)) { CWDebugLog("Soft timer expired but we are not retransmitting"); CWThreadSetSignals(SIG_UNBLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); return; } (gWTPs[*iPtr].retransmissionCount)++; CWDebugLog("Retransmission Count increases to %d", gWTPs[*iPtr].retransmissionCount); if (gWTPs[*iPtr].retransmissionCount >= gCWMaxRetransmit) { CWDebugLog("Peer is Dead"); /* ?? _CWCloseThread(*iPtr); * Request close thread */ gWTPs[*iPtr].isRequestClose = CW_TRUE; CWSignalThreadCondition(&gWTPs[*iPtr].interfaceWait); return; } if (!CWErr(CWACResendAcknowledgedPacket(*iPtr))) { _CWCloseThread(*iPtr); } /* CWDebugLog("~~~~~~fine ritrasmissione ~~~~~"); */ CWThreadSetSignals(SIG_UNBLOCK, 2, CW_SOFT_TIMER_EXPIRED_SIGNAL, CW_CRITICAL_TIMER_EXPIRED_SIGNAL); } void CWResetWTPProtocolManager(CWWTPProtocolManager * WTPProtocolManager) { CW_FREE_OBJECT(WTPProtocolManager->locationData); CW_FREE_OBJECT(WTPProtocolManager->name); WTPProtocolManager->sessionID = 0; WTPProtocolManager->descriptor.maxRadios = 0; WTPProtocolManager->descriptor.radiosInUse = 0; WTPProtocolManager->descriptor.encCapabilities.encryptCapsCount = 0; CW_FREE_OBJECT(WTPProtocolManager->descriptor.encCapabilities.encryptCaps); WTPProtocolManager->descriptor.vendorInfos.vendorInfosCount = 0; CW_FREE_OBJECT(WTPProtocolManager->descriptor.vendorInfos.vendorInfos); WTPProtocolManager->radiosInfo.radioCount = 0; CW_FREE_OBJECT(WTPProtocolManager->radiosInfo.radiosInfo); CW_FREE_OBJECT(WTPProtocolManager->ACName); (WTPProtocolManager->ACNameIndex).count = 0; CW_FREE_OBJECT((WTPProtocolManager->ACNameIndex).ACNameIndex); (WTPProtocolManager->radioAdminInfo).radiosCount = 0; CW_FREE_OBJECT((WTPProtocolManager->radioAdminInfo).radios); WTPProtocolManager->StatisticsTimer = 0; (WTPProtocolManager->WTPBoardData).vendorInfosCount = 0; CW_FREE_OBJECT((WTPProtocolManager->WTPBoardData).vendorInfos); CW_FREE_OBJECT(WTPProtocolManager->WTPRebootStatistics); //CWWTPResetRebootStatistics(&(WTPProtocolManager->WTPRebootStatistics)); /* **mancano questi campi:** CWNetworkLev4Address address; int pathMTU; struct sockaddr_in ipv4Address; CWProtocolConfigureRequestValues *configureReqValuesPtr; CWTimerID currentPacketTimer; */ } ================================================ FILE: ACMultiHomedSocket.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #include "common.h" #include "ieee802_11_defs.h" #define TYPE_LEN 2 #define ETH_ALEN 6 #define ETH_HLEN 14 #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif void CWNetworkDeleteMHInterface(void *intPtr) { CW_FREE_OBJECT(intPtr); } int from_8023_to_80211(unsigned char *inbuffer, int inlen, unsigned char *outbuffer, unsigned char *own_addr) { int indx = 0; struct ieee80211_hdr hdr; os_memset(&hdr, 0, sizeof(struct ieee80211_hdr)); hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA) | host_to_le16(WLAN_FC_FROMDS); hdr.duration_id = 0; hdr.seq_ctrl = 0; os_memcpy(hdr.addr1, inbuffer, ETH_ALEN); os_memcpy(hdr.addr2, own_addr, ETH_ALEN); os_memcpy(hdr.addr3, inbuffer + ETH_ALEN, ETH_ALEN); os_memcpy(outbuffer + indx, &hdr, sizeof(hdr)); indx += sizeof(hdr); os_memcpy(outbuffer + indx, inbuffer, inlen); indx += inlen; return indx; } /* * Multihomed sockets maps the system index for each interface to a array-like * int index in range 0-(# of interfaces -1). This function returns the int * index given the system index of an interface managed by the given multihomed * socket. */ int CWNetworkGetInterfaceIndexFromSystemIndex(CWMultiHomedSocket * sockPtr, int systemIndex) { int i, c; if (sockPtr == NULL || systemIndex == -1) return -1; for (i = 0, c = 0; i < sockPtr->count; i++) { if (sockPtr->interfaces[i].kind == CW_PRIMARY) { /* each primary interface increments the int index */ if (sockPtr->interfaces[i].systemIndex == systemIndex) return c; c++; } } return -1; } /* * Check if the interface with system index systemIndex is already managed by * the multihomed socket. If the answer is yes, returns informations on that * interface, returns NULL otherwise. */ CWMultiHomedInterface *CWNetworkGetInterfaceAlreadyStored(CWList list, short systemIndex) { CWListElement *el; for (el = list; el != NULL; el = el->next) { if (((CWMultiHomedInterface *) (el->data))->systemIndex == systemIndex && ((CWMultiHomedInterface *) (el->data))->kind == CW_PRIMARY) return (CWMultiHomedInterface *) el->data; } return NULL; } /* * Init multihomed socket. Will bind a socket for each interface + each * broadcast address + the wildcard addres + each multicast address in * multicastGroups. */ CWBool CWNetworkInitSocketServerMultiHomed(CWMultiHomedSocket * sockPtr, int port, char **multicastGroups, int multicastGroupsCount) { struct ifi_info *ifi, *ifihead; CWNetworkLev4Address wildaddr; int yes = 1; CWSocket sock; CWMultiHomedInterface *p; CWList interfaceList = CW_LIST_INIT; CWListElement *el = NULL; int i; if (sockPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); sockPtr->count = 0; /* * note: if get_ifi_info is called with AF_INET6 on an host that doesn't * support IPv6, it'll simply act like if it was called with AF_INET. * Consider aliases as different interfaces (last arg of get_ifi_info is 1). * Why? Just to increase the funny side of the thing. */ #ifdef CW_DEBUGGING /* for each network interface... */ for (ifihead = ifi = get_ifi_info((gNetworkPreferredFamily == CW_IPv6) ? AF_INET6 : AF_INET, 1); ifi != NULL; ifi = ifi->ifi_next) { #else /* for each network interface... */ for (ifihead = ifi = get_ifi_info((gNetworkPreferredFamily == CW_IPv6) ? AF_INET6 : AF_INET, 0); ifi != NULL; ifi = ifi->ifi_next) { #endif /* bind a unicast address */ if ((sock = socket(ifi->ifi_addr->sa_family, SOCK_DGRAM, 0)) < 0) { free_ifi_info(ifihead); CWNetworkRaiseSystemError(CW_ERROR_CREATING); } /* reuse address */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); /* bind address */ sock_set_port_cw(ifi->ifi_addr, htons(port)); if (bind (sock, (struct sockaddr *)ifi->ifi_addr, CWNetworkGetAddressSize((CWNetworkLev4Address *) ifi->ifi_addr)) < 0) { close(sock); CWUseSockNtop(ifi->ifi_addr, CWDebugLog("failed %s", str); ); continue; /* CWNetworkRaiseSystemError(CW_ERROR_CREATING); */ } CWUseSockNtop(ifi->ifi_addr, CWLog("bound %s (%d, %s)", str, ifi->ifi_index, ifi->ifi_name); ); /* store socket inside multihomed socket */ CW_CREATE_OBJECT_ERR(p, CWMultiHomedInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); p->sock = sock; if (CWNetworkGetInterfaceAlreadyStored(interfaceList, ifi->ifi_index) == NULL && strncmp(ifi->ifi_name, "lo", 2)) { /* don't consider loopback an interface (even if we accept packets from loopback) */ CWDebugLog("Primary Address"); p->kind = CW_PRIMARY; } else { /* should be BROADCAST_OR_ALIAS_OR_MULTICAST_OR_LOOPBACK ;-) */ p->kind = CW_BROADCAST_OR_ALIAS; #ifdef CW_DEBUGGING #if 0 if (!strncmp(ifi->ifi_name, "lo", 2)) { p->kind = CW_PRIMARY; } #endif #endif } p->systemIndex = ifi->ifi_index; /* the next field is useful only if we are an IPv6 server. In * this case, p->addr contains the IPv6 address of the interface * and p->addrIPv4 contains the equivalent IPv4 address. On the * other side, if we are an IPv4 server p->addr contains the * IPv4 address of the interface and p->addrIPv4 is garbage. */ p->addrIPv4.ss_family = AF_UNSPEC; CW_COPY_NET_ADDR_PTR(&(p->addr), ifi->ifi_addr); // Todd: Bind data channel to port 5427 /* bind a unicast address of data UDP stream */ if ((sock = socket(ifi->ifi_addr->sa_family, SOCK_DGRAM, 0)) < 0) { free_ifi_info(ifihead); CWNetworkRaiseSystemError(CW_ERROR_CREATING); } /* reuse address */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); /* bind address */ sock_set_port_cw(ifi->ifi_addr, htons(port + 1)); if (bind (sock, (struct sockaddr *)ifi->ifi_addr, CWNetworkGetAddressSize((CWNetworkLev4Address *) ifi->ifi_addr)) < 0) { close(sock); CWUseSockNtop(ifi->ifi_addr, CWDebugLog("failed %s", str); ); continue; /* CWNetworkRaiseSystemError(CW_ERROR_CREATING); */ } CWUseSockNtop(ifi->ifi_addr, CWLog("Data channel bound %s (%d, %s)", str, ifi->ifi_index, ifi->ifi_name); ); CW_COPY_NET_ADDR_PTR(&(p->dataAddr), ifi->ifi_addr); p->dataSock = sock; if (!CWAddElementToList(&interfaceList, p)) { return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } /* we add a socket to the multihomed socket */ sockPtr->count++; if (ifi->ifi_flags & IFF_BROADCAST) { /* try to bind broadcast address */ if ((sock = socket(ifi->ifi_addr->sa_family, SOCK_DGRAM, 0)) < 0) { free_ifi_info(ifihead); CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); CWNetworkRaiseSystemError(CW_ERROR_CREATING); } /* reuse address */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); sock_set_port_cw(ifi->ifi_brdaddr, htons(port)); if (bind(sock, (struct sockaddr *)ifi->ifi_brdaddr, CWNetworkGetAddressSize((CWNetworkLev4Address *) ifi->ifi_brdaddr)) < 0) { close(sock); if (errno == EADDRINUSE) { CWUseSockNtop(ifi->ifi_brdaddr, CWDebugLog("EADDRINUSE: %s", str);); continue; } else { CWUseSockNtop(ifi->ifi_brdaddr, CWDebugLog("failed %s", str);); continue; /* CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); */ /* CWNetworkRaiseSystemError(CW_ERROR_CREATING); */ } } CWUseSockNtop(ifi->ifi_brdaddr, CWLog("bound %s (%d, %s)", str, ifi->ifi_index, ifi->ifi_name); ); /* store socket inside multihomed socket */ CW_CREATE_OBJECT_ERR(p, CWMultiHomedInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); p->sock = sock; p->kind = CW_BROADCAST_OR_ALIAS; p->systemIndex = ifi->ifi_index; CW_COPY_NET_ADDR_PTR(&(p->addr), ifi->ifi_brdaddr); /* The next field is useful only if we are an IPv6 server. * In this case, p->addr contains the IPv6 address of the * interface and p->addrIPv4 contains the equivalent IPv4 * address. On the other side, if we are an IPv4 server * p->addr contains the IPv4 address of the interface and * p->addrIPv4 is garbage. */ p->addrIPv4.ss_family = AF_UNSPEC; if (!CWAddElementToList(&interfaceList, p)) { return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } /* we add a socket to the multihomed socket */ sockPtr->count++; } } /* get_ifi_info returned an error */ if (ifihead == NULL) { CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Error With get_ifi_info()"); } free_ifi_info(ifihead); #ifdef IPV6 /* we are an IPv6 server */ if (gNetworkPreferredFamily == CW_IPv6) { /* * Store IPv4 addresses for our interfaces in the field "addrIPv4". * Consider aliases as different interfaces (last arg of get_ifi_info is 1). * Why? Just to increase the funny side of the thing. */ #ifdef CW_DEBUGGING for (ifihead = ifi = get_ifi_info(AF_INET, 1); ifi != NULL; ifi = ifi->ifi_next) { #else for (ifihead = ifi = get_ifi_info(AF_INET, 0); ifi != NULL; ifi = ifi->ifi_next) { #endif CWMultiHomedInterface *s = CWNetworkGetInterfaceAlreadyStored(interfaceList, ifi->ifi_index); if (s == NULL || s->kind != CW_PRIMARY || s->addrIPv4.ss_family != AF_UNSPEC || ifi->ifi_addr->sa_family != AF_INET) continue; CW_COPY_NET_ADDR_PTR(&(s->addrIPv4), ifi->ifi_addr); CWUseSockNtop(&(s->addrIPv4), CWDebugLog("IPv4 address %s (%d, %s)", str, ifi->ifi_index, ifi->ifi_name); ); } /* get_ifi_info returned an error */ if (ifihead == NULL) { CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Error with get_ifi_info()"); } free_ifi_info(ifihead); } #endif /* bind wildcard address */ #ifdef IPV6 if (gNetworkPreferredFamily == CW_IPv6) { if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { goto fail; } } else #endif { if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) goto fail; } goto success; fail: CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); CWNetworkRaiseSystemError(CW_ERROR_CREATING); /* this wil return */ /* not reached */ success: /* reuse address */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); CW_ZERO_MEMORY(&wildaddr, sizeof(wildaddr)); #ifdef IPV6 if (gNetworkPreferredFamily == CW_IPv6) { /* fill wildaddr considering it an IPv6 addr */ struct sockaddr_in6 *a = (struct sockaddr_in6 *)&wildaddr; a->sin6_family = AF_INET6; a->sin6_addr = in6addr_any; a->sin6_port = htons(port); } else #endif { /* fill wildaddr considering it an IPv4 addr */ struct sockaddr_in *a = (struct sockaddr_in *)&wildaddr; a->sin_family = AF_INET; a->sin_addr.s_addr = htonl(INADDR_ANY); a->sin_port = htons(port); } if (bind(sock, (struct sockaddr *)&wildaddr, CWNetworkGetAddressSize(&wildaddr)) < 0) { close(sock); CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); CWNetworkRaiseSystemError(CW_ERROR_CREATING); } CWUseSockNtop(&wildaddr, CWLog("bound %s", str);); CW_CREATE_OBJECT_ERR(p, CWMultiHomedInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); p->sock = sock; p->kind = CW_BROADCAST_OR_ALIAS; p->systemIndex = -1; /* make sure this can't be confused with an interface */ /* addrIPv4 field for the wildcard address cause it * is garbage in both cases (IPv4 + IPv6) */ p->addrIPv4.ss_family = AF_UNSPEC; CW_COPY_NET_ADDR_PTR(&(p->addr), &wildaddr); if (!CWAddElementToList(&interfaceList, p)) { return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } sockPtr->count++; /* bind multicast addresses */ for (i = 0; i < multicastGroupsCount; i++) { struct addrinfo hints, *res, *ressave; char serviceName[5]; CWSocket sock; CW_ZERO_MEMORY(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /* endianness will be handled by getaddrinfo */ snprintf(serviceName, 5, "%d", CW_CONTROL_PORT); CWLog("Joining Multicast Group: %s...", multicastGroups[i]); if (getaddrinfo(multicastGroups[i], serviceName, &hints, &res) != 0) { CWNetworkRaiseSystemError(CW_ERROR_CREATING); } ressave = res; do { if ((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) { continue; /* try next address */ } /* reuse address */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); if (bind(sock, res->ai_addr, res->ai_addrlen) == 0) break; /* success */ close(sock); /* failure */ } while ((res = res->ai_next) != NULL); if (res == NULL) { /* error on last iteration */ CWNetworkRaiseSystemError(CW_ERROR_CREATING); } if (mcast_join(sock, res->ai_addr, res->ai_addrlen, NULL, 0) != 0) { CWNetworkRaiseSystemError(CW_ERROR_CREATING); } CWUseSockNtop((res->ai_addr), CWLog("Joined Multicast Group: %s", str);); CW_CREATE_OBJECT_ERR(p, CWMultiHomedInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); p->sock = sock; p->kind = CW_BROADCAST_OR_ALIAS; p->systemIndex = -1; p->addrIPv4.ss_family = AF_UNSPEC; CW_COPY_NET_ADDR_PTR(&(p->addr), res->ai_addr); if (!CWAddElementToList(&interfaceList, p)) { return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } sockPtr->count++; /* we add a socket to the multihomed socket */ freeaddrinfo(ressave); } /* * Lists are fun when you don't know how many sockets will not give an * error on creating/binding, but now that we know the exact number we * convert it into an array. The "interfaces" field of CWMultiHomedSocket * is actually an array. */ CW_CREATE_ARRAY_ERR((sockPtr->interfaces), sockPtr->count, CWMultiHomedInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* create array from list */ for (el = interfaceList, i = 0; el != NULL; el = el->next, i++) { CW_COPY_MH_INTERFACE_PTR(&((sockPtr->interfaces)[i]), ((CWMultiHomedInterface *) (el->data))); } /* delete the list */ CWDeleteList(&interfaceList, CWNetworkDeleteMHInterface); return CW_TRUE; } void CWNetworkCloseMultiHomedSocket(CWMultiHomedSocket * sockPtr) { int i = 0; if (sockPtr == NULL || sockPtr->interfaces == NULL) return; for (i = 0; i < sockPtr->count; i++) close(sockPtr->interfaces[i].sock); CW_FREE_OBJECT(sockPtr->interfaces); sockPtr->count = 0; } int get_mac_addr(unsigned char *outBuf, char *eth_name) { struct ifreq s; int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); strcpy(s.ifr_name, eth_name); if (!ioctl(fd, SIOCGIFHWADDR, &s)) memcpy(outBuf, s.ifr_addr.sa_data, 6); return 0; } /* * Blocks until one ore more interfaces are ready to read something. When there * is at least one packet pending, call CWManageIncomingPacket() for each pending * packet, then return. */ CWBool CWNetworkUnsafeMultiHomed(CWMultiHomedSocket * sockPtr, void (*CWManageIncomingPacket) (CWSocket, unsigned char *, int, int, CWNetworkLev4Address *, CWBool), CWBool peekRead) { fd_set fset; int max = 0, i; CWNetworkLev4Address addr; CWNetworkLev4Address address; int k; int fragmentsNum = 0; CWProtocolMessage *completeMsgPtr = NULL; CWProtocolMessage *frame = NULL; int dataSocket = 0; int readBytes; int flags = ((peekRead != CW_FALSE) ? MSG_PEEK : 0); unsigned char buf[CW_BUFFER_SIZE]; if (sockPtr == NULL || sockPtr->count == 0 || CWManageIncomingPacket == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); FD_ZERO(&fset); /* select() on all the sockets */ for (i = 0; i < sockPtr->count; i++) { FD_SET(sockPtr->interfaces[i].sock, &fset); if (sockPtr->interfaces[i].sock > max) max = sockPtr->interfaces[i].sock; if (sockPtr->interfaces[i].dataSock != 0) { // Todd: add tap device to 'select ' FD_SET(sockPtr->interfaces[i].dataSock, &fset); if (sockPtr->interfaces[i].dataSock > max) max = sockPtr->interfaces[i].dataSock; } } for (i = 0; i < gMaxWTPs; i++) { if (gWTPs[i].tap_fd != 0) { FD_SET(gWTPs[i].tap_fd, &fset); if (gWTPs[i].tap_fd > max) max = gWTPs[i].tap_fd; } } while (select(max + 1, &fset, NULL, NULL, NULL) < 0) { if (errno != EINTR) { CWNetworkRaiseSystemError(CW_ERROR_GENERAL); } } /* calls CWManageIncomingPacket() for each interface * that has an incoming packet */ for (i = 0; i < gMaxWTPs; i++) { // CWDebugLog("Parsing TAP %d", gWTPs[i].tap_fd); if (FD_ISSET(gWTPs[i].tap_fd, &fset)) { readBytes = read(gWTPs[i].tap_fd, buf, CW_BUFFER_SIZE); //Todd: read from TAP then forward to WTP through data channel CWDebugLog("gWTPs[%d].tap_fd:%d is set,data(%d bytes)", i, gWTPs[i].tap_fd, readBytes); if (readBytes < 0) { CWDebugLog("Reading from tap interface"); perror("Reading from interface"); close(gWTPs[i].tap_fd); gWTPs[i].tap_fd = 0; } if (gWTPs[i].currentState != CW_ENTER_RUN) { CWDebugLog("WTP %d is not in RUN State. The packet was dropped.", i); continue; } else { unsigned char macAddrTap[6]; get_mac_addr(macAddrTap, gWTPs[i].tap_name); unsigned char buf80211[CW_BUFFER_SIZE + 24]; int readByest80211 = from_8023_to_80211(buf, readBytes, buf80211, macAddrTap); CW_CREATE_OBJECT_ERR(frame, CWProtocolMessage, return 0; ); CW_CREATE_PROTOCOL_MESSAGE(*frame, readByest80211, return 0; ); memcpy(frame->msg, buf80211, readByest80211); frame->offset = readByest80211; frame->data_msgType = CW_IEEE_802_11_FRAME_TYPE; if (!CWAssembleDataMessage(&completeMsgPtr, &fragmentsNum, gWTPs[i].pathMTU, frame, NULL, CW_PACKET_PLAIN, 0)) { for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*frame); CW_FREE_OBJECT(frame); continue; } for (k = 0; k < sockPtr->count; k++) { if (sockPtr->interfaces[k].sock == gWTPs[i].socket) { dataSocket = sockPtr->interfaces[k].dataSock; CW_COPY_NET_ADDR_PTR(&address, &(gWTPs[i].dataAddress)); break; } } if (dataSocket == 0) { CWDebugLog("data socket of WTP %d isn't ready."); continue; } /* Set port and address of data tunnel */ //sock_set_port_cw((struct sockaddr *)&(address), htons(CW_DATA_PORT)); for (k = 0; k < fragmentsNum; k++) { if (!CWNetworkSendUnsafeUnconnected(dataSocket, &(address), completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { CWDebugLog("Failure sending Request"); break; } } for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*(frame)); CW_FREE_OBJECT(frame); } } } for (i = 0; i < sockPtr->count; i++) { if (FD_ISSET(sockPtr->interfaces[i].sock, &fset)) { int readBytes; /* CWUseSockNtop(&(sockPtr->interfaces[i].addr), CWDebugLog("Ready on %s", str); ); */ CW_ZERO_MEMORY(buf, CW_BUFFER_SIZE); /* message */ if (!CWErr (CWNetworkReceiveUnsafe (sockPtr->interfaces[i].sock, buf, CW_BUFFER_SIZE - 1, flags, &addr, &readBytes))) { sleep(1); continue; } CWManageIncomingPacket(sockPtr->interfaces[i].sock, buf, readBytes, CWNetworkGetInterfaceIndexFromSystemIndex(sockPtr, sockPtr->interfaces[i]. systemIndex), &addr, CW_FALSE); } if (FD_ISSET(sockPtr->interfaces[i].dataSock, &fset)) { //Todd: Bridge 802.3 packets of WTPs into AC int readBytes; CW_ZERO_MEMORY(buf, CW_BUFFER_SIZE); /* message */ if (!CWErr (CWNetworkReceiveUnsafe (sockPtr->interfaces[i].dataSock, buf, CW_BUFFER_SIZE - 1, flags, &addr, &readBytes))) { sleep(1); continue; } CWManageIncomingPacket(sockPtr->interfaces[i].dataSock, buf, readBytes, CWNetworkGetInterfaceIndexFromSystemIndex(sockPtr, sockPtr->interfaces[i]. systemIndex), &addr, CW_TRUE); } /* else {CWDebugLog("~~~~~~~Non Ready on....~~~~~~");} */ } return CW_TRUE; } /* count distinct interfaces managed by the multihomed socket */ int CWNetworkCountInterfaceAddresses(CWMultiHomedSocket * sockPtr) { int count = 0; int i; if (sockPtr == NULL) return 0; for (i = 0; i < sockPtr->count; i++) { if (sockPtr->interfaces[i].kind == CW_PRIMARY) count++; } return count; } /* * Get the addresses of each distinct interface managed by the multihomed * socket. If we are an IPv6 server element with index i of addressesPtr contains * the IPv6 address of the interface at index i (our mapped index, not system * index) and the element at index i of IPv4AddressesPtr contains the IPv4 * equivalent address for the interface at index i. If we are an IPv4 server, * addressesPtr are the IPv4 addresses and IPv4AddressesPtr is garbage. */ CWBool CWNetworkGetInterfaceAddresses(CWMultiHomedSocket * sockPtr, CWNetworkLev4Address ** addressesPtr, struct sockaddr_in ** IPv4AddressesPtr) { int i, j; if (sockPtr == NULL || addressesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_ARRAY_ERR(*addressesPtr, CWNetworkCountInterfaceAddresses(sockPtr), CWNetworkLev4Address, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (IPv4AddressesPtr != NULL && gNetworkPreferredFamily == CW_IPv6) { CW_CREATE_ARRAY_ERR(*IPv4AddressesPtr, CWNetworkCountInterfaceAddresses(sockPtr), struct sockaddr_in, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } for (i = 0, j = 0; i < sockPtr->count; i++) { if (sockPtr->interfaces[i].kind == CW_PRIMARY) { CW_COPY_NET_ADDR_PTR(&((*addressesPtr)[j]), ((CWNetworkLev4Address *) & (sockPtr->interfaces[i].addr))); if (IPv4AddressesPtr != NULL && gNetworkPreferredFamily == CW_IPv6) { CW_COPY_NET_ADDR_PTR(&((*IPv4AddressesPtr)[j]), ((CWNetworkLev4Address *) & (sockPtr->interfaces[i].addrIPv4))); } j++; } } return CW_TRUE; } ================================================ FILE: ACMultiHomedSocket.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWMultiHomedSocket_HEADER__ #define __CAPWAP_CWMultiHomedSocket_HEADER__ #include "CWNetwork.h" /*_____________________________________________________*/ /* *******************___TYPES___******************* */ typedef struct { CWNetworkLev4Address addr; CWNetworkLev4Address addrIPv4; CWSocket sock; enum { CW_PRIMARY, CW_BROADCAST_OR_ALIAS } kind; short systemIndex; // real interface index in the system CWNetworkLev4Address dataAddr; CWSocket dataSock; } CWMultiHomedInterface; typedef struct { int count; CWMultiHomedInterface *interfaces; } CWMultiHomedSocket; /*_____________________________________________________*/ /* *******************___MACRO___******************* */ #define CW_COPY_MH_INTERFACE_PTR(int1, int2) CW_COPY_NET_ADDR_PTR( &((int1)->addr), &((int2)->addr)); \ CW_COPY_NET_ADDR_PTR( &((int1)->addrIPv4), &((int2)->addrIPv4));\ (int1)->sock = (int2)->sock; \ (int1)->dataSock = (int2)->dataSock; \ (int1)->kind = (int2)->kind; \ (int1)->systemIndex = (int2)->systemIndex; /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ CWBool CWNetworkInitSocketServerMultiHomed(CWMultiHomedSocket * sockPtr, int port, char **multicastGroups, int multicastGroupsCount); void CWNetworkCloseMultiHomedSocket(CWMultiHomedSocket * sockPtr); CWBool CWNetworkUnsafeMultiHomed(CWMultiHomedSocket * sockPtr, void (*CWManageIncomingPacket) (CWSocket, unsigned char *, int, int, CWNetworkLev4Address *, CWBool), CWBool peekRead); int CWNetworkCountInterfaceAddresses(CWMultiHomedSocket * sockPtr); CWBool CWNetworkGetInterfaceAddresses(CWMultiHomedSocket * sockPtr, CWNetworkLev4Address ** addressesPtr, struct sockaddr_in **IPv4AddressesPtr); #endif ================================================ FILE: ACProtocol.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #include "CWVendorPayloads.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif unsigned char WTPRadioInformationType; /*____________________________________________________________________________*/ /* *****************************___ASSEMBLE___***************************** */ /*Update 2009: Assemble protocol Configuration update request. Mainly added to manage vendor specific packets*/ CWBool CWProtocolAssembleConfigurationUpdateRequest(CWProtocolMessage ** msgElems, int *msgElemCountPtr, int MsgElementType) { int *iPtr; int k = -1; if (msgElems == NULL || msgElemCountPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } *msgElemCountPtr = 1; CWLog("Assembling Protocol Configuration Update Request..."); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(*msgElems, *msgElemCountPtr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* Selection of type of Conf Update Request */ switch (MsgElementType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: // Assemble Message Elements if (!(CWAssembleWTPVendorPayloadUCI(&(*msgElems[++k])))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(*msgElems[i]); } CW_FREE_OBJECT(*msgElems); return CW_FALSE; // error will be handled by the caller } break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: // Assemble Message Elements if (!(CWAssembleWTPVendorPayloadWUM(&(*msgElems[++k])))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(*msgElems[i]); } CW_FREE_OBJECT(*msgElems); return CW_FALSE; // error will be handled by the caller } break; default:{ return CW_FALSE; // error will be handled by the caller } } CWLog("Protocol Configuration Update Request Assembled"); return CW_TRUE; } CWBool CWAssembleMsgElemACWTPRadioInformation(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL);; // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 5, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, 0); // Radio ID CWProtocolStore8(msgPtr, 0); // Reserved CWProtocolStore8(msgPtr, 0); // Reserved CWProtocolStore8(msgPtr, 0); // Reserved CWProtocolStore8(msgPtr, 0); // Radio Information Type ABGN return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE); } CWBool CWAssembleMsgElemACDescriptor(CWProtocolMessage * msgPtr) { CWACVendorInfos infos; int i = 0, size = 0; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL);; if (!CWACGetVendorInfos(&infos)) { // get infos return CW_FALSE; } for (i = 0; i < infos.vendorInfosCount; i++) { size += (8 + ((infos.vendorInfos)[i]).length); } size += 12; // size of message in bytes (excluding vendor infos, already counted) // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, size, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore16(msgPtr, CWACGetStations()); // Number of mobile stations associated CWProtocolStore16(msgPtr, CWACGetLimit()); // Maximum number of mobile stations supported CWProtocolStore16(msgPtr, CWACGetActiveWTPs()); // Number of WTPs active CWProtocolStore16(msgPtr, CWACGetMaxWTPs()); // Maximum number of WTPs supported CWProtocolStore8(msgPtr, CWACGetSecurity()); CWProtocolStore8(msgPtr, CWACGetRMACField()); CWProtocolStore8(msgPtr, 0); //Reserved CWProtocolStore8(msgPtr, CWACGetDTLSPolicy()); // DTLS Policy for (i = 0; i < infos.vendorInfosCount; i++) { CWProtocolStore32(msgPtr, ((infos.vendorInfos)[i].vendorIdentifier)); CWProtocolStore16(msgPtr, ((infos.vendorInfos)[i].type)); CWProtocolStore16(msgPtr, ((infos.vendorInfos)[i].length)); if ((infos.vendorInfos)[i].length == 4) { *((infos.vendorInfos)[i].valuePtr) = htonl(*((infos.vendorInfos)[i].valuePtr)); } CWProtocolStoreRawBytes(msgPtr, (unsigned char*)((infos.vendorInfos)[i].valuePtr), (infos.vendorInfos)[i].length); } CWACDestroyVendorInfos(&infos); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_AC_DESCRIPTOR_CW_TYPE); } CWBool CWAssembleMsgElemACIPv4List(CWProtocolMessage * msgPtr) { int *list; int count, i; const int IPv4_List_length = 4; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!CWACGetACIPv4List(&list, &count)) return CW_FALSE; // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, IPv4_List_length * count, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < count; i++) { CWProtocolStore32(msgPtr, list[i]); // CWDebugLog("AC IPv4 List(%d): %d", i, list[i]); } CW_FREE_OBJECT(list); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_AC_IPV4_LIST_CW_TYPE); } CWBool CWAssembleMsgElemACIPv6List(CWProtocolMessage * msgPtr) { struct in6_addr *list; const int IPv6_List_length = 16; int count, i; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!CWACGetACIPv6List(&list, &count)) return CW_FALSE; // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, IPv6_List_length * count, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /*--- ATTENZIONE! l'indirizzo ipv6 forse deve essere girato ---*/ for (i = 0; i < count; i++) { CWProtocolStoreRawBytes(msgPtr, list[i].s6_addr, 16); } CW_FREE_OBJECT(list); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_AC_IPV6_LIST_CW_TYPE); } CWBool CWAssembleMsgElemACName(CWProtocolMessage * msgPtr) { char *name; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); name = CWACGetName(); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, strlen(name), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreStr(msgPtr, name); // CWDebugLog("AC Name: %s", name); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_AC_NAME_CW_TYPE); } CWBool CWAssembleMsgElemAddWLAN(int radioID, CWProtocolMessage * msgPtr, unsigned char *recv_packet, int len_packet) { // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len_packet, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreRawBytes(msgPtr, recv_packet, len_packet); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IEEE80211_ADD_WLAN_CW_TYPE); } CWBool CWAssembleMsgElemDeleteWLAN(int radioID, CWProtocolMessage * msgPtr, unsigned char *recv_packet, int len_packet) { CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len_packet, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreRawBytes(msgPtr, recv_packet, len_packet); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IEEE80211_DELETE_WLAN_CW_TYPE); } CWBool CWAssembleMsgElemAddStation(int radioID, CWProtocolMessage * msgPtr, unsigned char *StationMacAddr) { const int add_Station_Length = 8; int Length = 6; //mac address length in bytes (48 bit) // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, add_Station_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, radioID); CWProtocolStore8(msgPtr, Length); CWProtocolStoreRawBytes(msgPtr, StationMacAddr, Length); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_ADD_STATION_CW_TYPE); } CWBool CWAssembleMsgElemDeleteStation(int radioID, CWProtocolMessage * msgPtr, unsigned char *StationMacAddr) { const int delete_Station_Length = 8; int Length = 6; //mac address length in bytes (48 bit) CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, delete_Station_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, radioID); CWProtocolStore8(msgPtr, Length); CWProtocolStoreRawBytes(msgPtr, StationMacAddr, Length); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_DELETE_STATION_CW_TYPE); } CWBool CWAssembleMsgElemCWControlIPv4Addresses(CWProtocolMessage * msgPtr) { int count, i; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); count = CWACGetInterfacesCount(); if (count <= 0) { return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "No Interfaces Configured"); } for (i = 0; i < count; i++) { // one Message Element for each interface CWProtocolMessage temp; // create message CW_CREATE_PROTOCOL_MESSAGE(temp, 6, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore32(&temp, CWACGetInterfaceIPv4AddressAtIndex(i)); CWProtocolStore16(&temp, CWACGetInterfaceWTPCountAtIndex(i)); CWAssembleMsgElem(&temp, CW_MSG_ELEMENT_CW_CONTROL_IPV4_ADDRESS_CW_TYPE); if (i == 0) { CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, (temp.offset) * count, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } CWProtocolStoreMessage(msgPtr, &temp); CW_FREE_PROTOCOL_MESSAGE(temp); } return CW_TRUE; } CWBool CWAssembleMsgElemCWControlIPv6Addresses(CWProtocolMessage * msgPtr) { int count, i; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); count = CWACGetInterfacesCount(); for (i = 0; i < count; i++) { // one Message Element for each interface CWProtocolMessage temp; // create message CW_CREATE_PROTOCOL_MESSAGE(temp, 18, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreRawBytes(&temp, CWACGetInterfaceIPv6AddressAtIndex(i), 16); CWProtocolStore16(&temp, CWACGetInterfaceWTPCountAtIndex(i)); CWAssembleMsgElem(&temp, CW_MSG_ELEMENT_CW_CONTROL_IPV6_ADDRESS_CW_TYPE); if (i == 0) { CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, (temp.offset) * count, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } CWProtocolStoreMessage(msgPtr, &temp); CW_FREE_PROTOCOL_MESSAGE(temp); } return CW_TRUE; } CWBool CWAssembleMsgElemCWTimer(CWProtocolMessage * msgPtr) { int discoveryTimer, echoTimer; const int CWTimer_length = 2; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, CWTimer_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWACGetDiscoveryTimer(&discoveryTimer)) || !(CWACGetEchoRequestTimer(&echoTimer))) return CW_FALSE; CWProtocolStore8(msgPtr, discoveryTimer); CWProtocolStore8(msgPtr, echoTimer); // CWDebugLog("Discovery Timer: %d", discoveryTimer); // CWDebugLog("Echo Timer: %d", echoTimer); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_CW_TIMERS_CW_TYPE); } /* Le informazioni sui Radio ID vengono prese dalle informazioni del Configure Message Provvisoriamente l'error Report Period è settato allo stesso valore per tutte le radio del WTP*/ CWBool CWAssembleMsgElemDecryptErrorReportPeriod(CWProtocolMessage * msgPtr) { const int radio_Decrypt_Error_Report_Period_Length = 3; const int reportInterval = 15; CWProtocolMessage *msgs; CWRadioAdminInfoValues *radiosInfoPtr; int radioCount = 0; int *iPtr; int len = 0; int i; int j; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { CWLog("Critical Error... closing thread"); CWCloseThread(); } radiosInfoPtr = gWTPs[*iPtr].WTPProtocolManager.radioAdminInfo.radios; radioCount = gWTPs[*iPtr].WTPProtocolManager.radioAdminInfo.radiosCount; CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgs, radioCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < radioCount; i++) { // create message CW_CREATE_PROTOCOL_MESSAGE(msgs[i], radio_Decrypt_Error_Report_Period_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(&(msgs[i]), radiosInfoPtr[i].ID); // ID of the radio CWProtocolStore16(&(msgs[i]), reportInterval); // state of the radio if (!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_PERIOD_CW_TYPE))) { for (j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]); } CW_FREE_OBJECT(msgs); return CW_FALSE; } len += msgs[i].offset; // CWDebugLog("Decrypt Error Report Period: %d - %d", radiosInfoPtr[i].ID, reportInterval); } CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < radioCount; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } CW_FREE_OBJECT(msgs); return CW_TRUE; } CWBool CWAssembleMsgElemIdleTimeout(CWProtocolMessage * msgPtr) { int idleTimeout; const int idle_Timeout_length = 4; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, idle_Timeout_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWACGetIdleTimeout(&idleTimeout))) return CW_FALSE; CWProtocolStore32(msgPtr, idleTimeout); // CWDebugLog("Idle Timeout: %d", idleTimeout); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IDLE_TIMEOUT_CW_TYPE); } CWBool CWAssembleMsgElemWTPFallback(CWProtocolMessage * msgPtr) { int value = 0; //PROVVISORIO const int WTP_fallback_length = 1; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, WTP_fallback_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, value); // CWDebugLog("Fallback: %d", value); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_FALLBACK_CW_TYPE); } CWBool CWAssembleMsgElemRadioOperationalState(int radioID, CWProtocolMessage * msgPtr) { const int radio_Operational_State_Length = 3; CWRadiosOperationalInfo infos; CWProtocolMessage *msgs; int len = 0; int i; int j; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!(CWGetWTPRadiosOperationalState(radioID, &infos))) { return CW_FALSE; } CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgs, (infos.radiosCount), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { // create message CW_CREATE_PROTOCOL_MESSAGE(msgs[i], radio_Operational_State_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(&(msgs[i]), infos.radios[i].ID); // ID of the radio CWProtocolStore8(&(msgs[i]), infos.radios[i].state); // state of the radio CWProtocolStore8(&(msgs[i]), infos.radios[i].cause); if (!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE))) { for (j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]); } CW_FREE_OBJECT(infos.radios); CW_FREE_OBJECT(msgs); return CW_FALSE; } len += msgs[i].offset; // CWDebugLog("Radio operational State: %d - %d - %d", infos.radios[i].ID, infos.radios[i].state, infos.radios[i].cause); } CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } CW_FREE_OBJECT(msgs); CW_FREE_OBJECT(infos.radios); return CW_TRUE; } /*_________________________________________________________________________*/ /* *****************************___PARSE___***************************** */ CWBool CWParseACNameWithIndex(CWProtocolMessage * msgPtr, int len, CWACNameWithIndexValues * valPtr) { CWParseMessageElementStart(); valPtr->index = CWProtocolRetrieve8(msgPtr); //CWDebugLog("CW_MSG_ELEMENT_WTP_RADIO_ID: %d", (valPtr->radios)[radioIndex].ID); valPtr->ACName = CWProtocolRetrieveStr(msgPtr, len - 1); //CWDebugLog("CW_MSG_ELEMENT_WTP_RADIO_TYPE: %d", (valPtr->radios)[radioIndex].type); //CWDebugLog("AC Name with index: %d - %s", valPtr->index, valPtr->ACName); CWParseMessageElementEnd(); } CWBool CWParseDiscoveryType(CWProtocolMessage * msgPtr, int len, CWDiscoveryRequestValues * valPtr) { CWParseMessageElementStart(); valPtr->type = CWProtocolRetrieve8(msgPtr); CWParseMessageElementEnd(); } CWBool CWParseLocationData(CWProtocolMessage * msgPtr, int len, char **valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieveStr(msgPtr, len); if (valPtr == NULL) return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); // CWDebugLog("Location Data:%s", *valPtr); CWParseMessageElementEnd(); } CWBool CWParseMsgElemDuplicateIPv4Address(CWProtocolMessage * msgPtr, int len, WTPDuplicateIPv4 * valPtr) { CWParseMessageElementStart(); valPtr->ipv4Address = CWProtocolRetrieve32(msgPtr); valPtr->status = CWProtocolRetrieve8(msgPtr); valPtr->length = CWProtocolRetrieve8(msgPtr); valPtr->MACoffendingDevice_forIpv4 = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, valPtr->length); //valPtr->MACoffendingDevice_forIpv4 = (unsigned char*)CWProtocolRetrieveRawBytes(msgPtr,6); //valPtr->status = CWProtocolRetrieve8(msgPtr); // CWDebugLog("Duplicate IPv4: %d", valPtr->ipv4Address); CWParseMessageElementEnd(); } CWBool CWParseMsgElemDuplicateIPv6Address(CWProtocolMessage * msgPtr, int len, WTPDuplicateIPv6 * valPtr) { CWParseMessageElementStart(); int i; for (i = 0; i < 16; i++) { unsigned char *aux; aux = CWProtocolRetrieveRawBytes(msgPtr, 1); (valPtr->ipv6Address).s6_addr[i] = *aux; } // CWDebugLog("Duplicate IPv6"); //valPtr->MACoffendingDevice_forIpv6 = (unsigned char*)CWProtocolRetrieveRawBytes(msgPtr,6); valPtr->status = CWProtocolRetrieve8(msgPtr); valPtr->length = CWProtocolRetrieve8(msgPtr); valPtr->MACoffendingDevice_forIpv6 = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, valPtr->length); CWParseMessageElementEnd(); } CWBool CWParseWTPStatisticsTimer(CWProtocolMessage * msgPtr, int len, int *valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieve16(msgPtr); // CWDebugLog("WTP Statistics Timer: %d", *valPtr); CWParseMessageElementEnd(); } CWBool CWParseWTPBoardData(CWProtocolMessage * msgPtr, int len, CWWTPVendorInfos * valPtr) { int theOffset, i, vendorID; CWParseMessageElementStart(); valPtr->vendorInfosCount = 0; // see how many vendor ID we have in the message vendorID = CWProtocolRetrieve32(msgPtr); // ID theOffset = msgPtr->offset; while ((msgPtr->offset - oldOffset) < len) { // oldOffset stores msgPtr->offset's value at the beginning of this function. // See the definition of the CWParseMessageElementStart() macro. int tmp; CWProtocolRetrieve16(msgPtr); // type tmp = CWProtocolRetrieve16(msgPtr); msgPtr->offset += tmp; // len valPtr->vendorInfosCount++; } msgPtr->offset = theOffset; // actually read each vendor ID CW_CREATE_ARRAY_ERR(valPtr->vendorInfos, valPtr->vendorInfosCount, CWWTPVendorInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < valPtr->vendorInfosCount; i++) { (valPtr->vendorInfos)[i].vendorIdentifier = vendorID; (valPtr->vendorInfos)[i].type = CWProtocolRetrieve16(msgPtr); (valPtr->vendorInfos)[i].length = CWProtocolRetrieve16(msgPtr); (valPtr->vendorInfos)[i].valuePtr = (CWProtocolRetrieveRawBytes(msgPtr, (valPtr->vendorInfos)[i].length)); if ((valPtr->vendorInfos)[i].valuePtr == NULL) return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); if ((valPtr->vendorInfos)[i].length == 4) { *(int *)((valPtr->vendorInfos)[i].valuePtr) = ntohl(*((valPtr->vendorInfos)[i].valuePtr)); } // CWDebugLog("WTP Board Data: %d - %d - %d - %d", (valPtr->vendorInfos)[i].vendorIdentifier, (valPtr->vendorInfos)[i].type, (valPtr->vendorInfos)[i].length, *(valPtr->vendorInfos)[i].valuePtr); } CWParseMessageElementEnd(); } CWBool CWParseMsgElemDataTransferData(CWProtocolMessage * msgPtr, int len, CWProtocolWTPDataTransferRequestValues * valPtr) { CWParseMessageElementStart(); valPtr->data = CWProtocolRetrieve8(msgPtr); valPtr->length = CWProtocolRetrieve8(msgPtr); valPtr->debug_info = CWProtocolRetrieveStr(msgPtr, valPtr->length); //CWDebugLog("- %s ---",valPtr->debug_info); CWParseMessageElementEnd(); } CWBool CWParseWTPDescriptor(CWProtocolMessage * msgPtr, int len, CWWTPDescriptor * valPtr) { int theOffset, i; CWParseMessageElementStart(); valPtr->maxRadios = CWProtocolRetrieve8(msgPtr); // CWDebugLog("WTP Descriptor Max Radios: %d", valPtr->maxRadios); valPtr->radiosInUse = CWProtocolRetrieve8(msgPtr); // CWDebugLog("WTP Descriptor Active Radios: %d", valPtr->radiosInUse); valPtr->encCapabilities.encryptCapsCount = CWProtocolRetrieve8(msgPtr); CW_CREATE_ARRAY_ERR(valPtr->encCapabilities.encryptCaps, valPtr->encCapabilities.encryptCapsCount, CWWTPEncryptCapValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < valPtr->encCapabilities.encryptCapsCount; i++) { (valPtr->encCapabilities.encryptCaps)[i].WBID = CWProtocolRetrieve8(msgPtr) & 0x1f; (valPtr->encCapabilities.encryptCaps)[i].encryptionCapabilities = CWProtocolRetrieve16(msgPtr); } valPtr->vendorInfos.vendorInfosCount = 0; theOffset = msgPtr->offset; // see how many vendor ID we have in the message while ((msgPtr->offset - oldOffset) < len) { // oldOffset stores msgPtr->offset's value at the beginning of this function. // See the definition of the CWParseMessageElementStart() macro. int tmp; CWProtocolRetrieve32(msgPtr); // ID CWProtocolRetrieve16(msgPtr); // type tmp = CWProtocolRetrieve16(msgPtr); // len msgPtr->offset += tmp; valPtr->vendorInfos.vendorInfosCount++; } msgPtr->offset = theOffset; // actually read each vendor ID CW_CREATE_ARRAY_ERR(valPtr->vendorInfos.vendorInfos, valPtr->vendorInfos.vendorInfosCount, CWWTPVendorInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < valPtr->vendorInfos.vendorInfosCount; i++) { (valPtr->vendorInfos.vendorInfos)[i].vendorIdentifier = CWProtocolRetrieve32(msgPtr); (valPtr->vendorInfos.vendorInfos)[i].type = CWProtocolRetrieve16(msgPtr); (valPtr->vendorInfos.vendorInfos)[i].length = CWProtocolRetrieve16(msgPtr); (valPtr->vendorInfos.vendorInfos)[i].valuePtr = (CWProtocolRetrieveRawBytes(msgPtr, (valPtr->vendorInfos.vendorInfos)[i].length)); if ((valPtr->vendorInfos.vendorInfos)[i].valuePtr == NULL) return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); if ((valPtr->vendorInfos.vendorInfos)[i].length == 4) { *((valPtr->vendorInfos.vendorInfos)[i].valuePtr) = ntohl(*((valPtr->vendorInfos.vendorInfos)[i].valuePtr)); } // CWDebugLog("WTP Descriptor Vendor ID: %d", (valPtr->vendorInfos.vendorInfos)[i].vendorIdentifier); // CWDebugLog("WTP Descriptor Type: %d", (valPtr->vendorInfos.vendorInfos)[i].type); // CWDebugLog("WTP Descriptor Length: %d", (valPtr->vendorInfos.vendorInfos)[i].length); // CWDebugLog("WTP Descriptor Value: %d", *((valPtr->vendorInfos.vendorInfos)[i].valuePtr)); } CWParseMessageElementEnd(); } CWBool CWParseWTPFrameTunnelMode(CWProtocolMessage * msgPtr, int len, CWframeTunnelMode * valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieve8(msgPtr); // CWDebugLog("CW_MSG_ELEMENT_WTP_FRAME_ENCAPSULATION_TYPE: %d", valPtr->frameTunnelMode); CWParseMessageElementEnd(); } CWBool CWParseWTPIPv4Address(CWProtocolMessage * msgPtr, int len, CWProtocolJoinRequestValues * valPtr) { CWParseMessageElementStart(); valPtr->addr.sin_addr.s_addr = htonl(CWProtocolRetrieve32(msgPtr)); valPtr->addr.sin_family = AF_INET; valPtr->addr.sin_port = htons(CW_CONTROL_PORT); // CWDebugLog("WTP Address: %s", sock_ntop((struct sockaddr*) (&(valPtr->addr)), sizeof(valPtr->addr))); CWParseMessageElementEnd(); } CWBool CWParseWTPMACType(CWProtocolMessage * msgPtr, int len, CWMACType * valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieve8(msgPtr); // CWDebugLog("CW_MSG_ELEMENT_WTP_MAC_TYPE: %d", valPtr->MACType); CWParseMessageElementEnd(); } CWBool CWParseWTPRadioInformation(CWProtocolMessage * msgPtr, int len, unsigned char *valPtr) { CWParseMessageElementStart(); CWProtocolRetrieve8(msgPtr); // Radio ID CWProtocolRetrieve8(msgPtr); // Res CWProtocolRetrieve8(msgPtr); // Res CWProtocolRetrieve8(msgPtr); // Res *valPtr = CWProtocolRetrieve8(msgPtr); // Radio Information CWParseMessageElementEnd(); } CWBool CWParseWTPSupportedRates(CWProtocolMessage * msgPtr, int len, unsigned char *valPtr) { CWParseMessageElementStart(); unsigned char sup_rates[8]; CWProtocolRetrieve8(msgPtr); sup_rates[0] = CWProtocolRetrieve8(msgPtr); sup_rates[1] = CWProtocolRetrieve8(msgPtr); sup_rates[2] = CWProtocolRetrieve8(msgPtr); sup_rates[3] = CWProtocolRetrieve8(msgPtr); sup_rates[4] = CWProtocolRetrieve8(msgPtr); sup_rates[5] = CWProtocolRetrieve8(msgPtr); sup_rates[6] = CWProtocolRetrieve8(msgPtr); sup_rates[7] = CWProtocolRetrieve8(msgPtr); memcpy(valPtr, sup_rates, 8); CWParseMessageElementEnd(); } CWBool CWParseWTPMultiDomainCapability(CWProtocolMessage * msgPtr, int len, char *valPtr) { CWParseMessageElementStart(); unsigned char sup_cap[6]; CWProtocolRetrieve8(msgPtr); CWProtocolRetrieve8(msgPtr); sup_cap[0] = CWProtocolRetrieve8(msgPtr); sup_cap[1] = CWProtocolRetrieve8(msgPtr); sup_cap[2] = CWProtocolRetrieve8(msgPtr); sup_cap[3] = CWProtocolRetrieve8(msgPtr); sup_cap[4] = CWProtocolRetrieve8(msgPtr); sup_cap[5] = CWProtocolRetrieve8(msgPtr); memcpy(valPtr, sup_cap, 6); CWParseMessageElementEnd(); } CWBool CWParseWTPName(CWProtocolMessage * msgPtr, int len, char **valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieveStr(msgPtr, len); if (valPtr == NULL) return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); // CWDebugLog("WTP Name:%s", *valPtr); CWParseMessageElementEnd(); } CWBool CWParseWTPRebootStatistics(CWProtocolMessage * msgPtr, int len, WTPRebootStatisticsInfo * valPtr) { CWParseMessageElementStart(); valPtr->rebootCount = CWProtocolRetrieve16(msgPtr); valPtr->ACInitiatedCount = CWProtocolRetrieve16(msgPtr); valPtr->linkFailurerCount = CWProtocolRetrieve16(msgPtr); valPtr->SWFailureCount = CWProtocolRetrieve16(msgPtr); valPtr->HWFailuireCount = CWProtocolRetrieve16(msgPtr); valPtr->otherFailureCount = CWProtocolRetrieve16(msgPtr); valPtr->unknownFailureCount = CWProtocolRetrieve16(msgPtr); valPtr->lastFailureType = CWProtocolRetrieve8(msgPtr); // CWDebugLog(""); // CWDebugLog("WTPRebootStat(1): %d - %d - %d", valPtr->rebootCount, valPtr->ACInitiatedCount, valPtr->linkFailurerCount); // CWDebugLog("WTPRebootStat(2): %d - %d - %d", valPtr->SWFailureCount, valPtr->HWFailuireCount, valPtr->otherFailureCount); // CWDebugLog("WTPRebootStat(3): %d - %d", valPtr->unknownFailureCount, valPtr->lastFailureType); CWParseMessageElementEnd(); } CWBool CWParseWTPRadioStatistics(CWProtocolMessage * msgPtr, int len, WTPRadioStatisticsValues * valPtr) { CWParseMessageElementStart(); valPtr->radioID = CWProtocolRetrieve8(msgPtr); valPtr->WTPRadioStatistics.lastFailureType = CWProtocolRetrieve8(msgPtr); valPtr->WTPRadioStatistics.resetCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.SWFailureCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.HWFailuireCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.otherFailureCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.unknownFailureCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.configUpdateCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.channelChangeCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.bandChangeCount = CWProtocolRetrieve16(msgPtr); valPtr->WTPRadioStatistics.currentNoiseFloor = CWProtocolRetrieve16(msgPtr); // CWDebugLog(""); // CWDebugLog("WTPRadioStatistics of radio: \"%d\"", valPtr->radioID); // CWDebugLog("WTPRadioStatistics(1): %d - %d - %d", valPtr->WTPRadioStatistics.lastFailureType, valPtr->WTPRadioStatistics.resetCount, valPtr->WTPRadioStatistics.SWFailureCount); // CWDebugLog("WTPRadioStatistics(2): %d - %d - %d", valPtr->WTPRadioStatistics.HWFailuireCount, valPtr->WTPRadioStatistics.otherFailureCount, valPtr->WTPRadioStatistics.unknownFailureCount); // CWDebugLog("WTPRadioStatistics(3): %d - %d - %d - %d", valPtr->WTPRadioStatistics.configUpdateCount, valPtr->WTPRadioStatistics.channelChangeCount, valPtr->WTPRadioStatistics.bandChangeCount, valPtr->WTPRadioStatistics.currentNoiseFloor); CWParseMessageElementEnd(); } CWBool CWParseWTPOperationalStatistics(CWProtocolMessage * msgPtr, int len, WTPOperationalStatisticsValues * valPtr) { CWParseMessageElementStart(); valPtr->radioID = CWProtocolRetrieve8(msgPtr); valPtr->TxQueueLevel = CWProtocolRetrieve8(msgPtr); valPtr->wirelessLinkFramesPerSec = CWProtocolRetrieve16(msgPtr); // CWDebugLog("WTPOperationalStatistics of radio \"%d\": %d - %d", valPtr->radioID, valPtr->TxQueueLevel, valPtr->wirelessLinkFramesPerSec); CWParseMessageElementEnd(); } CWBool CWParseMsgElemDecryptErrorReport(CWProtocolMessage * msgPtr, int len, CWDecryptErrorReportValues * valPtr) { CWParseMessageElementStart(); valPtr->ID = CWProtocolRetrieve8(msgPtr); valPtr->numEntries = CWProtocolRetrieve8(msgPtr); valPtr->length = CWProtocolRetrieve8(msgPtr); valPtr->decryptErrorMACAddressList = NULL; if ((valPtr->numEntries) > 0) { CW_CREATE_ARRAY_ERR(valPtr->decryptErrorMACAddressList, valPtr->numEntries, CWMACAddress, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); int size = sizeof(CWMACAddress) * (valPtr->numEntries); CW_COPY_MEMORY(valPtr->decryptErrorMACAddressList, CWProtocolRetrieveRawBytes(msgPtr, size), size); //valPtr->decryptErrorMACAddressList =(unsigned char*) CWProtocolRetrieveRawBytes(msgPtr, sizeof(CWMACAddress)*(valPtr->numEntries)); //CW_COPY_MEMORY(&((valPtr->ACIPv6List)[i]), CWProtocolRetrieveRawBytes(msgPtr, 16), 16); /* int j; for (j=0;j<(sizeof(CWMACAddress)*(valPtr->numEntries)); j++) CWDebugLog("##(%d/6) = %d", j%6, (valPtr->decryptErrorMACAddressList)[j/6][j%6]); */ } // CWDebugLog(""); // CWDebugLog("Radio Decrypt Error Report of radio \"%d\": %d", valPtr->ID, valPtr->numEntries); CWParseMessageElementEnd(); } /* CWBool CWParseWTPRadioInfo(CWPrradios)[radioIndex].ID = CWProtocolRetrieve8(msgPtr); (valPtr->radios)[radioIndex].type = CWProtocolRetrieve32(msgPtr); CWDebugLog("WTP Radio info: %d %d ", (valPtr->radios)[radioIndex].ID, (valPtr->radios)[radioIndex].type); CWParseMessageElementEnd(); } */ ================================================ FILE: ACProtocol.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_ACProtocol_HEADER__ #define __CAPWAP_ACProtocol_HEADER__ //#define UNUSED_RADIO_ID 1000 typedef struct { char *locationData; char *name; unsigned char *sessionID; CWWTPDescriptor descriptor; struct sockaddr_in ipv4Address; CWWTPRadiosInfo radiosInfo; char *ACName; CWACNamesWithIndex ACNameIndex; CWRadiosAdminInfo radioAdminInfo; int StatisticsTimer; CWWTPVendorInfos WTPBoardData; //CWRadiosInformation WTPRadioInfo; WTPRebootStatisticsInfo *WTPRebootStatistics; void *bindingValuesPtr; } CWWTPProtocolManager; typedef struct { char *location; char *name; CWWTPVendorInfos WTPBoardData; unsigned char *sessionID; CWWTPDescriptor WTPDescriptor; struct sockaddr_in addr; CWframeTunnelMode frameTunnelMode; CWMACType MACType; } CWProtocolJoinRequestValues; typedef struct { char *ACName; CWACNamesWithIndex ACinWTP; int radioAdminInfoCount; CWRadioAdminInfoValues *radioAdminInfo; int StatisticsTimer; WTPRebootStatisticsInfo *WTPRebootStatistics; } CWProtocolConfigureRequestValues; typedef struct { CWRadiosOperationalInfo radioOperationalInfo; CWProtocolResultCode resultCode; } CWProtocolChangeStateEventRequestValues; typedef struct { unsigned int radioID; unsigned int TxQueueLevel; unsigned int wirelessLinkFramesPerSec; } WTPOperationalStatisticsValues; typedef struct { unsigned int radioID; WTPRadioStatisticsInfo WTPRadioStatistics; } WTPRadioStatisticsValues; typedef struct { int ipv4Address; unsigned int length; unsigned char *MACoffendingDevice_forIpv4; int status; } WTPDuplicateIPv4; typedef struct { struct in6_addr ipv6Address; unsigned int length; unsigned char *MACoffendingDevice_forIpv6; int status; } WTPDuplicateIPv6; typedef struct { int errorReportCount; CWDecryptErrorReportValues *errorReport; WTPDuplicateIPv4 *duplicateIPv4; WTPDuplicateIPv6 *duplicateIPv6; int WTPOperationalStatisticsCount; WTPOperationalStatisticsValues *WTPOperationalStatistics; int WTPRadioStatisticsCount; WTPRadioStatisticsValues *WTPRadioStatistics; WTPRebootStatisticsInfo *WTPRebootStatistics; } CWProtocolWTPEventRequestValues; typedef struct { int data; int length; char *debug_info; } CWProtocolWTPDataTransferRequestValues; /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ CWBool CWParseChangeStateEventRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWProtocolChangeStateEventRequestValues * valuesPtr); CWBool CWAssembleChangeStateEventResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum); CWBool CWAssembleMsgElemACDescriptor(CWProtocolMessage * msgPtr); // 1 CWBool CWAssembleMsgElemACIPv4List(CWProtocolMessage * msgPtr); // 2 CWBool CWAssembleMsgElemACIPv6List(CWProtocolMessage * msgPtr); // 3 CWBool CWAssembleMsgElemACName(CWProtocolMessage * msgPtr); // 4 CWBool CWAssembleMsgElemAddStation(int radioID, CWProtocolMessage * msgPtr, unsigned char *StationMacAddr); // 8 CWBool CWAssembleMsgElemDeleteStation(int radioID, CWProtocolMessage * msgPtr, unsigned char *StationMacAddr); // 8 CWBool CWAssembleMsgElemCWControlIPv4Addresses(CWProtocolMessage * msgPtr); //10 CWBool CWAssembleMsgElemCWControlIPv6Addresses(CWProtocolMessage * msgPtr); //11 CWBool CWAssembleMsgElemCWTimer(CWProtocolMessage * msgPtr); //12 CWBool CWAssembleMsgElemDecryptErrorReportPeriod(CWProtocolMessage * msgPtr); //16 CWBool CWAssembleMsgElemIdleTimeout(CWProtocolMessage * msgPtr); //23 CWBool CWAssembleMsgElemWTPFallback(CWProtocolMessage * msgPtr); //37 CWBool CWAssembleWLANConfigurationRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, unsigned char *recv_packet, int Operation, int len_packet); CWBool CWAssembleMsgElemACWTPRadioInformation(CWProtocolMessage * msgPtr); CWBool CWAssembleMsgElemAddWLAN(int radioID, CWProtocolMessage * msgPtr, unsigned char *recv_packet, int len_packet); CWBool CWAssembleMsgElemDeleteWLAN(int radioID, CWProtocolMessage * msgPtr, unsigned char *recv_packet, int len_packet); //---------------------------------------------------------/ //CWBool CWParseACName(CWProtocolMessage *msgPtr, int len, char **valPtr); CWBool CWParseACNameWithIndex(CWProtocolMessage * msgPtr, int len, CWACNameWithIndexValues * valPtr); // 5 CWBool CWParseMsgElemDataTransferData(CWProtocolMessage * msgPtr, int len, CWProtocolWTPDataTransferRequestValues * valPtr); //13 CWBool CWParseDiscoveryType(CWProtocolMessage * msgPtr, int len, CWDiscoveryRequestValues * valPtr); //20 CWBool CWParseMsgElemDuplicateIPv4Address(CWProtocolMessage * msgPtr, int len, WTPDuplicateIPv4 * valPtr); //21 CWBool CWParseLocationData(CWProtocolMessage * msgPtr, int len, char **valPtr); //27 CWBool CWParseWTPRadioAdminState(CWProtocolMessage * msgPtr, int len, CWRadioAdminInfoValues * valPtr); //29 CWBool CWParseWTPStatisticsTimer(CWProtocolMessage * msgPtr, int len, int *valPtr); //33 CWBool CWParseWTPBoardData(CWProtocolMessage * msgPtr, int len, CWWTPVendorInfos * valPtr); //35 CWBool CWParseWTPDescriptor(CWProtocolMessage * msgPtr, int len, CWWTPDescriptor * valPtr); //37 CWBool CWParseWTPFrameTunnelMode(CWProtocolMessage * msgPtr, int len, CWframeTunnelMode * valPtr); //38 CWBool CWParseWTPIPv4Address(CWProtocolMessage * msgPtr, int len, CWProtocolJoinRequestValues * valPtr); //39 CWBool CWParseWTPMACType(CWProtocolMessage * msgPtr, int len, CWMACType * valPtr); //40 CWBool CWParseWTPName(CWProtocolMessage * msgPtr, int len, char **valPtr); //41 CWBool CWParseWTPOperationalStatistics(CWProtocolMessage * msgPtr, int len, WTPOperationalStatisticsValues * valPtr); //42 CWBool CWParseWTPRadioStatistics(CWProtocolMessage * msgPtr, int len, WTPRadioStatisticsValues * valPtr); //43 CWBool CWParseWTPRebootStatistics(CWProtocolMessage * msgPtr, int len, WTPRebootStatisticsInfo * valPtr); //44 CWBool CWParseMsgElemDecryptErrorReport(CWProtocolMessage * msgPtr, int len, CWDecryptErrorReportValues * valPtr); CWBool CWParseMsgElemDuplicateIPv6Address(CWProtocolMessage * msgPtr, int len, WTPDuplicateIPv6 * valPtr); CWBool CWParseWTPRadioInformation(CWProtocolMessage * msgPtr, int len, unsigned char *valPtr); //1048 CWBool CWParseWTPSupportedRates(CWProtocolMessage * msgPtr, int len, unsigned char *valPtr); //1040 CWBool CWParseWTPMultiDomainCapability(CWProtocolMessage * msgPtr, int len, char *valPtr); //1032 //CWBool CWParseWTPRadioInfo(CWProtocolMessage *msgPtr, int len, CWRadiosInformation *valPtr, int radioIndex); //---------------------------------------------------------/ CWBool CWACGetACIPv4List(int **listPtr, int *countPtr); CWBool CWACGetACIPv6List(struct in6_addr **listPtr, int *countPtr); char *CWACGetName(void); int CWACGetHWVersion(void); int CWACGetSWVersion(void); int CWACGetStations(void); int CWACGetLimit(void); int CWACGetActiveWTPs(void); int CWACGetMaxWTPs(void); int CWACGetSecurity(void); int CWACGetInterfacesCount(void); int CWACGetInterfaceIPv4AddressAtIndex(int i); unsigned char *CWACGetInterfaceIPv6AddressAtIndex(int i); int CWACGetInterfaceWTPCountAtIndex(int i); CWBool CWACGetDiscoveryTimer(int *timer); CWBool CWACGetEchoRequestTimer(int *timer); CWBool CWACGetIdleTimeout(int *timer); CWBool CWGetWTPRadiosOperationalState(int radioID, CWRadiosOperationalInfo * valPtr); //---------------------------------------------------------/ CWBool CWACSupportIPv6(); void CWDestroyDiscoveryRequestValues(CWDiscoveryRequestValues * valPtr); CWBool CWProtocolAssembleConfigurationUpdateRequest(CWProtocolMessage ** msgElems, int *msgElemCountPtr, int MsgElementType); #endif ================================================ FILE: ACProtocol_User.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif __inline__ CWBool CWACSupportIPv6() { return (gNetworkPreferredFamily == CW_IPv6); } __inline__ char *CWACGetName() { return gACName; } __inline__ int CWACGetStations() { return gActiveStations; } __inline__ int CWACGetLimit() { return gLimit; } __inline__ int CWACGetActiveWTPs() { int tmp; if (!CWErr(CWThreadMutexLock(&gActiveWTPsMutex))) return 0; tmp = gActiveWTPs; CWThreadMutexUnlock(&gActiveWTPsMutex); return tmp; } __inline__ int CWACGetMaxWTPs() { return gMaxWTPs; } __inline__ int CWACGetSecurity() { return gACDescriptorSecurity; } __inline__ int CWACGetRMACField() { return gRMACField; } __inline__ int CWACGetWirelessField() { return gWirelessField; } __inline__ int CWACGetDTLSPolicy() { return gDTLSPolicy; } __inline__ int CWACGetHWVersion() { return gACHWVersion; } __inline__ int CWACGetSWVersion() { return gACSWVersion; } __inline__ int CWACGetInterfacesCount() { return gInterfacesCount; } __inline__ int CWACGetInterfaceIPv4AddressAtIndex(int i) { struct sockaddr_in *addrPtr; if (gNetworkPreferredFamily == CW_IPv4) { addrPtr = (struct sockaddr_in *)&(gInterfaces[i].addr); } else { addrPtr = (struct sockaddr_in *)&(gInterfaces[i].addrIPv4); } return ntohl(addrPtr->sin_addr.s_addr); } __inline__ unsigned char *CWACGetInterfaceIPv6AddressAtIndex(int i) { struct sockaddr_in6 *addrPtr; addrPtr = (struct sockaddr_in6 *)&(gInterfaces[i].addr); return addrPtr->sin6_addr.s6_addr; } __inline__ int CWACGetInterfaceWTPCountAtIndex(int i) { return gInterfaces[i].WTPCount; } CWBool CWACGetVendorInfos(CWACVendorInfos * valPtr) { if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); valPtr->vendorInfosCount = 2; CW_CREATE_ARRAY_ERR((valPtr->vendorInfos), valPtr->vendorInfosCount, CWACVendorInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") (valPtr->vendorInfos)[0].vendorIdentifier = 65432; (valPtr->vendorInfos)[0].type = CW_AC_HARDWARE_VERSION; (valPtr->vendorInfos)[0].length = 4; // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[0]).valuePtr), 4, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(((valPtr->vendorInfos)[0]).valuePtr) = CWACGetHWVersion(); // HW version // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") ((valPtr->vendorInfos)[1]).vendorIdentifier = 65432; ((valPtr->vendorInfos)[1]).type = CW_AC_SOFTWARE_VERSION; ((valPtr->vendorInfos)[1]).length = 4; // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[1]).valuePtr), 4, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(((valPtr->vendorInfos)[1]).valuePtr) = CWACGetSWVersion(); // SW version return CW_TRUE; } __inline__ void CWACDestroyVendorInfos(CWACVendorInfos * valPtr) { int i; if (valPtr == NULL) return; for (i = 0; i < valPtr->vendorInfosCount; i++) { CW_FREE_OBJECT((valPtr->vendorInfos)[i].valuePtr); } CW_FREE_OBJECT(valPtr->vendorInfos); } CWBool CWACGetACIPv4List(int **listPtr, int *countPtr) { struct in_addr addr; // TO-DO this func should return the addresses of eventual other ACs in a cluster. Hey, what? What is the WTP // supposed to do with that? if (listPtr == NULL || countPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); *countPtr = 2; CW_CREATE_ARRAY_ERR((*listPtr), (*countPtr), int, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); inet_pton(AF_INET, "192.168.1.2", &addr); // TO-DO take the addresses from config file? (*listPtr)[0] = addr.s_addr; inet_pton(AF_INET, "192.168.1.66", &addr); (*listPtr)[1] = addr.s_addr; return CW_TRUE; } CWBool CWACGetACIPv6List(struct in6_addr ** listPtr, int *countPtr) { // TO-DO this func should return the addresses of eventual other ACs in a cluster. Hey, what? What is the WTP // supposed to do with that? if (listPtr == NULL || countPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); *countPtr = 2; CW_CREATE_ARRAY_ERR(*listPtr, (*countPtr), struct in6_addr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); inet_pton(AF_INET6, "5f1b:df00:ce3e:e200:0020:0800:2078:e3e3", &((*listPtr)[0])); // TO-DO take the addresses from config file? inet_pton(AF_INET6, "5f1b:df00:ce3e:e200:0020:0800:2078:e3e4", &((*listPtr)[1])); return CW_TRUE; } CWBool CWACGetDiscoveryTimer(int *timer) { *timer = gDiscoveryTimer; return CW_TRUE; } CWBool CWACGetEchoRequestTimer(int *timer) { *timer = gEchoRequestTimer; return CW_TRUE; } CWBool CWACGetIdleTimeout(int *timer) { *timer = gIdleTimeout; return CW_TRUE; } /* Il WTP ha la funzione ridefinita */ CWBool CWGetWTPRadiosAdminState(CWRadiosAdminInfo * valPtr) { int *WTPIndexPtr; if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((WTPIndexPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } valPtr->radiosCount = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radioCount; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioAdminInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); int i; for (i = 0; i < valPtr->radiosCount; i++) { (valPtr->radios)[i].ID = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].radioID; (valPtr->radios)[i].state = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].adminState; (valPtr->radios)[i].cause = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].adminCause; } return CW_TRUE; } CWBool CWGetWTPRadiosOperationalState(int radioID, CWRadiosOperationalInfo * valPtr) { int i; CWBool found = CW_FALSE; int *WTPIndexPtr; if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((WTPIndexPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } if (radioID < 0) { valPtr->radiosCount = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radioCount; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < valPtr->radiosCount; i++) { (valPtr->radios)[i].ID = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].radioID; (valPtr->radios)[i].state = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].operationalState; (valPtr->radios)[i].cause = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].operationalCause; } return CW_TRUE; } else { for (i = 0; i < valPtr->radiosCount; i++) { if (gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].radioID == radioID) { found = CW_TRUE; valPtr->radiosCount = 1; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (valPtr->radios)[i].ID = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].radioID; (valPtr->radios)[i].state = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].operationalState; (valPtr->radios)[i].cause = gWTPs[*WTPIndexPtr].WTPProtocolManager.radiosInfo.radiosInfo[i].operationalCause; break; } } return found; } } ================================================ FILE: ACRetransmission.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWAC.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /* * CW_FREE_WTP_MSG_ARRAY - free the array of the messages * to be sent relative to the WTP with the specified index. * * ref -> BUG ML12 * 20/10/2009 - Donato Capitella */ static void inline CW_FREE_WTP_MSG_ARRAY(int WTPIndex) { int i; for (i = 0; i < gWTPs[WTPIndex].messagesCount; i++) { CW_FREE_OBJECT(gWTPs[WTPIndex].messages[i].msg); } CW_FREE_OBJECT(gWTPs[WTPIndex].messages); gWTPs[WTPIndex].messagesCount = 0; } CWBool CWACSendFragments(int WTPIndex) { int i; if (gWTPs[WTPIndex].messages == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); for (i = 0; i < gWTPs[WTPIndex].messagesCount; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeUnconnected(gWTPs[WTPIndex].socket, &gWTPs[WTPIndex].address, gWTPs[WTPIndex].messages[i].msg, gWTPs[WTPIndex].messages[i].offset)) { #else if (! (CWSecuritySend (gWTPs[WTPIndex].session, gWTPs[WTPIndex].messages[i].msg, gWTPs[WTPIndex].messages[i].offset))) { #endif return CW_FALSE; } } /* * BUG - ML12 * * 20/10/2009 - Donato Capitella */ CW_FREE_WTP_MSG_ARRAY(WTPIndex); CWLog("Message Sent\n"); return CW_TRUE; } CWBool CWACResendAcknowledgedPacket(int WTPIndex) { if (!CWACSendFragments(WTPIndex)) return CW_FALSE; CWThreadSetSignals(SIG_BLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); if (! (CWTimerRequest (gCWRetransmitTimer, &(gWTPs[WTPIndex].thread), &(gWTPs[WTPIndex].currentPacketTimer), CW_SOFT_TIMER_EXPIRED_SIGNAL))) { return CW_FALSE; } CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); return CW_TRUE; } __inline__ CWBool CWACSendAcknowledgedPacket(int WTPIndex, int msgType, int seqNum) { gWTPs[WTPIndex].retransmissionCount = 0; gWTPs[WTPIndex].isRetransmitting = CW_TRUE; gWTPs[WTPIndex].responseType = msgType; gWTPs[WTPIndex].responseSeqNum = seqNum; // CWDebugLog("~~~~~~seq num in Send: %d~~~~~~", gWTPs[WTPIndex].responseSeqNum); return CWACResendAcknowledgedPacket(WTPIndex); } void CWACStopRetransmission(int WTPIndex) { if (gWTPs[WTPIndex].isRetransmitting) { int i; CWDebugLog("Stop Retransmission"); gWTPs[WTPIndex].isRetransmitting = CW_FALSE; CWThreadSetSignals(SIG_BLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); if (!CWTimerCancel(&(gWTPs[WTPIndex].currentPacketTimer))) { CWDebugLog("Error Cancelling a Timer... possible error!"); } CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); gWTPs[WTPIndex].responseType = UNUSED_MSG_TYPE; gWTPs[WTPIndex].responseSeqNum = 0; for (i = 0; i < gWTPs[WTPIndex].messagesCount; i++) { CW_FREE_PROTOCOL_MESSAGE(gWTPs[WTPIndex].messages[i]); } CW_FREE_OBJECT(gWTPs[WTPIndex].messages); // CWDebugLog("~~~~~~ End of Stop Retransmission"); } } ================================================ FILE: ACRunState.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include "CWAC.h" #include "ACipcHostapd.h" #include "CWVendorPayloads.h" #include "CWFreqPayloads.h" #include "WUM.h" #include "common.h" #include "ieee802_11_defs.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWACParseGenericRunMessage(int WTPIndex, CWProtocolMessage * msg, CWControlHeaderValues * controlVal); CWBool CWParseConfigurationUpdateResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode, CWProtocolVendorSpecificValues ** protocolValues); CWBool CWSaveConfigurationUpdateResponseMessage(CWProtocolResultCode resultCode, int WTPIndex, CWProtocolVendorSpecificValues * protocolValues); CWBool CWParseClearConfigurationResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode); CWBool CWParseWLANConfigurationResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode); CWBool CWParseStationConfigurationResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode); CWBool CWParseWTPDataTransferRequestMessage(CWProtocolMessage * msgPtr, int len, CWProtocolWTPDataTransferRequestValues * valuesPtr); CWBool CWAssembleWTPDataTransferResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum); CWBool CWParseWTPEventRequestMessage(CWProtocolMessage * msgPtr, int len, CWProtocolWTPEventRequestValues * valuesPtr); CWBool CWSaveWTPEventRequestMessage(CWProtocolWTPEventRequestValues * WTPEventRequest, CWWTPProtocolManager * WTPProtocolManager); CWBool CWAssembleWTPEventResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum); CWBool CWParseChangeStateEventRequestMessage2(CWProtocolMessage * msgPtr, int len, CWProtocolChangeStateEventRequestValues ** valuesPtr); CWBool CWParseEchoRequestMessage(CWProtocolMessage * msgPtr, int len); CWBool CWAssembleEchoResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum); CWBool CWStartNeighborDeadTimer(int WTPIndex); CWBool CWStopNeighborDeadTimer(int WTPIndex); CWBool CWRestartNeighborDeadTimer(int WTPIndex); CWBool CWRestartNeighborDeadTimerForEcho(int WTPIndex); int flush_pcap(u_char * buf, int len, char *filename) { FILE *file; file = fopen(filename, "a+"); u_char index = 0x00; int cnt = 0; int i; int giro = 0; for (i = 0; cnt < len; i++) { fprintf(file, "0%02X0 ", index); for (; cnt < len;) { fprintf(file, "%02X ", buf[cnt]); cnt++; if (giro == 15) { giro = 0; break; } giro++; } fprintf(file, "\n"); index++; } fprintf(file, "\n"); fclose(file); return 0; } #define HLEN_80211 24 int isEAPOL_Frame(unsigned char *buf, int len) { unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; int i; for (i = 0; i < 6; i++) if (rfc1042_header[i] != buf[i + HLEN_80211]) return 0; return 1; } CWBool ACEnterRun(int WTPIndex, CWProtocolMessage * msgPtr, CWBool dataFlag) { CWBool toSend = CW_FALSE, timerSet = CW_TRUE; CWControlHeaderValues controlVal; CWProtocolMessage *messages = NULL; int messagesCount = 0; unsigned char StationMacAddr[MAC_ADDR_LEN]; char string[10]; char socketctl_path_name[50]; char socketserv_path_name[50]; int msglen = msgPtr->offset; msgPtr->offset = 0; if (dataFlag) { /* We have received a Data Message... now just log this event and do actions by the dataType */ CWDebugLog("--> Received a DATA Message"); if (msgPtr->data_msgType == CW_DATA_MSG_FRAME_TYPE) { /*Retrive mac address station from msg */ memset(StationMacAddr, 0, MAC_ADDR_LEN); memcpy(StationMacAddr, msgPtr->msg + SOURCE_ADDR_START, MAC_ADDR_LEN); int seqNum = CWGetSeqNum(); //Send a Station Configuration Request if (CWAssembleStationConfigurationRequest(&(gWTPs[WTPIndex].messages), &(gWTPs[WTPIndex].messagesCount), gWTPs[WTPIndex].pathMTU, seqNum, StationMacAddr, CW_MSG_ELEMENT_ADD_STATION_CW_TYPE)) { if (CWACSendAcknowledgedPacket(WTPIndex, CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE, seqNum)) return CW_TRUE; else CWACStopRetransmission(WTPIndex); } CWDebugLog("Send a Station Configuration Request"); } else if (msgPtr->data_msgType == CW_DATA_MSG_KEEP_ALIVE_TYPE) { unsigned char *valPtr = NULL; CWProtocolMessage *messages = NULL; CWProtocolMessage sessionIDmsgElem; int fragmentsNum = 0; int i; int dataSocket = 0; unsigned short int elemType = 0; unsigned short int elemLen = 0; CWNetworkLev4Address address; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); valPtr = CWParseSessionID(msgPtr, elemLen); CWAssembleMsgElemSessionID(&sessionIDmsgElem, valPtr); if (!CWAssembleDataMessage(&messages, &fragmentsNum, gWTPs[WTPIndex].pathMTU, &sessionIDmsgElem, NULL, CW_PACKET_PLAIN, 1)) { CWLog("Failure Assembling KeepAlive Request"); if (messages) for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); return CW_FALSE; } for (i = 0; i < gACSocket.count; i++) { if (gACSocket.interfaces[i].sock == gWTPs[WTPIndex].socket) { dataSocket = gACSocket.interfaces[i].dataSock; CW_COPY_NET_ADDR_PTR(&address, &(gWTPs[WTPIndex].dataAddress)); break; } } if (dataSocket == 0) { CWLog("data socket of WTP %d isn't ready."); return CW_FALSE; } /* Set port and address of data tunnel */ //sock_set_port_cw((struct sockaddr *)&(address), htons(CW_DATA_PORT)); for (i = 0; i < fragmentsNum; i++) { if (!CWNetworkSendUnsafeUnconnected(dataSocket, &(address), messages[i].msg, messages[i].offset)) { CWLog("Failure sending KeepAlive Request"); int k; for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); break; } } int k; for (k = 0; messages && k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); } else if (msgPtr->data_msgType == CW_IEEE_802_3_FRAME_TYPE) { CWDebugLog("Write 802.3 data to TAP[%d], len:%d", gWTPs[WTPIndex].tap_fd, msglen); write(gWTPs[WTPIndex].tap_fd, msgPtr->msg, msglen); } else if (msgPtr->data_msgType == CW_IEEE_802_11_FRAME_TYPE) { struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *)msgPtr->msg; fc = le_to_host16(hdr->frame_control); CWDebugLog("Received 802.11 Frame type: %d", WLAN_FC_GET_TYPE(fc)); CWDebugLog("Received 802.11 Frame sybtype: %d", WLAN_FC_GET_STYPE(fc)); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT || isEAPOL_Frame(msgPtr->msg, msglen)) { CWACsend_data_to_hostapd(WTPIndex, msgPtr->msg, msglen); } else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_NULLFUNC || WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH || WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ASSOC_REQ) { CWACsend_data_to_hostapd(WTPIndex, msgPtr->msg, msglen); } else { CWDebugLog("Sending 802.11 frame subtype %d to TAP[%d]", WLAN_FC_GET_STYPE(fc), gWTPs[WTPIndex].tap_fd); int write_bytes = write(gWTPs[WTPIndex].tap_fd, msgPtr->msg + HLEN_80211, msglen - HLEN_80211); if (write_bytes != (msglen - 24)) { CWLog("%02X %02X %02X %02X %02X %02X ", msgPtr->msg[0], msgPtr->msg[1], msgPtr->msg[2], msgPtr->msg[3], msgPtr->msg[4], msgPtr->msg[5]); CWLog("Error:. RecvByte:%d, write_Byte:%d ", msglen - 24, write_bytes); } } } else { write(gWTPs[WTPIndex].tap_fd, msgPtr->msg + HLEN_80211, msglen - HLEN_80211); CWDebugLog("Control Frame !!!\n"); } //flush_pcap(msgPtr->msg, msglen, "cap_wtp_to_ac.txt"); } else { CWDebugLog("Manage special data packets with frequency"); /************************************************************ * Update 2009: * * Manage special data packets with frequency * * statistics informations. * ************************************************************/ if (msgPtr->data_msgType == CW_DATA_MSG_FREQ_STATS_TYPE) { int cells; /* How many cell are heard */ int isAck; char *freqPayload; int socketIndex, indexToSend = htonl(WTPIndex); int sizeofAckInfoUnit = CW_FREQ_ACK_SIZE; int sizeofFreqInfoUnit = CW_FREQ_CELL_INFO_PAYLOAD_SIZE; int sizeOfPayload = 0, payload_offset = 0; /*----------------------------------------------------------------------------------------------- * Payload Management ( infos for frequency application) : * Ack Structure : | WTPIndex | Ack Value | * Freq Info Structure : | WTPIndex | Number of cells | Frequecies Info Payload | *-----------------------------------------------------------------------------------------------*/ memcpy(&isAck, msgPtr->msg, sizeof(int)); isAck = ntohl(isAck); if (isAck == 0) { /* isnt an ack message */ memcpy(&cells, msgPtr->msg + sizeof(int), sizeof(int)); cells = ntohl(cells); sizeOfPayload = (cells * sizeofFreqInfoUnit) + (2 * sizeof(int)); } else { sizeOfPayload = sizeofAckInfoUnit; } if ((freqPayload = malloc(sizeOfPayload)) != NULL) { memset(freqPayload, 0, sizeOfPayload); memcpy(freqPayload, &indexToSend, sizeof(int)); payload_offset += sizeof(int); if (isAck == 0) { memcpy(freqPayload + payload_offset, msgPtr->msg + sizeof(int), sizeOfPayload - payload_offset); } else { memcpy(freqPayload + payload_offset, msgPtr->msg + sizeof(int), sizeOfPayload - payload_offset); } socketIndex = gWTPs[WTPIndex].applicationIndex; /**************************************************** * Forward payload to correct application * ****************************************************/ if (!CWErr(CWThreadMutexLock(&appsManager.socketMutex[socketIndex]))) { CWLog("[ACrunState]:: Error locking socket Application Mutex"); free(freqPayload); return CW_FALSE; } if (Writen(appsManager.appSocket[socketIndex], freqPayload, sizeOfPayload) < 0) { CWThreadMutexUnlock(&appsManager.socketMutex[socketIndex]); free(freqPayload); CWLog("[ACrunState]:: Error writing Message To Application"); return CW_FALSE; } CWThreadMutexUnlock(&appsManager.socketMutex[socketIndex]); free(freqPayload); } else CWLog("[ACrunState]:: Malloc error (payload to frequency application"); } if (msgPtr->data_msgType == CW_DATA_MSG_STATS_TYPE) { if (!UnixSocksArray[WTPIndex].data_stats_sock) { //Init Socket only the first time when the function is called if ((UnixSocksArray[WTPIndex].data_stats_sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { CWDebugLog("Error creating socket for data send"); return CW_FALSE; } memset(&(UnixSocksArray[WTPIndex].clntaddr), (int)NULL, sizeof(UnixSocksArray[WTPIndex].clntaddr)); UnixSocksArray[WTPIndex].clntaddr.sun_family = AF_UNIX; //make unix socket client path name by index i snprintf(string, sizeof(string), "%d", WTPIndex); string[sizeof(string) - 1] = 0; strcpy(socketctl_path_name, SOCKET_PATH_AC); strcat(socketctl_path_name, string); strcpy(UnixSocksArray[WTPIndex].clntaddr.sun_path, socketctl_path_name); unlink(socketctl_path_name); memset(&(UnixSocksArray[WTPIndex].servaddr), (int)NULL, sizeof(UnixSocksArray[WTPIndex].servaddr)); UnixSocksArray[WTPIndex].servaddr.sun_family = AF_UNIX; //make unix socket server path name by index i strcpy(socketserv_path_name, SOCKET_PATH_RECV_AGENT); strcat(socketserv_path_name, string); strcpy(UnixSocksArray[WTPIndex].servaddr.sun_path, socketserv_path_name); printf("\n%s\t%s", socketserv_path_name, socketctl_path_name); fflush(stdout); } int nbytes; int pDataLen = 656; //len of Monitoring Data //Send data stats from AC thread to monitor client over unix socket nbytes = sendto(UnixSocksArray[WTPIndex].data_stats_sock, msgPtr->msg, pDataLen, 0, (struct sockaddr *)&(UnixSocksArray[WTPIndex].servaddr), sizeof(UnixSocksArray[WTPIndex].servaddr)); if (nbytes < 0) { CWDebugLog("Error sending data over socket"); return CW_FALSE; } } } return CW_TRUE; } if (!(CWACParseGenericRunMessage(WTPIndex, msgPtr, &controlVal))) { /* Two possible errors: WRONG_ARG and INVALID_FORMAT * In the second case we have an unexpected response: ignore the * message and log the event. */ return CW_FALSE; } switch (controlVal.messageTypeValue) { case CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE:{ CWProtocolResultCode resultCode; /*Update 2009: Store Protocol specific response data */ CWProtocolVendorSpecificValues *protocolValues = NULL; if (! (CWParseConfigurationUpdateResponseMessage (msgPtr, controlVal.msgElemsLen, &resultCode, &protocolValues))) return CW_FALSE; CWACStopRetransmission(WTPIndex); if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } CWSaveConfigurationUpdateResponseMessage(resultCode, WTPIndex, protocolValues); if (gWTPs[WTPIndex].interfaceCommandProgress == CW_TRUE) { CWThreadMutexLock(&gWTPs[WTPIndex].interfaceMutex); gWTPs[WTPIndex].interfaceResult = 1; gWTPs[WTPIndex].interfaceCommandProgress = CW_FALSE; CWSignalThreadCondition(&gWTPs[WTPIndex].interfaceComplete); CWThreadMutexUnlock(&gWTPs[WTPIndex].interfaceMutex); } break; } case CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_REQUEST:{ CWProtocolChangeStateEventRequestValues *valuesPtr; if (!(CWParseChangeStateEventRequestMessage2(msgPtr, controlVal.msgElemsLen, &valuesPtr))) return CW_FALSE; if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } if (!(CWSaveChangeStateEventRequestMessage(valuesPtr, &(gWTPs[WTPIndex].WTPProtocolManager)))) return CW_FALSE; if (!(CWAssembleChangeStateEventResponse(&messages, &messagesCount, gWTPs[WTPIndex].pathMTU, controlVal.seqNum))) return CW_FALSE; toSend = CW_TRUE; break; } case CW_MSG_TYPE_VALUE_ECHO_REQUEST:{ if (!(CWParseEchoRequestMessage(msgPtr, controlVal.msgElemsLen))) return CW_FALSE; if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } if (!(CWAssembleEchoResponse(&messages, &messagesCount, gWTPs[WTPIndex].pathMTU, controlVal.seqNum))) return CW_FALSE; toSend = CW_TRUE; break; } case CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE:{ CWProtocolResultCode resultCode; if (!(CWParseStationConfigurationResponseMessage(msgPtr, controlVal.msgElemsLen, &resultCode))) return CW_FALSE; CWACStopRetransmission(WTPIndex); if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } //CWSaveStationConfigurationResponseMessage(resultCode, WTPIndex); <-- Must be Implemented ???? break; } case CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_RESPONSE:{ CWProtocolResultCode resultCode; if (!(CWParseClearConfigurationResponseMessage(msgPtr, controlVal.msgElemsLen, &resultCode))) return CW_FALSE; CWACStopRetransmission(WTPIndex); if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } if (gWTPs[WTPIndex].interfaceCommandProgress == CW_TRUE) { CWThreadMutexLock(&gWTPs[WTPIndex].interfaceMutex); gWTPs[WTPIndex].interfaceResult = 1; gWTPs[WTPIndex].interfaceCommandProgress = CW_FALSE; CWSignalThreadCondition(&gWTPs[WTPIndex].interfaceComplete); CWThreadMutexUnlock(&gWTPs[WTPIndex].interfaceMutex); } break; } case CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_RESPONSE:{ CWProtocolResultCode resultCode; if (!(CWParseWLANConfigurationResponseMessage(msgPtr, controlVal.msgElemsLen, &resultCode))) return CW_FALSE; CWACStopRetransmission(WTPIndex); if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } if (gWTPs[WTPIndex].interfaceCommandProgress == CW_TRUE) { CWThreadMutexLock(&gWTPs[WTPIndex].interfaceMutex); gWTPs[WTPIndex].interfaceResult = 1; gWTPs[WTPIndex].interfaceCommandProgress = CW_FALSE; CWSignalThreadCondition(&gWTPs[WTPIndex].interfaceComplete); CWThreadMutexUnlock(&gWTPs[WTPIndex].interfaceMutex); } break; } case CW_MSG_TYPE_VALUE_DATA_TRANSFER_REQUEST:{ CWProtocolWTPDataTransferRequestValues valuesPtr; if (!(CWParseWTPDataTransferRequestMessage(msgPtr, controlVal.msgElemsLen, &valuesPtr))) return CW_FALSE; if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } if (! (CWAssembleWTPDataTransferResponse (&messages, &messagesCount, gWTPs[WTPIndex].pathMTU, controlVal.seqNum))) return CW_FALSE; toSend = CW_TRUE; break; } case CW_MSG_TYPE_VALUE_WTP_EVENT_REQUEST:{ CWProtocolWTPEventRequestValues valuesPtr; if (!(CWParseWTPEventRequestMessage(msgPtr, controlVal.msgElemsLen, &valuesPtr))) return CW_FALSE; if (timerSet) { if (!CWRestartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } else { if (!CWStartNeighborDeadTimer(WTPIndex)) { CWCloseThread(); } } if (!(CWSaveWTPEventRequestMessage(&valuesPtr, &(gWTPs[WTPIndex].WTPProtocolManager)))) return CW_FALSE; if (!(CWAssembleWTPEventResponse(&messages, &messagesCount, gWTPs[WTPIndex].pathMTU, controlVal.seqNum))) return CW_FALSE; toSend = CW_TRUE; break; } default: /* * We have an unexpected request and we have to send * a corresponding response containing a failure result code */ CWDebugLog("--> Not valid Request in Run State... we send a failure Response"); if (!(CWAssembleUnrecognizedMessageResponse(&messages, &messagesCount, gWTPs[WTPIndex].pathMTU, controlVal.seqNum, controlVal.messageTypeValue + 1))) return CW_FALSE; toSend = CW_TRUE; /*return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message not valid in Run State"); */ } if (toSend) { int i; if (messages == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); for (i = 0; i < messagesCount; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeUnconnected(gWTPs[WTPIndex].socket, &gWTPs[WTPIndex].address, messages[i].msg, messages[i].offset)) { #else if (!(CWSecuritySend(gWTPs[WTPIndex].session, messages[i].msg, messages[i].offset))) { #endif CWFreeMessageFragments(messages, messagesCount); CW_FREE_OBJECT(messages); return CW_FALSE; } } CWFreeMessageFragments(messages, messagesCount); CW_FREE_OBJECT(messages); } gWTPs[WTPIndex].currentState = CW_ENTER_RUN; gWTPs[WTPIndex].subState = CW_WAITING_REQUEST; return CW_TRUE; } CWBool CWACParseGenericRunMessage(int WTPIndex, CWProtocolMessage * msg, CWControlHeaderValues * controlVal) { if (msg == NULL || controlVal == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!(CWParseControlHeader(msg, controlVal))) /* will be handled by the caller */ return CW_FALSE; /* skip timestamp */ controlVal->msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; /* Check if it is a request */ if (controlVal->messageTypeValue % 2 == 1) { return CW_TRUE; } if ((gWTPs[WTPIndex].responseSeqNum != controlVal->seqNum) || (gWTPs[WTPIndex].responseType != controlVal->messageTypeValue)) { CWDebugLog("gWTPs: %d\n", gWTPs[WTPIndex].responseSeqNum); CWDebugLog("controlVal: %d\n", controlVal->seqNum); CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Seq Num or Msg Type not valid!"); return CW_FALSE; } return CW_TRUE; } /*Update 2009: Added vendValues to include a response payload (to pass response data)*/ CWBool CWParseConfigurationUpdateResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode, CWProtocolVendorSpecificValues ** vendValues) { int offsetTillMessages; if (msgPtr == NULL || resultCode == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); offsetTillMessages = msgPtr->offset; CWLog("Parsing Configuration Update Response..."); /* parse message elements */ while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: *resultCode = CWProtocolRetrieve32(msgPtr); break; /*Update 2009: Added case to implement conf update response with payload */ case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE_WITH_PAYLOAD:{ int payloadSize = 0; CW_CREATE_OBJECT_ERR(*vendValues, CWProtocolVendorSpecificValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *resultCode = CWProtocolRetrieve32(msgPtr); if (CWProtocolRetrieve16(msgPtr) != CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE) /*For now, we only have UCI payloads, so we will accept only vendor payloads for protocol data */ return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Configuration Update Response"); (*vendValues)->vendorPayloadType = CWProtocolRetrieve16(msgPtr); switch ((*vendValues)->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: payloadSize = CWProtocolRetrieve32(msgPtr); if (payloadSize != 0) { (*vendValues)->payload = (void *)CWProtocolRetrieveStr(msgPtr, payloadSize); } else (*vendValues)->payload = NULL; break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: payloadSize = CWProtocolRetrieve32(msgPtr); if (payloadSize <= 0) { /* Payload can't be zero here, * at least the message type must be specified */ return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Configuration Update Response"); } (*vendValues)->payload = (void *)CWProtocolRetrieveRawBytes(msgPtr, payloadSize); break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Configuration Update Response"); break; } } break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Configuration Update Response"); break; } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CWLog("Configuration Update Response Parsed"); return CW_TRUE; } CWBool CWParseWLANConfigurationResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode) { int offsetTillMessages; if (msgPtr == NULL || resultCode == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); offsetTillMessages = msgPtr->offset; CWLog("Parsing WLAN Configuration Response..."); // parse message elements while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: *resultCode = CWProtocolRetrieve32(msgPtr); break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Configuration WLAN Response"); break; } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CWLog("WLAN Configuration Response Parsed"); return CW_TRUE; } CWBool CWParseClearConfigurationResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode) { int offsetTillMessages; if (msgPtr == NULL || resultCode == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); offsetTillMessages = msgPtr->offset; CWLog("Parsing Clear Configuration Response..."); // parse message elements while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: *resultCode = CWProtocolRetrieve32(msgPtr); break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Configuration Update Response"); break; } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CWLog("Clear Configuration Response Parsed"); return CW_TRUE; } CWBool CWParseStationConfigurationResponseMessage(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * resultCode) { int offsetTillMessages; if (msgPtr == NULL || resultCode == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); offsetTillMessages = msgPtr->offset; CWLog("Parsing Station Configuration Response..."); // parse message elements while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: *resultCode = CWProtocolRetrieve32(msgPtr); break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Station Configuration Response"); break; } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CWLog("Station Configuration Response Parsed"); return CW_TRUE; } CWBool CWSaveConfigurationUpdateResponseMessage(CWProtocolResultCode resultCode, int WTPIndex, CWProtocolVendorSpecificValues * vendValues) { char *wumPayloadBytes = NULL; int closeWTPManager = CW_FALSE; if (vendValues != NULL) { char *responseBuffer; int socketIndex, payloadSize, headerSize, netWTPIndex, netresultCode, netpayloadSize; /******************************** *Payload Management * ********************************/ headerSize = 3 * sizeof(int); switch (vendValues->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: if (vendValues->payload != NULL) payloadSize = strlen((char *)vendValues->payload); else payloadSize = 0; break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: wumPayloadBytes = vendValues->payload; payloadSize = 1; /* * When dealing with WUM responses, the dafault size * is 1 bytes, which is used for the type. * * The only response message with a bigger payload is the * WTP_VERSION_RESPONSE (4 bytes), as it carries the WTP version * together with the response type. */ if (wumPayloadBytes[0] == WTP_VERSION_RESPONSE) payloadSize = 4; /* * If we received a positive WTP_COMMIT_ACK, we need to terminate * the WTP Manager Thread. */ if (wumPayloadBytes[0] == WTP_COMMIT_ACK && resultCode == CW_PROTOCOL_SUCCESS) closeWTPManager = CW_TRUE; break; default: payloadSize = 0; break; } if ((responseBuffer = malloc(headerSize + payloadSize)) != NULL) { netWTPIndex = htonl(WTPIndex); memcpy(responseBuffer, &netWTPIndex, sizeof(int)); netresultCode = htonl(resultCode); memcpy(responseBuffer + sizeof(int), &netresultCode, sizeof(int)); netpayloadSize = htonl(payloadSize); memcpy(responseBuffer + (2 * sizeof(int)), &netpayloadSize, sizeof(int)); if (payloadSize > 0) { memcpy(responseBuffer + headerSize, (char *)vendValues->payload, payloadSize); if (vendValues->vendorPayloadType == CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI) ((char *)vendValues->payload)[payloadSize] = '\0'; } socketIndex = gWTPs[WTPIndex].applicationIndex; /**************************************************** * Forward payload to correct application * ****************************************************/ if (!CWErr(CWThreadMutexLock(&appsManager.socketMutex[socketIndex]))) { CWLog("Error locking numSocketFree Mutex"); return CW_FALSE; } if (Writen(appsManager.appSocket[socketIndex], responseBuffer, headerSize + payloadSize) < 0) { CWThreadMutexUnlock(&appsManager.socketMutex[socketIndex]); CWLog("Error locking numSocketFree Mutex"); return CW_FALSE; } CWThreadMutexUnlock(&appsManager.socketMutex[socketIndex]); } CW_FREE_OBJECT(responseBuffer); CW_FREE_OBJECT(vendValues->payload); CW_FREE_OBJECT(vendValues); } else if (!CWBindingSaveConfigurationUpdateResponse(resultCode, WTPIndex)) { return CW_FALSE; } /* * On a positive WTP_COMMIT_ACK, we need to close the WTP Manager. */ if (closeWTPManager) { gWTPs[WTPIndex].isRequestClose = CW_TRUE; CWSignalThreadCondition(&gWTPs[WTPIndex].interfaceWait); } CWDebugLog("Configuration Update Response Saved"); return CW_TRUE; } CWBool CWParseWTPDataTransferRequestMessage(CWProtocolMessage * msgPtr, int len, CWProtocolWTPDataTransferRequestValues * valuesPtr) { int offsetTillMessages; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); offsetTillMessages = msgPtr->offset; CWLog(""); CWLog("#________ WTP Data Transfer (Run) ________#"); CWLog("Parsing WTP Data Transfer Request..."); // parse message elements while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_DATA_TRANSFER_DATA_CW_TYPE:{ if (!(CWParseMsgElemDataTransferData(msgPtr, elemLen, valuesPtr))) return CW_FALSE; CWDebugLog("----- %s --------\n", valuesPtr->debug_info); break; } default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in WTP Data Transfer Request"); break; } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); return CW_TRUE; } CWBool CWParseWTPEventRequestMessage(CWProtocolMessage * msgPtr, int len, CWProtocolWTPEventRequestValues * valuesPtr) { int offsetTillMessages; int i = 0, k = 0; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); /* CW_CREATE_OBJECT_ERR(valuesPtr, CWProtocolWTPEventRequestValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); */ offsetTillMessages = msgPtr->offset; CWLog(""); CWLog("#________ WTP Event (Run) ________#"); CWLog("Parsing WTP Event Request..."); valuesPtr->errorReportCount = 0; valuesPtr->errorReport = NULL; valuesPtr->duplicateIPv4 = NULL; valuesPtr->duplicateIPv6 = NULL; valuesPtr->WTPOperationalStatisticsCount = 0; valuesPtr->WTPOperationalStatistics = NULL; valuesPtr->WTPRadioStatisticsCount = 0; valuesPtr->WTPRadioStatistics = NULL; valuesPtr->WTPRebootStatistics = NULL; /* parse message elements */ while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_CW_TYPE: CW_CREATE_OBJECT_ERR(valuesPtr->errorReport, CWDecryptErrorReportValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWParseMsgElemDecryptErrorReport(msgPtr, elemLen, valuesPtr->errorReport))) return CW_FALSE; break; case CW_MSG_ELEMENT_DUPLICATE_IPV4_ADDRESS_CW_TYPE: CW_CREATE_OBJECT_ERR(valuesPtr->duplicateIPv4, WTPDuplicateIPv4, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_ARRAY_ERR((valuesPtr->duplicateIPv4)->MACoffendingDevice_forIpv4, 6, unsigned char, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWParseMsgElemDuplicateIPv4Address(msgPtr, elemLen, valuesPtr->duplicateIPv4))) return CW_FALSE; break; case CW_MSG_ELEMENT_DUPLICATE_IPV6_ADDRESS_CW_TYPE: CW_CREATE_OBJECT_ERR(valuesPtr->duplicateIPv6, WTPDuplicateIPv6, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_ARRAY_ERR((valuesPtr->duplicateIPv6)->MACoffendingDevice_forIpv6, 6, unsigned char, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWParseMsgElemDuplicateIPv6Address(msgPtr, elemLen, valuesPtr->duplicateIPv6))) return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_OPERAT_STATISTICS_CW_TYPE: valuesPtr->WTPOperationalStatisticsCount++; msgPtr->offset += elemLen; break; case CW_MSG_ELEMENT_WTP_RADIO_STATISTICS_CW_TYPE: valuesPtr->WTPRadioStatisticsCount++; msgPtr->offset += elemLen; break; case CW_MSG_ELEMENT_WTP_REBOOT_STATISTICS_CW_TYPE: CW_CREATE_OBJECT_ERR(valuesPtr->WTPRebootStatistics, WTPRebootStatisticsInfo, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWParseWTPRebootStatistics(msgPtr, elemLen, valuesPtr->WTPRebootStatistics))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in WTP Event Request"); break; } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CW_CREATE_ARRAY_ERR(valuesPtr->WTPOperationalStatistics, valuesPtr->WTPOperationalStatisticsCount, WTPOperationalStatisticsValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_ARRAY_ERR(valuesPtr->WTPRadioStatistics, valuesPtr->WTPRadioStatisticsCount, WTPRadioStatisticsValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); msgPtr->offset = offsetTillMessages; while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_WTP_OPERAT_STATISTICS_CW_TYPE: if (!(CWParseWTPOperationalStatistics(msgPtr, elemLen, &(valuesPtr->WTPOperationalStatistics[k++])))) return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_RADIO_STATISTICS_CW_TYPE: if (!(CWParseWTPRadioStatistics(msgPtr, elemLen, &(valuesPtr->WTPRadioStatistics[i++])))) return CW_FALSE; break; default: msgPtr->offset += elemLen; break; } } CWLog("WTP Event Request Parsed"); return CW_TRUE; } CWBool CWSaveWTPEventRequestMessage(CWProtocolWTPEventRequestValues * WTPEventRequest, CWWTPProtocolManager * WTPProtocolManager) { if (WTPEventRequest == NULL || WTPProtocolManager == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (WTPEventRequest->WTPRebootStatistics) { CW_FREE_OBJECT(WTPProtocolManager->WTPRebootStatistics); WTPProtocolManager->WTPRebootStatistics = WTPEventRequest->WTPRebootStatistics; } if ((WTPEventRequest->WTPOperationalStatisticsCount) > 0) { int i, k; for (i = 0; i < (WTPEventRequest->WTPOperationalStatisticsCount); i++) { //found = CW_FALSE; for (k = 0; k < (WTPProtocolManager->radiosInfo).radioCount; k++) { if ((WTPProtocolManager->radiosInfo).radiosInfo[k].radioID == (WTPEventRequest->WTPOperationalStatistics[i]).radioID) { //found = CW_TRUE; (WTPProtocolManager->radiosInfo).radiosInfo[k].TxQueueLevel = (WTPEventRequest->WTPOperationalStatistics[i]).TxQueueLevel; (WTPProtocolManager->radiosInfo).radiosInfo[k].wirelessLinkFramesPerSec = (WTPEventRequest->WTPOperationalStatistics[i]).wirelessLinkFramesPerSec; } } /*if(!found) { for(k=0; k<(WTPProtocolManager->radiosInfo).radioCount; k++) { if((WTPProtocolManager->radiosInfo).radiosInfo[k].radioID == UNUSED_RADIO_ID); { (WTPProtocolManager->radiosInfo).radiosInfo[k].radioID = (WTPEventRequest->WTPOperationalStatistics[i]).radioID; (WTPProtocolManager->radiosInfo).radiosInfo[k].TxQueueLevel = (WTPEventRequest->WTPOperationalStatistics[i]).TxQueueLevel; (WTPProtocolManager->radiosInfo).radiosInfo[k].wirelessLinkFramesPerSec = (WTPEventRequest->WTPOperationalStatistics[i]).wirelessLinkFramesPerSec; } } } */ } } if ((WTPEventRequest->WTPRadioStatisticsCount) > 0) { int i, k; for (i = 0; i < (WTPEventRequest->WTPRadioStatisticsCount); i++) { //found = CW_FALSE; for (k = 0; k < (WTPProtocolManager->radiosInfo).radioCount; k++) { if ((WTPProtocolManager->radiosInfo).radiosInfo[k].radioID == (WTPEventRequest->WTPOperationalStatistics[i]).radioID) { //found = CW_TRUE; (WTPProtocolManager->radiosInfo).radiosInfo[k].statistics = (WTPEventRequest->WTPRadioStatistics[i]).WTPRadioStatistics; } } /*if(!found) { for(k=0; k<(WTPProtocolManager->radiosInfo).radioCount; k++) { if((WTPProtocolManager->radiosInfo).radiosInfo[k].radioID == UNUSED_RADIO_ID); { (WTPProtocolManager->radiosInfo).radiosInfo[k].radioID = (WTPEventRequest->WTPOperationalStatistics[i]).radioID; (WTPProtocolManager->radiosInfo).radiosInfo[k].statistics = (WTPEventRequest->WTPRadioStatistics[i]).WTPRadioStatistics; } } } */ } } /* CW_FREE_OBJECT((WTPEventRequest->WTPOperationalStatistics), (WTPEventRequest->WTPOperationalStatisticsCount)); CW_FREE_OBJECTS_ARRAY((WTPEventRequest->WTPRadioStatistics), (WTPEventRequest->WTPRadioStatisticsCount)); Da controllare!!!!!!! */ CW_FREE_OBJECT(WTPEventRequest->WTPOperationalStatistics); CW_FREE_OBJECT(WTPEventRequest->WTPRadioStatistics); /*CW_FREE_OBJECT(WTPEventRequest); */ return CW_TRUE; } CWBool CWAssembleWTPDataTransferResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling WTP Data Transfer Response..."); if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_DATA_TRANSFER_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("WTP Data Transfer Response Assembled"); return CW_TRUE; } CWBool CWAssembleWTPEventResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling WTP Event Response..."); if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_WTP_EVENT_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("WTP Event Response Assembled"); return CW_TRUE; } CWBool CWParseChangeStateEventRequestMessage2(CWProtocolMessage * msgPtr, int len, CWProtocolChangeStateEventRequestValues ** valuesPtr) { int offsetTillMessages; int i = 0; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_OBJECT_ERR(*valuesPtr, CWProtocolChangeStateEventRequestValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); offsetTillMessages = msgPtr->offset; CWLog(""); CWLog("#________ WTP Change State Event (Run) ________#"); (*valuesPtr)->radioOperationalInfo.radiosCount = 0; (*valuesPtr)->radioOperationalInfo.radios = NULL; /* parse message elements */ while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); /*CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ switch (elemType) { case CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE: /* just count how many radios we have, so we * can allocate the array */ ((*valuesPtr)->radioOperationalInfo.radiosCount)++; msgPtr->offset += elemLen; break; case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: if (!(CWParseResultCode(msgPtr, elemLen, &((*valuesPtr)->resultCode)))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element in Change State Event Request"); } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CW_CREATE_ARRAY_ERR((*valuesPtr)->radioOperationalInfo.radios, (*valuesPtr)->radioOperationalInfo.radiosCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); msgPtr->offset = offsetTillMessages; i = 0; while (msgPtr->offset - offsetTillMessages < len) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(msgPtr, &type, &len); switch (type) { case CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE: /* will be handled by the caller */ if (! (CWParseWTPRadioOperationalState (msgPtr, len, &((*valuesPtr)->radioOperationalInfo.radios[i])))) return CW_FALSE; i++; break; default: msgPtr->offset += len; break; } } CWLog("Change State Event Request Parsed"); return CW_TRUE; } CWBool CWSaveChangeStateEventRequestMessage(CWProtocolChangeStateEventRequestValues * valuesPtr, CWWTPProtocolManager * WTPProtocolManager) { CWBool found; CWBool retValue = CW_TRUE; if (valuesPtr == NULL || WTPProtocolManager == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((valuesPtr->radioOperationalInfo.radiosCount) > 0) { int i, k; for (i = 0; i < (valuesPtr->radioOperationalInfo.radiosCount); i++) { found = CW_FALSE; for (k = 0; k < (WTPProtocolManager->radiosInfo).radioCount; k++) { if ((WTPProtocolManager->radiosInfo).radiosInfo[k].radioID == (valuesPtr->radioOperationalInfo.radios[i]).ID) { found = CW_TRUE; (WTPProtocolManager->radiosInfo).radiosInfo[k].operationalState = (valuesPtr->radioOperationalInfo.radios[i]).state; (WTPProtocolManager->radiosInfo).radiosInfo[k].operationalCause = (valuesPtr->radioOperationalInfo.radios[i]).cause; } if (!found) retValue = CW_FALSE; } } } CW_FREE_OBJECT(valuesPtr->radioOperationalInfo.radios) CW_FREE_OBJECT(valuesPtr); return retValue; } CWBool CWParseEchoRequestMessage(CWProtocolMessage * msgPtr, int len) { int offsetTillMessages; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((msgPtr->msg) == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); offsetTillMessages = msgPtr->offset; CWLog(""); CWLog("#________ Echo Request (Run) ________#"); /* parse message elements */ while ((msgPtr->offset - offsetTillMessages) < len) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(msgPtr, &elemType, &elemLen); /*CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ switch (elemType) { default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Echo Request must carry no message elements"); } } if ((msgPtr->offset - offsetTillMessages) != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CWLog("Echo Request Parsed"); return CW_TRUE; } CWBool CWAssembleEchoResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Echo Response..."); if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_ECHO_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Echo Response Assembled"); return CW_TRUE; } CWBool CWAssembleConfigurationUpdateRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, int msgElement) { CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; CWProtocolMessage *msgElems = NULL; int msgElemCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Configuration Update Request..."); switch (msgElement) { case CONFIG_UPDATE_REQ_QOS_ELEMENT_TYPE:{ if (!CWBindingAssembleConfigurationUpdateRequest (&msgElemsBinding, &msgElemBindingCount, BINDING_MSG_ELEMENT_TYPE_WTP_QOS)) { return CW_FALSE; } break; } case CONFIG_UPDATE_REQ_OFDM_ELEMENT_TYPE:{ if (!CWBindingAssembleConfigurationUpdateRequest (&msgElemsBinding, &msgElemBindingCount, BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL)) { return CW_FALSE; } break; } case CONFIG_UPDATE_REQ_VENDOR_UCI_ELEMENT_TYPE:{ CWLog("Assembling UCI Conf Update Request"); if (!CWProtocolAssembleConfigurationUpdateRequest (&msgElems, &msgElemCount, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI)) { return CW_FALSE; } break; } case CONFIG_UPDATE_REQ_VENDOR_WUM_ELEMENT_TYPE:{ CWLog("Assembling WUM Conf Update Request"); if (!CWProtocolAssembleConfigurationUpdateRequest (&msgElems, &msgElemCount, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM)) { return CW_FALSE; } break; } } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Configuration Update Request Assembled"); return CW_TRUE; } CWBool CWAssembleClearConfigurationRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum) { CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; CWProtocolMessage *msgElems = NULL; int msgElemCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Clear Configuration Request..."); if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Clear Configuration Request Assembled"); return CW_TRUE; } CWBool CWAssembleWLANConfigurationRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, unsigned char *recv_packet, int Operation, int len_packet) { CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; CWProtocolMessage *msgElems = NULL; int msgElemCount = 1; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling WLAN 802.11 Configuration Request..."); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // Assemble Message Elements if (Operation == CW_MSG_ELEMENT_IEEE80211_ADD_WLAN_CW_TYPE) { if (!(CWAssembleMsgElemAddWLAN(0, &(msgElems[++k]), recv_packet, len_packet))) { //radioID = 0 -valore predefinito- CWErrorHandleLast(); int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } } else if (Operation == CW_MSG_ELEMENT_IEEE80211_DELETE_WLAN_CW_TYPE) { if (!(CWAssembleMsgElemDeleteWLAN(0, &(msgElems[++k]), recv_packet, len_packet))) { //radioID = 0 -valore predefinito- CWErrorHandleLast(); int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } } /* to be implemented in a case of Binding with appropriate messages elements -- see draft capwap-spec && capwap-binding if(!CWBindingAssembleConfigurationUpdateRequest(&msgElemsBinding, &msgElemBindingCount)){ return CW_FALSE; } */ if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Station WLAN 802.11 Configuration Request Assembled"); return CW_TRUE; } CWBool CWAssembleStationConfigurationRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, unsigned char *StationMacAddr, int Operation) { CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; CWProtocolMessage *msgElems = NULL; int msgElemCount = 1; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Station Configuration Request..."); CWLog("StationMacAddr = %02X %02X %02X %02X %02X %02X", StationMacAddr[0], StationMacAddr[1], StationMacAddr[2], StationMacAddr[3], StationMacAddr[4], StationMacAddr[5]); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // Assemble Message Elements if (Operation == CW_MSG_ELEMENT_ADD_STATION_CW_TYPE) { if (!(CWAssembleMsgElemAddStation(0, &(msgElems[++k]), StationMacAddr))) { //radioID = 0 -valore predefinito- CWErrorHandleLast(); int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } } else if (Operation == CW_MSG_ELEMENT_DELETE_STATION_CW_TYPE) { if (!(CWAssembleMsgElemDeleteStation(0, &(msgElems[++k]), StationMacAddr))) { //radioID = 0 -valore predefinito- CWErrorHandleLast(); int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } } /* to be implemented in a case of Binding with appropriate messages elements -- see draft capwap-spec && capwap-binding if(!CWBindingAssembleConfigurationUpdateRequest(&msgElemsBinding, &msgElemBindingCount)){ return CW_FALSE; } */ if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Station Configuration Request Assembled"); return CW_TRUE; } CWBool CWStartNeighborDeadTimer(int WTPIndex) { /* start NeighborDeadInterval timer */ if (!CWErr(CWTimerRequest(gCWNeighborDeadInterval, &(gWTPs[WTPIndex].thread), &(gWTPs[WTPIndex].currentTimer), CW_CRITICAL_TIMER_EXPIRED_SIGNAL))) { return CW_FALSE; } return CW_TRUE; } CWBool CWStartNeighborDeadTimerForEcho(int WTPIndex) { int echoInterval; /* start NeighborDeadInterval timer */ CWACGetEchoRequestTimer(&echoInterval); if (!CWErr(CWTimerRequest(echoInterval, &(gWTPs[WTPIndex].thread), &(gWTPs[WTPIndex].currentTimer), CW_CRITICAL_TIMER_EXPIRED_SIGNAL))) { return CW_FALSE; } return CW_TRUE; } CWBool CWStopNeighborDeadTimer(int WTPIndex) { if (!CWTimerCancel(&(gWTPs[WTPIndex].currentTimer))) { return CW_FALSE; } return CW_TRUE; } CWBool CWRestartNeighborDeadTimer(int WTPIndex) { CWThreadSetSignals(SIG_BLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); if (!CWStopNeighborDeadTimer(WTPIndex)) return CW_FALSE; if (!CWStartNeighborDeadTimer(WTPIndex)) return CW_FALSE; CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); CWDebugLog("NeighborDeadTimer restarted"); return CW_TRUE; } CWBool CWRestartNeighborDeadTimerForEcho(int WTPIndex) { CWThreadSetSignals(SIG_BLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); if (!CWStopNeighborDeadTimer(WTPIndex)) return CW_FALSE; if (!CWStartNeighborDeadTimerForEcho(WTPIndex)) return CW_FALSE; CWThreadSetSignals(SIG_UNBLOCK, 1, CW_SOFT_TIMER_EXPIRED_SIGNAL); CWDebugLog("NeighborDeadTimer restarted for Echo interval"); return CW_TRUE; } ================================================ FILE: ACSettingsFile.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define CW_SETTINGS_FILE "/etc/capwap/settings.ac.txt" #define CWMIN_DEFAULT 3 #define CWMAX_DEFAULT 10 #define AIFS_DEFAULT 1 FILE *gSettingsFile = NULL; WTPQosValues *gDefaultQosValues = NULL; int gHostapd_port; char *gHostapd_unix_path; void CWExtractValue(char *start, char **startValue, char **endValue, int *offset) { *offset = strspn(start + 1, " \t\n\r"); *startValue = start + 1 + *offset; *offset = strcspn(*startValue, " \t\n\r"); *endValue = *startValue + *offset - 1; } CWBool CWParseSettingsFile() { char *line = NULL; gSettingsFile = fopen(CW_SETTINGS_FILE, "rb"); if (gSettingsFile == NULL) { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } CW_CREATE_ARRAY_ERR(gDefaultQosValues, NUM_QOS_PROFILES, WTPQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); while ((line = (char *)CWGetCommand(gSettingsFile)) != NULL) { char *startTag = NULL; char *endTag = NULL; if ((startTag = strchr(line, '<')) == NULL) { CW_FREE_OBJECT(line); continue; } if ((endTag = strchr(line, '>')) == NULL) { CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMIN_VOICE", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMIN_DEFAULT; gDefaultQosValues[VOICE_QUEUE_INDEX].cwMin = value; CWDebugLog("CWMIN_VOICE: %d", gDefaultQosValues[VOICE_QUEUE_INDEX].cwMin); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMAX_VOICE", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMAX_DEFAULT; gDefaultQosValues[VOICE_QUEUE_INDEX].cwMax = value; CWDebugLog("CWMAX_VOICE: %d", gDefaultQosValues[VOICE_QUEUE_INDEX].cwMax); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "AIFS_VOICE", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = AIFS_DEFAULT; gDefaultQosValues[VOICE_QUEUE_INDEX].AIFS = value; CWDebugLog("AIFS_VOICE: %d", gDefaultQosValues[VOICE_QUEUE_INDEX].AIFS); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMIN_VIDEO", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMIN_DEFAULT; gDefaultQosValues[VIDEO_QUEUE_INDEX].cwMin = value; CWDebugLog("CWMIN_VIDEO: %d", gDefaultQosValues[VIDEO_QUEUE_INDEX].cwMin); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMAX_VIDEO", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMAX_DEFAULT; gDefaultQosValues[VIDEO_QUEUE_INDEX].cwMax = value; CWDebugLog("CWMAX_VIDEO: %d", gDefaultQosValues[VIDEO_QUEUE_INDEX].cwMax); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "AIFS_VIDEO", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = AIFS_DEFAULT; gDefaultQosValues[VIDEO_QUEUE_INDEX].AIFS = value; CWDebugLog("AIFS_VIDEO: %d", gDefaultQosValues[VIDEO_QUEUE_INDEX].AIFS); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMIN_BEST_EFFORT", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMIN_DEFAULT; gDefaultQosValues[BESTEFFORT_QUEUE_INDEX].cwMin = value; CWDebugLog("CWMIN_BEST_EFFORT: %d", gDefaultQosValues[BESTEFFORT_QUEUE_INDEX].cwMin); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMAX_BEST_EFFORT", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMAX_DEFAULT; gDefaultQosValues[BESTEFFORT_QUEUE_INDEX].cwMax = value; CWDebugLog("CWMAX_BEST_EFFORT: %d", gDefaultQosValues[BESTEFFORT_QUEUE_INDEX].cwMax); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "AIFS_BEST_EFFORT", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = AIFS_DEFAULT; gDefaultQosValues[BESTEFFORT_QUEUE_INDEX].AIFS = value; CWDebugLog("AIFS_BEST_EFFORT: %d", gDefaultQosValues[BESTEFFORT_QUEUE_INDEX].AIFS); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMIN_BACKGROUND", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMIN_DEFAULT; gDefaultQosValues[BACKGROUND_QUEUE_INDEX].cwMin = value; CWDebugLog("CWMIN_BACKGROUND: %d", gDefaultQosValues[BACKGROUND_QUEUE_INDEX].cwMin); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "CWMAX_BACKGROUND", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = CWMAX_DEFAULT; gDefaultQosValues[BACKGROUND_QUEUE_INDEX].cwMax = value; CWDebugLog("CWMAX_BACKGROUND: %d", gDefaultQosValues[BACKGROUND_QUEUE_INDEX].cwMax); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "AIFS_BACKGROUND", endTag - startTag - 1)) { int value = atoi(endTag + 1); if (value == 0) value = AIFS_DEFAULT; gDefaultQosValues[BACKGROUND_QUEUE_INDEX].AIFS = value; CWDebugLog("AIFS_BACKGROUND: %d", gDefaultQosValues[BACKGROUND_QUEUE_INDEX].AIFS); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "AC_HOSTAPD_PORT", endTag - startTag - 1)) { gHostapd_port = atoi(endTag + 1); CWDebugLog("Hostapd Port connection: %d", gHostapd_port); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "AC_HOSTAPD_UNIX_PATH", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; CWExtractValue(endTag, &startValue, &endValue, &offset); CW_CREATE_STRING_ERR(gHostapd_unix_path, offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); strncpy(gHostapd_unix_path, startValue, offset); gHostapd_unix_path[offset] = '\0'; CWDebugLog("Hostapd Unix Domain Path: %s", gHostapd_unix_path); CW_FREE_OBJECT(line); continue; } CW_FREE_OBJECT(line); } return CW_TRUE; } ================================================ FILE: ACipcHostapd.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Sotiraq Sima (Sotiraq.Sima@gmail.com) * * * *******************************************************************************************/ #include #include "ACipcHostapd.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define EXIT_FRAME_THREAD(sock) CWLog("ERROR Handling Frames: application will be closed!"); close(sock); exit(1); //#define LOCALUDP //#define NETUDP //#define USEIPV6 struct client_hostapd { char live; char start_set_fase; int associated; int address_size; #if defined(LOCALUDP) struct sockaddr_un client; #else #if defined(USEIPV6) struct sockaddr_in6 client; #else struct sockaddr_in client; #endif #endif }; struct client_hostapd ch[CW_MAX_WTP]; char connected = 0; int sock; extern int wtpInRunState; void CWACsend_data_to_hostapd(int WTPIndex, unsigned char *buf, int len) { CWDebugLog("CWACsend_data_to_hostapd() "); unsigned char tmp_buf[3000]; tmp_buf[0] = DATE_TO_AC; memcpy(tmp_buf + 1, buf, len); if (sendto(sock, tmp_buf, len + 1, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { perror("send"); return; } } void CWACsend_command_to_hostapd_CLOSE(int WTPIndex, unsigned char *buf, int len) { buf[0] = CLOSE; if (sendto(sock, buf, len, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_SET_WTPRINFO(int WTPIndex, char *buf, int len) { buf[0] = SET_WTPRINFO; if (sendto(sock, buf, len, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_SET_RATES(int WTPIndex, char *buf, int len) { buf[0] = SET_RATES; if (sendto(sock, buf, len, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_SET_MDC(int WTPIndex, char *buf, int len) { buf[0] = SET_MDC; if (sendto(sock, buf, len, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_SET_MAC(int WTPIndex, char *buf, int len) { buf[0] = SET_MAC; if (sendto(sock, buf, len, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_GOLIVE(int WTPIndex) { char buf[1]; buf[0] = GOLIVE; if (sendto(sock, buf, 1, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_HAVE_TO_WAIT(int WTPIndex) { char buf[1]; buf[0] = HAVE_TO_WAIT; if (sendto(sock, buf, 1, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWACsend_command_to_hostapd_SEND_WLAN(int WTPIndex) { char buf[1]; buf[0] = SEND_WLAN_TO_WTP; if (sendto(sock, buf, 1, 0, (struct sockaddr *)&ch[WTPIndex].client, ch[WTPIndex].address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } #if defined(LOCALUDP) void send_close_cmd(struct sockaddr_un cli, int as) { #else #if defined(USEIPV6) void send_close_cmd(struct sockaddr_in6 cli, int as) { #else void send_close_cmd(struct sockaddr_in cli, int as) { #endif #endif unsigned char cmd[10]; cmd[0] = CLOSE; if (sendto(sock, cmd, 1, 0, (struct sockaddr *)&cli, as) < 0) { perror("send close"); return; } } int We_Radio_Information_WTP(int WTPIndex) { int i; int a = 0; int b = 0; int c = 0; if (gWTPs[WTPIndex].SuppRates[0] != 0) b = 1; if (gWTPs[WTPIndex].RadioInformationABGN != 0) a = 1; for (i = 0; i < 6; i++) if (gWTPs[WTPIndex].MultiDomCapa[i] != 0) c = 1; if (a && b && c) return 1; else return 0; } int Exist_WTPs() { int i; for (i = 0; i < CW_MAX_WTP; i++) if (gWTPs[i].isNotFree) return 1; return 0; } int GetWTP_not_associated_to_Hostapd() { int i; for (i = 0; i < CW_MAX_WTP; i++) { if (gWTPs[i].isNotFree && ch[i].associated == 0) return i; } return -1; } CW_THREAD_RETURN_TYPE CWACipc_with_ac_hostapd(void *arg) { int tmp_WTPIndex = -1; int len; int k; #if defined(LOCALUDP) struct sockaddr_un server; #elif defined(NETUDP) #if defined(USEIPV6) struct sockaddr_in6 server; #else struct sockaddr_in server; #endif #endif unsigned char buffer[2048]; int connect_ret; char cmd[10]; CWProtocolMessage *frame = NULL; CWNetworkLev4Address address; CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); #if defined(LOCALUDP) sock = socket(AF_UNIX, SOCK_DGRAM, 0); #elif defined(NETUDP) #if defined(USEIPV6) bzero(&server, sizeof(server)); sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); #else memset(&server, 0, sizeof(server)); if ((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) CWDebugLog("WTP ipc HOSTAPD: Error listen "); #endif #else #if defined(USEIPV6) bzero(&server, sizeof(server)); sock = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); #else memset(&server, 0, sizeof(server)); sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); #endif #endif if (sock < 0) { CWDebugLog("AC ipc HOSTAPD: Error creating socket"); EXIT_FRAME_THREAD(sock); } CWDebugLog("AC ipc HOSTAPD: Trying to connect to hostapd (AC)..."); #if defined(LOCALUDP) server.sun_family = AF_UNIX; strcpy(server.sun_path, gHostapd_unix_path); unlink(server.sun_path); connect_ret = bind(sock, (struct sockaddr *)&server, strlen(server.sun_path) + sizeof(server.sun_family)); #elif defined(NETUDP) #if defined(USEIPV6) server.sin6_family = AF_INET6; server.sin6_port = gHostapd_port; server.sin6_addr = in6addr_any; #else server.sin_family = AF_INET; server.sin_port = htons(gHostapd_port); server.sin_addr.s_addr = htonl(INADDR_ANY); #endif if ((connect_ret = bind(sock, (struct sockaddr *)&server, sizeof(server)))==-1) CWDebugLog("WTP ipc HOSTAPD: Error listen "); #endif if (connect_ret == -1) { CWDebugLog("AC ipc HOSTAPD: Error connect to socket"); EXIT_FRAME_THREAD(sock); } #if defined(LOCALUDP) #elif defined(NETUDP) #else if (listen(sock, CW_MAX_WTP) < 0) { CWDebugLog("AC ipc HOSTAPD: Error listen "); EXIT_FRAME_THREAD(sock); } #endif int i = 0; CWProtocolMessage *completeMsgPtr = NULL; int fragmentsNum = 0; CWMultiHomedSocket *sockPtr = &gACSocket; int dataSocket = 0; #if defined(LOCALUDP) struct sockaddr_un client_tmp; client_tmp.sun_family = AF_UNIX; #elif defined(NETUDP) #if defined(USEIPV6) struct sockaddr_in6 client_tmp; #else struct sockaddr_in client_tmp; #endif #endif socklen_t address_size_tmp = sizeof(client_tmp); for (i = 0; i < CW_MAX_WTP; i++) { ch[i].associated = 0; #if defined(LOCALUDP) ch[i].client.sun_family = AF_UNIX; ch[i].address_size = sizeof(struct sockaddr_un); #elif defined(NETUDP) #if defined(USEIPV6) ch[i].client.sin6_port = 0; #else ch[i].client.sin_port = 0; #endif #endif } #if defined(LOCALUDP) CWLog("Accept Packet at pipe: %s", gHostapd_unix_path); #elif defined(NETUDP) #if defined(USEIPV6) CWLog("Accept UDP v6 Packet at Port: %d", server.sin6_port); #else CWLog("Accept UDP v4 Packet at Port: %d", server.sin_port); #endif #else #if defined(USEIPV6) CWLog("Accept SCTP v6 Packet at Port: %d", server.sin6_port); #else CWLog("Accept SCTP v4 Packet at Port: %d", server.sin_port); #endif #endif CW_REPEAT_FOREVER { tmp_WTPIndex = -1; len = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_tmp, &address_size_tmp); #if defined(LOCALUDP) sprintf(client_tmp.sun_path, "%s%c%c%c%c%c", server.sun_path, buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); #endif if (Exist_WTPs() == 0) { send_close_cmd(client_tmp, sizeof(client_tmp)); continue; } if (len <= 0) { continue; /* EXIT_FRAME_THREAD(sock) */ } for (i = 0; i < CW_MAX_WTP; i++) { #if defined(LOCALUDP) if (strcmp(client_tmp.sun_path, ch[i].client.sun_path) == 0) { tmp_WTPIndex = i; break; } #elif defined(NETUDP) #if defined(USEIPV6) if ((client_tmp.sin6_port == ch[i].client.sin6_port) && (strncmp(client_tmp.sin6_addr.s6_addr, ch[i].client.sin6_addr.s6_addr, 16) == 0)) { tmp_WTPIndex = i; } #else if ((client_tmp.sin_port == ch[i].client.sin_port) && (strcmp(inet_ntoa(client_tmp.sin_addr), inet_ntoa(ch[i].client.sin_addr)) == 0)) { tmp_WTPIndex = i; } #endif #endif } if (tmp_WTPIndex < 0) { // Client not recognized int wtp_non_associated = GetWTP_not_associated_to_Hostapd(); if (wtp_non_associated >= 0) { if (buffer[0] == CONNECT) { ch[wtp_non_associated].live = 0; ch[wtp_non_associated].start_set_fase = 0; ch[wtp_non_associated].associated = 1; ch[wtp_non_associated].client = client_tmp; ch[wtp_non_associated].address_size = address_size_tmp; cmd[0] = CONNECT_R; sendto(sock, cmd, 1, 0, (struct sockaddr *)&ch[wtp_non_associated].client, ch[wtp_non_associated].address_size); CWLog("wtp_non_associated:%d", wtp_non_associated); #if defined(LOCALUDP) CWLog("Hostapd_AC Connect: %s", ch[wtp_non_associated].client.sun_path); #else #if defined(USEIPV6) CWLog("Hostapd_AC (v6) Connect: %d", ch[wtp_non_associated].client.sin6_port); #else CWLog("Hostapd_AC (v4) Connect: %s:%d", inet_ntoa(ch[wtp_non_associated].client.sin_addr), ch[wtp_non_associated].client.sin_port); #endif #endif continue; } else { send_close_cmd(client_tmp, sizeof(client_tmp)); continue; } } else { send_close_cmd(client_tmp, sizeof(client_tmp)); continue; } } else { // Client recognized int sig_byte = 1; #if defined(LOCALUDP) sig_byte = 6; //Code #endif if (buffer[0] == DATE_TO_WTP) { if (gWTPs[tmp_WTPIndex].currentState != CW_ENTER_RUN) { CWDebugLog("AC %d is not in RUN State. The packet was dropped.", i); continue; } else if (len > (gWTPs[tmp_WTPIndex].pathMTU - 20)) { CWDebugLog("802.11 data length(%d) > MTU(%d)", len, gWTPs[tmp_WTPIndex].pathMTU); continue; } else { len = len - sig_byte; CW_CREATE_OBJECT_ERR(frame, CWProtocolMessage, return 0; ); CW_CREATE_PROTOCOL_MESSAGE(*frame, len, return 0; ); memcpy(frame->msg, buffer + sig_byte, len); frame->offset = len; frame->data_msgType = CW_IEEE_802_11_FRAME_TYPE; if (!CWAssembleDataMessage (&completeMsgPtr, &fragmentsNum, gWTPs[tmp_WTPIndex].pathMTU, frame, NULL, CW_PACKET_PLAIN, 0)) { for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*frame); CW_FREE_OBJECT(frame); continue; } for (k = 0; k < sockPtr->count; k++) { if (sockPtr->interfaces[k].sock == gWTPs[tmp_WTPIndex].socket) { dataSocket = sockPtr->interfaces[k].dataSock; CW_COPY_NET_ADDR_PTR(&address, &(gWTPs[tmp_WTPIndex].dataAddress)); break; } } if (dataSocket == 0) { CWDebugLog("data socket of WTP %d isn't ready."); continue; } /* Set port and address of data tunnel */ //sock_set_port_cw((struct sockaddr *)&(address), htons(CW_DATA_PORT)); for (k = 0; k < fragmentsNum; k++) { if (!CWNetworkSendUnsafeUnconnected (dataSocket, &(address), completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { CWDebugLog("Failure sending Request"); break; } } for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*(frame)); CW_FREE_OBJECT(frame); } } else if (buffer[0] == SET_ADDR) { int seqNum = CWGetSeqNum(); if (CWAssembleStationConfigurationRequest(&(gWTPs[tmp_WTPIndex].messages), &(gWTPs[tmp_WTPIndex].messagesCount), gWTPs[tmp_WTPIndex].pathMTU, seqNum, buffer + sig_byte, CW_MSG_ELEMENT_ADD_STATION_CW_TYPE)) { if (CWACSendAcknowledgedPacket (tmp_WTPIndex, CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE, seqNum)) continue; else CWACStopRetransmission(tmp_WTPIndex); } } else if (buffer[0] == DEL_ADDR) { int seqNum = CWGetSeqNum(); if (CWAssembleStationConfigurationRequest(&(gWTPs[tmp_WTPIndex].messages), &(gWTPs[tmp_WTPIndex].messagesCount), gWTPs[tmp_WTPIndex].pathMTU, seqNum, buffer + sig_byte, CW_MSG_ELEMENT_DELETE_STATION_CW_TYPE)) { if (CWACSendAcknowledgedPacket (tmp_WTPIndex, CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE, seqNum)) continue; else CWACStopRetransmission(tmp_WTPIndex); } } else if (buffer[0] == ADD_WLAN) { int seqNum = CWGetSeqNum(); /* UP TAP Interface */ char str[100]; sprintf(str, "ifconfig %s down", gWTPs[tmp_WTPIndex].tap_name); if (system(str)) { CWLog("Error: cmd: \"%s\" ", str); EXIT_FRAME_THREAD(sock); } sprintf(str, "ifconfig %s hw ether %02X:%02X:%02X:%02X:%02X:%02X\n", gWTPs[tmp_WTPIndex].tap_name, (unsigned char)gWTPs[tmp_WTPIndex].RadioMAC[0], (unsigned char)gWTPs[tmp_WTPIndex].RadioMAC[1], (unsigned char)gWTPs[tmp_WTPIndex].RadioMAC[2], (unsigned char)gWTPs[tmp_WTPIndex].RadioMAC[3], (unsigned char)gWTPs[tmp_WTPIndex].RadioMAC[4], (unsigned char)gWTPs[tmp_WTPIndex].RadioMAC[5]); if (system(str)) { CWLog("Error: cmd: \"%s\" ", str); EXIT_FRAME_THREAD(sock); } sprintf(str, "ifconfig %s up", gWTPs[tmp_WTPIndex].tap_name); if (system(str)) { CWLog("Error: cmd: \"%s\" ", str); EXIT_FRAME_THREAD(sock); } if (CWAssembleWLANConfigurationRequest(&(gWTPs[tmp_WTPIndex].messages), &(gWTPs[tmp_WTPIndex].messagesCount), gWTPs[tmp_WTPIndex].pathMTU, seqNum, buffer + sig_byte, CW_MSG_ELEMENT_IEEE80211_ADD_WLAN_CW_TYPE, len - sig_byte)) { if (CWACSendAcknowledgedPacket (tmp_WTPIndex, CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_RESPONSE, seqNum)) continue; else CWACStopRetransmission(tmp_WTPIndex); } } else if (buffer[0] == DEL_WLAN) { int seqNum = CWGetSeqNum(); if (CWAssembleWLANConfigurationRequest(&(gWTPs[tmp_WTPIndex].messages), &(gWTPs[tmp_WTPIndex].messagesCount), gWTPs[tmp_WTPIndex].pathMTU, seqNum, buffer + sig_byte, CW_MSG_ELEMENT_IEEE80211_DELETE_WLAN_CW_TYPE, len - sig_byte)) { if (CWACSendAcknowledgedPacket (tmp_WTPIndex, CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_RESPONSE, seqNum)) continue; else CWACStopRetransmission(tmp_WTPIndex); } } else if (buffer[0] == CLOSE) { #if defined(LOCALUDP) CWLog("Hostapd_AC Disconnect: %s", ch[tmp_WTPIndex].client.sun_path); sprintf(ch[tmp_WTPIndex].client.sun_path, ""); #else #if defined(USEIPV6) CWLog("Hostapd_AC (v6) Disconnect: %d", ch[tmp_WTPIndex].client.sin6_port); ch[tmp_WTPIndex].client.sin6_port = 0; #else CWLog("Hostapd_AC (v4) Disconnect: %s:%d", inet_ntoa(ch[tmp_WTPIndex].client.sin_addr), ch[tmp_WTPIndex].client.sin_port); ch[tmp_WTPIndex].client.sin_port = 0; #endif #endif ch[tmp_WTPIndex].live = 0; ch[tmp_WTPIndex].start_set_fase = 1; ch[tmp_WTPIndex].associated = 0; } else if (buffer[0] == WANT_GOLIVE) { if (ch[tmp_WTPIndex].start_set_fase) { continue; } if (We_Radio_Information_WTP(tmp_WTPIndex) && ch[tmp_WTPIndex].live == 0) { /* NEXT STEP SET WTPRINFO */ ch[tmp_WTPIndex].start_set_fase = 1; char tmp_RadioInfoABGN[2]; CWThreadMutexLock(&gWTPsMutex); tmp_RadioInfoABGN[1] = gWTPs[tmp_WTPIndex].RadioInformationABGN; CWThreadMutexUnlock(&gWTPsMutex); CWACsend_command_to_hostapd_SET_WTPRINFO(tmp_WTPIndex, tmp_RadioInfoABGN, 2); } else { /* NEXT STEP HAVE TO WAIT */ CWACsend_command_to_hostapd_HAVE_TO_WAIT(tmp_WTPIndex); } } else if (buffer[0] == SET_WTPRINFO_R) { /* NEXT STEP SET RATES */ char tmp_SuppRates[9]; CWThreadMutexLock(&gWTPsMutex); memcpy(tmp_SuppRates + 1, gWTPs[tmp_WTPIndex].SuppRates, 8); CWThreadMutexUnlock(&gWTPsMutex); CWACsend_command_to_hostapd_SET_RATES(tmp_WTPIndex, tmp_SuppRates, 9); } else if (buffer[0] == SET_RATES_R) { /* NEXT STEP SET MDC */ char tmp_MultiDomCapa[7]; CWThreadMutexLock(&gWTPsMutex); memcpy(tmp_MultiDomCapa + 1, gWTPs[tmp_WTPIndex].MultiDomCapa, 6); CWThreadMutexUnlock(&gWTPsMutex); CWACsend_command_to_hostapd_SET_MDC(tmp_WTPIndex, tmp_MultiDomCapa, 7); } else if (buffer[0] == SET_MDC_R) { /* NEXT STEP SET MAC */ char tmp_mac[7]; CWThreadMutexLock(&gWTPsMutex); memcpy(tmp_mac + 1, gWTPs[tmp_WTPIndex].RadioMAC, 6); CWThreadMutexUnlock(&gWTPsMutex); CWACsend_command_to_hostapd_SET_MAC(tmp_WTPIndex, tmp_mac, 7); } else if (buffer[0] == SET_MAC_R) { /* NEXT STEP SET MDC */ CWACsend_command_to_hostapd_GOLIVE(tmp_WTPIndex); } else if (buffer[0] == GOLIVE_R) { CWLog("GOLIVE_R from %d", GOLIVE_R); ch[GOLIVE_R].live = 1; } else { CWDebugLog("Received Unknow Command from Hostapd AC (%d)", buffer[0]); } } } close(sock); return (NULL); } ================================================ FILE: ACipcHostapd.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Sotiraq Sima (Sotiraq.Sima@gmail.com) * * * *******************************************************************************************/ #ifndef __CAPWAP_WTPFrameReceive_HEADER__ #define __CAPWAP_WTPFrameReceive_HEADER__ #include #include #include #include #include #include #include #include "smac_code.h" #include "CWAC.h" void CWACsend_data_to_hostapd(int WTPIndex, unsigned char *buf, int len); #endif ================================================ FILE: COPYING ================================================ # ******************************************************************************************* # * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * # * Universita' Campus BioMedico - Italy * # * * # * 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., 59 Temple Place - Suite 330, Boston, * # * MA 02111-1307, USA. * # * * # * --------------------------------------------------------------------------------------- * # * Project: Capwap * # * * # * Author : Ludovico Rossi (ludo@bluepixysw.com) * # * Del Moro Andrea (andrea_delmoro@libero.it) * # * Giovannini Federica (giovannini.federica@gmail.com) * # * Massimo Vellucci (m.vellucci@unicampus.it) * # * Donato Capitella (d.capitella@gmail.com) * # ******************************************************************************************* ================================================ FILE: CWAC.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Daniele De Sanctis (danieledesanctis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_CWAC_HEADER__ #define __CAPWAP_CWAC_HEADER__ /*_______________________________________________________*/ /* *******************___INCLUDE___******************* */ #include "CWCommon.h" #include "ACMultiHomedSocket.h" #include "ACProtocol.h" #include "ACInterface.h" #include "ACBinding.h" #include #include #include #include /*______________________________________________________*/ /* *******************___DEFINE___******************* */ #define CW_MAX_WTP 100 #define CW_CRITICAL_TIMER_EXPIRED_SIGNAL SIGUSR2 #define CW_SOFT_TIMER_EXPIRED_SIGNAL SIGUSR1 #define AC_LOG_FILE_NAME "/var/log/ac.log.txt" #define MAC_ADDR_LEN 6 #define DEST_ADDR_START 4 #define SOURCE_ADDR_START 10 /*Definition of socket's path to send data stats */ #define SOCKET_PATH_AC "/tmp/af_unix_ac_client" #define SOCKET_PATH_RECV_AGENT "/tmp/monitorclt" /********************************************************* * 2009 Updates: * * Message Element Types for the CWAsseble- * * ConfigurationUpdateRequest Function. * *********************************************************/ #define CONFIG_UPDATE_REQ_QOS_ELEMENT_TYPE 0 #define CONFIG_UPDATE_REQ_OFDM_ELEMENT_TYPE 1 #define CONFIG_UPDATE_REQ_VENDOR_UCI_ELEMENT_TYPE 2 #define CONFIG_UPDATE_REQ_VENDOR_WUM_ELEMENT_TYPE 3 /******************************************************** * 2009 Updates: * * For manage the applications connected to AC we use * * an array of socket. Through this array we can set * * easily the correct answer socket. * * isFree and numSocketFree are used for management. * * The mutex array is used for serialize the correct * * write operation by the different wtp thread on the * * relative application socket. * ********************************************************/ #define MAX_APPS_CONNECTED_TO_AC 4 typedef struct { CWSocket appSocket[MAX_APPS_CONNECTED_TO_AC]; CWBool isFree[MAX_APPS_CONNECTED_TO_AC]; CWThreadMutex socketMutex[MAX_APPS_CONNECTED_TO_AC]; int numSocketFree; CWThreadMutex numSocketFreeMutex; } applicationsManager; applicationsManager appsManager; /*_____________________________________________________*/ /* *******************___TYPES___******************* */ /* * Struct that describes a WTP from the AC's point of view */ typedef struct { CWNetworkLev4Address address; CWNetworkLev4Address dataAddress; CWThread thread; CWSecuritySession session; CWBool isNotFree; CWBool isRequestClose; CWStateTransition currentState; int interfaceIndex; CWSocket socket; unsigned char buf[CW_BUFFER_SIZE]; enum { CW_DTLS_HANDSHAKE_IN_PROGRESS, CW_WAITING_REQUEST, CW_COMPLETED, } subState; CWSafeList packetReceiveList; /* depends on the current state: WaitJoin, NeighborDead */ CWTimerID currentTimer; CWTimerID heartbeatTimer; CWList fragmentsList; int pathMTU; /**** ACInterface ****/ int interfaceResult; CWBool interfaceCommandProgress; int interfaceCommand; CWThreadMutex interfaceSingleton; CWThreadMutex interfaceMutex; CWThreadCondition interfaceWait; CWThreadCondition interfaceComplete; WTPQosValues *qosValues; /******************************************************** * 2009 Updates: * * - ofdmValues is a struct for setting the values of * * a Configuration Update Request with message * * elemente OFDM. * * - applicationIndex is the index of application which * * request the command to WTP * * (it will used for selecting the correct socket) * ********************************************************/ OFDMControlValues *ofdmValues; CWProtocolVendorSpecificValues *vendorValues; int applicationIndex; /**** ACInterface ****/ CWWTPProtocolManager WTPProtocolManager; /* Retransmission */ CWProtocolMessage *messages; int messagesCount; int retransmissionCount; CWTimerID currentPacketTimer; CWBool isRetransmitting; /* expected response */ int responseType; int responseSeqNum; /* //Unrecognized message type value * int unrecognizedMsgType; */ // TAP interface name char tap_name[IFNAMSIZ]; int tap_fd; // IEEE 802.11 unsigned char RadioInformationABGN; unsigned char SuppRates[8]; char MultiDomCapa[6]; unsigned char RadioMAC[6]; } CWWTPManager; /*________________________________________________________________*/ /* *******************___EXTERN VARIABLES___******************* */ extern CWWTPManager gWTPs[CW_MAX_WTP]; extern CWThreadMutex gWTPsMutex; extern CWSecurityContext gACSecurityContext; extern int gACHWVersion; extern int gACSWVersion; extern int gActiveStations; extern int gActiveWTPs; extern CWThreadMutex gActiveWTPsMutex; extern int gLimit; extern int gMaxWTPs; extern CWAuthSecurity gACDescriptorSecurity; extern int gRMACField; extern int gWirelessField; extern int gDTLSPolicy; extern CWThreadSpecific gIndexSpecific; extern char *gACName; extern int gDiscoveryTimer; extern int gEchoRequestTimer; extern int gIdleTimeout; extern CWProtocolNetworkInterface *gInterfaces; extern int gInterfacesCount; extern char **gMulticastGroups; extern int gMulticastGroupsCount; extern CWMultiHomedSocket gACSocket; extern WTPQosValues *gDefaultQosValues; extern int gHostapd_port; extern char *gHostapd_unix_path; extern unsigned char WTPRadioInformationType; /*________________________________________________________________*/ /* *******************___GLOBAL VARIABLES FOR ATH_MONITOR TEST___******************* */ typedef struct { struct sockaddr_un servaddr; /* address of Receive Agent */ struct sockaddr_un clntaddr; /* address on AC-side */ int data_stats_sock; } UNIX_SOCKS_INFO; UNIX_SOCKS_INFO UnixSocksArray[CW_MAX_WTP]; /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ /* in AC.c */ void CWACInit(void); void CWCreateConnectionWithHostapdAC(void); void CWACEnterMainLoop(void); CWBool CWACSendAcknowledgedPacket(int WTPIndex, int msgType, int seqNum); CWBool CWACResendAcknowledgedPacket(int WTPIndex); void CWACStopRetransmission(int WTPIndex); void CWACDestroy(void); /* in ACTest.h */ CWBool ACQosTest(int WTPIndex); /* in ACRunState.c */ CWBool CWSaveChangeStateEventRequestMessage(CWProtocolChangeStateEventRequestValues * valuesPtr, CWWTPProtocolManager * WTPProtocolManager); CW_THREAD_RETURN_TYPE CWACipc_with_ac_hostapd(void *arg); //send_data_to_hostapd(unsigned char *, int); /**************************************************************** * 2009 Updates: * * msgElement is used for differentiation between * * all message elements * ****************************************************************/ CWBool CWAssembleConfigurationUpdateRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, int msgElement); CWBool CWAssembleStationConfigurationRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, unsigned char *StationMacAddr, int Operation); CWBool CWAssembleClearConfigurationRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum); /* in ACDiscoveryState.c */ CWBool CWAssembleDiscoveryResponse(CWProtocolMessage ** messagesPtr, int seqNum); CWBool CWParseDiscoveryRequestMessage(unsigned char *msg, int len, int *seqNumPtr, CWDiscoveryRequestValues * valuesPtr); /* in ACRetransmission.c */ CWBool CWACSendFragments(int WTPIndex); /* in ACRunStateCheck.c */ CWBool CWACCheckForConfigurationUpdateRequest(int WTPIndex); /* in ACProtocol_User.c */ CWBool CWACGetVendorInfos(CWACVendorInfos * valPtr); int CWACGetRMACField(); int CWACGetWirelessField(); int CWACGetDTLSPolicy(); void CWACDestroyVendorInfos(CWACVendorInfos * valPtr); /* in ACMainLoop.c */ void CWACManageIncomingPacket(CWSocket sock, unsigned char *buf, int len, int incomingInterfaceIndex, CWNetworkLev4Address * addrPtr, CWBool dataFlag); void *CWManageWTP(void *arg); void CWCloseThread(); /* in CWSecurity.c */ CWBool CWSecurityInitSessionServer(CWWTPManager * pWtp, CWSocket sock, CWSecurityContext ctx, CWSecuritySession * sessionPtr, int *PMTUPtr); CWBool ACEnterJoin(int WTPIndex, CWProtocolMessage * msgPtr); CWBool ACEnterConfigure(int WTPIndex, CWProtocolMessage * msgPtr); CWBool ACEnterDataCheck(int WTPIndex, CWProtocolMessage * msgPtr); CWBool ACEnterRun(int WTPIndex, CWProtocolMessage * msgPtr, CWBool dataFlag); CW_THREAD_RETURN_TYPE CWInterface(void *arg); /* void CWTimerExpiredHandler(int arg); */ #endif ================================================ FILE: CWBinding.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWThreadMutex gWTPsMutex; const int gMaxCAPWAPHeaderSizeBinding = 16; // note: this include optional Wireless field CWBool CWBindingCheckType(int elemType) { if (elemType >= BINDING_MIN_ELEM_TYPE && elemType <= BINDING_MAX_ELEM_TYPE) return CW_TRUE; return CW_FALSE; } // Assemble a CAPWAP Data Packet creating Transport Header. // completeMsgPtr is an array of fragments (can be of size 1 if the packet doesn't need fragmentation) CWBool CWAssembleDataMessage(CWProtocolMessage ** completeMsgPtr, int *fragmentsNumPtr, int PMTU, CWProtocolMessage * frame, CWBindingTransportHeaderValues * bindingValuesPtr, int is_crypted, int keepAlive) { CWProtocolMessage transportHdr; CWProtocolTransportHeaderValues transportVal; if (completeMsgPtr == NULL || fragmentsNumPtr == NULL || frame == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // CWDebugLog("PMTU: %d", PMTU); // handle fragmentation PMTU = PMTU - gMaxCAPWAPHeaderSizeBinding; if (PMTU > 0) { PMTU = (PMTU / 8) * 8; // CAPWAP fragments are made of groups of 8 bytes if (PMTU == 0) goto cw_dont_fragment; // CWDebugLog("Aligned PMTU: %d", PMTU); *fragmentsNumPtr = (frame->offset) / PMTU; if ((frame->offset % PMTU) != 0) (*fragmentsNumPtr)++; //CWDebugLog("Fragments #: %d", *fragmentsNumPtr); } else { cw_dont_fragment: *fragmentsNumPtr = 1; } transportVal.bindingValuesPtr = bindingValuesPtr; if (frame->data_msgType == CW_IEEE_802_11_FRAME_TYPE) transportVal.type = 1; if (*fragmentsNumPtr == 1) { transportVal.isFragment = transportVal.last = transportVal.fragmentOffset = transportVal.fragmentID = 0; transportVal.payloadType = is_crypted; // Assemble Message Elements if (keepAlive) { if (!(CWAssembleTransportHeaderKeepAliveData(&transportHdr, &transportVal, keepAlive))) { CW_FREE_PROTOCOL_MESSAGE(transportHdr); return CW_FALSE; // will be handled by the caller } } else { if (!(CWAssembleTransportHeader(&transportHdr, &transportVal))) { CW_FREE_PROTOCOL_MESSAGE(transportHdr); return CW_FALSE; // will be handled by the caller } } CW_CREATE_OBJECT_ERR(*completeMsgPtr, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_PROTOCOL_MESSAGE(((*completeMsgPtr)[0]), transportHdr.offset + frame->offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreMessage(&((*completeMsgPtr)[0]), &transportHdr); CWProtocolStoreMessage(&((*completeMsgPtr)[0]), frame); CW_FREE_PROTOCOL_MESSAGE(transportHdr); } else { int fragID = CWGetFragmentID(); int totalSize = frame->offset; //CWDebugLog("%d Fragments", *fragmentsNumPtr); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(*completeMsgPtr, *fragmentsNumPtr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); frame->offset = 0; int i; for (i = 0; i < *fragmentsNumPtr; i++) { // for each fragment to assemble int fragSize; transportVal.isFragment = 1; transportVal.fragmentOffset = (frame->offset) / 8; transportVal.fragmentID = fragID; transportVal.payloadType = is_crypted; if (i < ((*fragmentsNumPtr) - 1)) { // not last fragment fragSize = PMTU; transportVal.last = 0; } else { // last fragment fragSize = totalSize - (((*fragmentsNumPtr) - 1) * PMTU); transportVal.last = 1; } CWDebugLog("Fragment #:%d, offset:%d, bytes stored:%d/%d", i, transportVal.fragmentOffset, fragSize, totalSize); // Assemble Transport Header for this fragment if (keepAlive) { if (!(CWAssembleTransportHeaderKeepAliveData(&transportHdr, &transportVal, keepAlive))) { CW_FREE_PROTOCOL_MESSAGE(transportHdr); CW_FREE_OBJECT(completeMsgPtr); return CW_FALSE; // will be handled by the caller } } else { if (!(CWAssembleTransportHeader(&transportHdr, &transportVal))) { CW_FREE_PROTOCOL_MESSAGE(transportHdr); CW_FREE_OBJECT(completeMsgPtr); return CW_FALSE; // will be handled by the caller } } CW_CREATE_PROTOCOL_MESSAGE(((*completeMsgPtr)[i]), transportHdr.offset + fragSize, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreMessage(&((*completeMsgPtr)[i]), &transportHdr); CWProtocolStoreRawBytes(&((*completeMsgPtr)[i]), &((frame->msg)[frame->offset]), fragSize); (frame->offset) += fragSize; CW_FREE_PROTOCOL_MESSAGE(transportHdr); } } return CW_TRUE; } CWBool CWAssembleTransportHeaderBinding(CWProtocolMessage * transportHdrPtr, CWBindingTransportHeaderValues * valuesPtr) { int val = 0; /* Mauro: non piu' specificato nel campo Wireless Specific Information CWSetField32(val, CW_TRANSPORT_HEADER_WIRELESS_ID_START, CW_TRANSPORT_HEADER_WIRELESS_ID_LEN, CW_BINDING_WIRELESSID); */ CWSetField32(val, CW_TRANSPORT_HEADER_LENGTH_START, CW_TRANSPORT_HEADER_LENGTH_LEN, CW_BINDING_DATALENGTH); // CWDebugLog("#### RSSI in= %d",valuesPtr->RSSI ); CWSetField32(val, CW_TRANSPORT_HEADER_RSSI_START, CW_TRANSPORT_HEADER_RSSI_LEN, valuesPtr->RSSI); // CWDebugLog("#### SNR in= %d",valuesPtr->SNR ); CWSetField32(val, CW_TRANSPORT_HEADER_SNR_START, CW_TRANSPORT_HEADER_SNR_LEN, valuesPtr->SNR); /* Mauro: inserisci il byte piu' significativo del sottocampo Data */ CWSetField32(val, CW_TRANSPORT_HEADER_DATARATE_1_START, CW_TRANSPORT_HEADER_DATARATE_1_LEN, (valuesPtr->dataRate) >> 8); CWProtocolStore32(transportHdrPtr, val); val = 0; /* Mauro: inserisci il byte meno significativo del sottocampo Data */ CWSetField32(val, CW_TRANSPORT_HEADER_DATARATE_2_START, CW_TRANSPORT_HEADER_DATARATE_2_LEN, (valuesPtr->dataRate) & 0x000000FF); // CWDebugLog("#### data rate in= %d",valuesPtr->dataRate ); /* CWSetField32(val, CW_TRANSPORT_HEADER_DATARATE_START, CW_TRANSPORT_HEADER_DATARATE_LEN, valuesPtr->dataRate); */ CWSetField32(val, CW_TRANSPORT_HEADER_PADDING_START, CW_TRANSPORT_HEADER_PADDING_LEN, 0); CWProtocolStore32(transportHdrPtr, val); return CW_TRUE; } CWBool CWParseTransportHeaderMACAddress(CWProtocolMessage * msgPtr, unsigned char *mac_ptr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); unsigned char *vval; vval = malloc(7); //CWDebugLog("Parse Transport Header"); int Mac_len = CWProtocolRetrieve8(msgPtr); vval = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, 7); if (mac_ptr != NULL) { CWThreadMutexLock(&gWTPsMutex); memcpy(mac_ptr, vval, Mac_len); CWThreadMutexUnlock(&gWTPsMutex); } return CW_TRUE; } CWBool CWParseTransportHeaderBinding(CWProtocolMessage * msgPtr, CWBindingTransportHeaderValues * valuesPtr) { unsigned int val = 0; if (msgPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); //CWDebugLog("Parse Transport Header"); val = CWProtocolRetrieve32(msgPtr); /* Mauro: non piu' specificato nel campo Wireless Specific Information if(CWGetField32(val, CW_TRANSPORT_HEADER_WIRELESS_ID_START, CW_TRANSPORT_HEADER_WIRELESS_ID_LEN) != CW_BINDING_WIRELESSID) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Wrong Binding Wireless ID"); */ if (CWGetField32(val, CW_TRANSPORT_HEADER_LENGTH_START, CW_TRANSPORT_HEADER_LENGTH_LEN) != CW_BINDING_DATALENGTH) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Wrong Binding Data Field Length"); valuesPtr->RSSI = CWGetField32(val, CW_TRANSPORT_HEADER_RSSI_START, CW_TRANSPORT_HEADER_RSSI_LEN); // CWDebugLog("RSSI: %d", valuesPtr->RSSI); valuesPtr->SNR = CWGetField32(val, CW_TRANSPORT_HEADER_SNR_START, CW_TRANSPORT_HEADER_SNR_LEN); // CWDebugLog("SNR: %d", valuesPtr->SNR); /* Mauro: preleva il byte piu' significativo del sottocampo Data */ valuesPtr->dataRate = CWGetField32(val, CW_TRANSPORT_HEADER_DATARATE_1_START, CW_TRANSPORT_HEADER_DATARATE_1_LEN); val = CWProtocolRetrieve32(msgPtr); /* Daniele: controlla se si tratta di un msg dati(statistiche) o di un msg contenete un wireless frame */ /************************************************************************ * 2009 Update: * * For distinguish between the two types of "specials" data messages * * (QoS stats and Frequency Stats) we used the following values: * * dataRate == 255 && SNR = 1 -> Frequency Stats Packet * * dataRate == 255 -> QoS Stats Packet * ************************************************************************/ if (valuesPtr->dataRate == 255) { if (valuesPtr->SNR == 1) msgPtr->data_msgType = CW_DATA_MSG_FREQ_STATS_TYPE; else msgPtr->data_msgType = CW_DATA_MSG_STATS_TYPE; } else if (valuesPtr->dataRate == 0) msgPtr->data_msgType = CW_DATA_MSG_FRAME_TYPE; /* Mauro: preleva il byte meno significativo del sottocampo Data */ valuesPtr->dataRate = ((valuesPtr->dataRate) << 8) | CWGetField32(val, CW_TRANSPORT_HEADER_DATARATE_1_START, CW_TRANSPORT_HEADER_DATARATE_1_LEN); // valuesPtr->dataRate = CWGetField32(val, CW_TRANSPORT_HEADER_DATARATE_START, CW_TRANSPORT_HEADER_DATARATE_LEN); // CWDebugLog("DATARATE: %d", valuesPtr->dataRate); return CW_TRUE; } ================================================ FILE: CWBinding.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Daniele De Sanctis (danieledesanctis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_CWBinding_HEADER__ #define __CAPWAP_CWBinding_HEADER__ #define CW_BINDING_HLEN 4 #define CW_BINDING_WIRELESSID 1 #define CW_BINDING_DATALENGTH 4 #define NUM_QOS_PROFILES 4 #define UNUSED_QOS_VALUE 255 #define VOICE_QUEUE_INDEX 0 #define VIDEO_QUEUE_INDEX 1 #define BESTEFFORT_QUEUE_INDEX 2 #define BACKGROUND_QUEUE_INDEX 3 #define BINDING_MIN_ELEM_TYPE 1024 #define BINDING_MAX_ELEM_TYPE 2047 #define UNUSED_OFDM_VALUE 255 // Wireless ID viene preso dal campo WBID //#define CW_TRANSPORT_HEADER_WIRELESS_ID_START 0 //#define CW_TRANSPORT_HEADER_WIRELESS_ID_LEN 8 //#define CW_TRANSPORT_HEADER_LENGTH_START 8 #define CW_TRANSPORT_HEADER_LENGTH_START 0 #define CW_TRANSPORT_HEADER_LENGTH_LEN 8 //#define CW_TRANSPORT_HEADER_RSSI_START 16 #define CW_TRANSPORT_HEADER_RSSI_START 8 #define CW_TRANSPORT_HEADER_RSSI_LEN 8 //#define CW_TRANSPORT_HEADER_SNR_START 24 #define CW_TRANSPORT_HEADER_SNR_START 16 #define CW_TRANSPORT_HEADER_SNR_LEN 8 // Poiche' nel draft 09 il campo del CAPWAP header Wireless Specific // Information e' stato privato del sottocampo Wireless ID con il // conseguente shift a sx di 8 bit dei sottocampi successivi il sottocampo // datarate del binding si trova a cavallo tra 2 word da 4 byte quindi // vanno specificati due offset. //#define CW_TRANSPORT_HEADER_DATARATE_START 0 //#define CW_TRANSPORT_HEADER_DATARATE_LEN 16 #define CW_TRANSPORT_HEADER_DATARATE_1_START 24 #define CW_TRANSPORT_HEADER_DATARATE_1_LEN 8 #define CW_TRANSPORT_HEADER_DATARATE_2_START 0 #define CW_TRANSPORT_HEADER_DATARATE_2_LEN 8 //#define CW_TRANSPORT_HEADER_PADDING_START 16 //#define CW_TRANSPORT_HEADER_PADDING_LEN 16 #define CW_TRANSPORT_HEADER_PADDING_START 8 #define CW_TRANSPORT_HEADER_PADDING_LEN 24 #define BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL 1033 #define BINDING_MSG_ELEMENT_TYPE_WTP_QOS 1045 /**************************************************** * 2009 Update: * * Lengths Messages Element Definition * * Specified in the 802.11 binding * ****************************************************/ #define BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL_LENGTH 8 /**************************************************** * 2009 Update: * * Define Structure for OFDM contol * * Values Management * ****************************************************/ typedef struct { int currentChan; /* 16 Bit Value */ unsigned char BandSupport; unsigned int TIThreshold; } OFDMControlValues; typedef struct { unsigned char queueDepth; int cwMin; int cwMax; unsigned char AIFS; unsigned char dot1PTag; unsigned char DSCPTag; } WTPQosValues; typedef struct { WTPQosValues *qosValues; } bindingValues; /*---------------------------*/ typedef struct { char RSSI; char SNR; int dataRate; } CWBindingTransportHeaderValues; typedef struct { CWProtocolMessage *frame; CWBindingTransportHeaderValues *bindingValues; } CWBindingDataListElement; extern const int gMaxCAPWAPHeaderSizeBinding; CWBool CWAssembleDataMessage(CWProtocolMessage ** completeMsgPtr, int *fragmentsNumPtr, int PMTU, CWProtocolMessage * frame, CWBindingTransportHeaderValues * bindingValuesPtr, int is_crypted, int keepAlive); CWBool CWAssembleTransportHeaderBinding(CWProtocolMessage * transportHdrPtr, CWBindingTransportHeaderValues * valuesPtr); CWBool CWBindingCheckType(int elemType); CWBool CWParseTransportHeaderBinding(CWProtocolMessage * msgPtr, CWBindingTransportHeaderValues * valuesPtr); CWBool CWParseTransportHeaderMACAddress(CWProtocolMessage * msgPtr,unsigned char *mac_ptr); #endif ================================================ FILE: CWCommon.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif int gCWForceMTU = 0; int gCWRetransmitTimer = CW_RETRANSMIT_INTERVAL_DEFAULT; //Default value for RetransmitInterval int gCWNeighborDeadInterval = CW_NEIGHBORDEAD_INTERVAL_DEFAULT; //Default value for NeighbourDeadInterval (no less than 2*EchoInterval and no greater than 240) int gCWMaxRetransmit = CW_MAX_RETRANSMIT_DEFAULT; //Default value for MaxRetransmit int CWTimevalSubtract(struct timeval *res, const struct timeval *x, const struct timeval *y) { int nsec; struct timeval z = *y; // Perform the carry for the later subtraction by updating Y if (x->tv_usec < z.tv_usec) { nsec = (z.tv_usec - x->tv_usec) / 1000000 + 1; z.tv_usec -= 1000000 * nsec; z.tv_sec += nsec; } if (x->tv_usec - z.tv_usec > 1000000) { nsec = (x->tv_usec - z.tv_usec) / 1000000; z.tv_usec += 1000000 * nsec; z.tv_sec -= nsec; } // Compute the time remaining to wait. `tv_usec' is certainly positive if (res != NULL) { res->tv_sec = x->tv_sec - z.tv_sec; res->tv_usec = x->tv_usec - z.tv_usec; } // Return 1 if result is negative (x < y) return ((x->tv_sec < z.tv_sec) || ((x->tv_sec == z.tv_sec) && (x->tv_usec < z.tv_usec))); } ================================================ FILE: CWCommon.h ================================================ /******************************************************************************************* * Copyright (c) 2006-9 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWCommon_HEADER__ #define __CAPWAP_CWCommon_HEADER__ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MACOSX #include #else #include #endif #include #include #include #include #include "wireless_copy.h" // make sure the types really have the right sizes #define CW_COMPILE_TIME_ASSERT(name, x) typedef int CWDummy_ ## name[(x) * 2 - 1] // if you get a compile error, change types (NOT VALUES!) according to your system CW_COMPILE_TIME_ASSERT(int_size, sizeof(int) == 4); CW_COMPILE_TIME_ASSERT(char_size, sizeof(char) == 1); #define CW_BUFFER_SIZE 65536 #define CW_ZERO_MEMORY bzero #define CW_COPY_MEMORY(dst, src, len) bcopy(src, dst, len) #define CW_REPEAT_FOREVER while(1) #define DEFAULT_LOG_SIZE 1000000 typedef enum { CW_FALSE = 0, CW_TRUE = 1 } CWBool; typedef enum { CW_ENTER_SULKING, CW_ENTER_DISCOVERY, CW_ENTER_JOIN, CW_ENTER_CONFIGURE, CW_ENTER_DATA_CHECK, CW_ENTER_RUN, CW_ENTER_RESET, CW_QUIT } CWStateTransition; extern const char *CW_CONFIG_FILE; extern int gCWForceMTU; extern int gCWRetransmitTimer; extern int gCWNeighborDeadInterval; extern int gCWMaxRetransmit; extern int gMaxLogFileSize; extern int gEnabledLog; extern int gCWDiscoveryCount; #define CW_FREE_OBJECT(obj_name) {if(obj_name){free((obj_name)); (obj_name) = NULL;}} #define CW_FREE_OBJECTS_ARRAY(ar_name, ar_size) {int _i = 0; for(_i = ((ar_size)-1); _i >= 0; _i--) {if(((ar_name)[_i]) != NULL){ free((ar_name)[_i]);}} free(ar_name); (ar_name) = NULL; } #define CW_PRINT_STRING_ARRAY(ar_name, ar_size) {int i = 0; for(i = 0; i < (ar_size); i++) printf("[%d]: **%s**\n", i, ar_name[i]);} // custom error #define CW_CREATE_OBJECT_ERR(obj_name, obj_type, on_err) {obj_name = (obj_type*) (malloc(sizeof(obj_type))); if(!(obj_name)) {on_err}} #define CW_CREATE_OBJECT_SIZE_ERR(obj_name, obj_size,on_err) {obj_name = (malloc(obj_size)); if(!(obj_name)) {on_err}} #define CW_CREATE_ARRAY_ERR(ar_name, ar_size, ar_type, on_err) {ar_name = (ar_type*) (malloc(sizeof(ar_type) * (ar_size))); if(!(ar_name)) {on_err}} #define CW_CREATE_STRING_ERR(str_name, str_length, on_err) {str_name = (char*) (malloc(sizeof(char) * ((str_length)+1) ) ); if(!(str_name)) {on_err}} #define CW_CREATE_STRING_FROM_STRING_ERR(str_name, str, on_err) {CW_CREATE_STRING_ERR(str_name, strlen(str), on_err); strcpy((str_name), str);} #ifdef CW_DEBUGGING #define CW_CREATE_ARRAY_ERR2(ar_name, ar_size, ar_type, on_err) {ar_name = (ar_type*) (malloc(sizeof(ar_type) * (ar_size))); if((ar_name)) {on_err}} #define CW_CREATE_OBJECT_ERR2(obj_name, obj_type, on_err) {obj_name = (obj_type*) (malloc(sizeof(obj_type))); if((obj_name)) {on_err}} #define CW_CREATE_OBJECT_SIZE_ERR2(obj_name, obj_size,on_err) {obj_name = (malloc(obj_size)); if((obj_name)) {on_err}} #define CW_CREATE_STRING_ERR2(str_name, str_length, on_err) {str_name = (char*) (malloc(sizeof(char) * ((str_length)+1) ) ); if((str_name)) {on_err}} #define CW_CREATE_STRING_FROM_STRING_ERR2(str_name, str, on_err) {CW_CREATE_STRING_ERR2(str_name, strlen(str), on_err); strcpy((str_name), str);} #endif #include "CWStevens.h" #include "config.h" #include "CWLog.h" #include "CWErrorHandling.h" #include "CWRandom.h" //#include "CWTimer.h" #include "timerlib.h" #include "CWThread.h" #include "CWNetwork.h" #include "CWList.h" #include "CWSafeList.h" #include "CWProtocol.h" #include "CWSecurity.h" #include "CWConfigFile.h" int CWTimevalSubtract(struct timeval *res, const struct timeval *x, const struct timeval *y); CWBool CWParseSettingsFile(); void CWErrorHandlingInitLib(); #endif ================================================ FILE: CWConfigFile.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif FILE *gCWConfigFile = NULL; CWConfigValue *gConfigValues; int gConfigValuesCount; /* * Replacement for std fgets which seems to dislike windows return character */ char *CWFgets(char *buf, int bufSize, FILE * f) { int i = -1; if (buf == NULL || f == NULL || bufSize <= 0) return NULL; CW_ZERO_MEMORY(buf, bufSize); do { i++; buf[i] = getc(f); if (buf[i] == EOF) { i--; break; } } while (i < bufSize && buf[i] != '\n' && buf[i] != '\r'); if (i == -1) return NULL; i++; buf[i] = '\0'; return buf; } /* * Get one "useful" (not a comment, not blank) line from the config file */ char *CWGetCommand(FILE * configFile) { char *buff = NULL; char *command = NULL; char *ret = NULL; CW_CREATE_STRING_ERR(buff, CW_BUFFER_SIZE, return NULL; ); /* skip comments and blank lines */ while (((ret = CWFgets(buff, CW_BUFFER_SIZE, configFile)) != NULL) && (buff[0] == '\n' || buff[0] == '\r' || buff[0] == '#')) ; if (buff != NULL && ret != NULL) { int len = strlen(buff); buff[len - 1] = '\0'; /* remove newline */ CW_CREATE_STRING_ERR(command, len - 1, return NULL; ); strcpy(command, buff); } CW_FREE_OBJECT(buff); return command; } /* * Parses the configuration file. * * Params: isCount CW_TRUE to just count ACAddresses and paths; * CW_FALSE to actually parse them. * * Return: CW_TRUE if the operation is succesful; CW_FALSE otherwise. */ CWBool CWParseTheFile(CWBool isCount) { char *line = NULL; int i; if (!isCount) { for (i = 0; i < gConfigValuesCount; i++) { if (gConfigValues[i].type == CW_STRING_ARRAY) { /* avoid to allocate 0 bytes */ if (gConfigValues[i].count) { CW_CREATE_ARRAY_ERR((gConfigValues[i].value.str_array_value), gConfigValues[i].count, char *, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } } } } else { for (i = 0; i < gConfigValuesCount; i++) { if (gConfigValues[i].type == CW_STRING_ARRAY) { gConfigValues[i].count = 0; } } } gCWConfigFile = fopen(CW_CONFIG_FILE, "rb"); if (gCWConfigFile == NULL) CWErrorRaiseSystemError(CW_ERROR_GENERAL); while ((line = CWGetCommand(gCWConfigFile)) != NULL) { int i, j; CWDebugLog("*** Parsing (%s) ***", line); for (i = 0; i < gConfigValuesCount; i++) { if (!strncmp(line, gConfigValues[i].code, strlen(gConfigValues[i].code))) { char *myLine = line + strlen(gConfigValues[i].code); switch (gConfigValues[i].type) { case CW_INTEGER: gConfigValues[i].value.int_value = atoi(myLine); break; case CW_STRING: /* * BUG - LE02 * If this function was called just to count ACAddresses and * paths, we MUST NOT allocate a string value; the actual allocation * will be performed when the function is called with the isCount * argument = CW_FALSE. * * 19/10/2009 - Donato Capitella */ if (!isCount) CW_CREATE_STRING_FROM_STRING_ERR(gConfigValues[i].value.str_value, myLine, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); break; case CW_STRING_ARRAY: #ifdef CW_DEBUGGING CWDebugLog("*** Parsing String Array... *** \n"); #endif j = 0; CW_FREE_OBJECT(line); while ((line = CWGetCommand(gCWConfigFile)) != NULL && strcmp(line, gConfigValues[i].endCode)) { #ifdef CW_DEBUGGING CWDebugLog("*** Parsing String (%s) *** \n", line); #endif if (isCount) gConfigValues[i].count++; else { CW_CREATE_STRING_FROM_STRING_ERR((gConfigValues[i].value. str_array_value)[j], line, return CWErrorRaise (CW_ERROR_OUT_OF_MEMORY, NULL); ); j++; } CW_FREE_OBJECT(line); } break; } break; } } CW_FREE_OBJECT(line); } CWDebugLog("*** Config File Parsed ***"); fclose(gCWConfigFile); return CW_TRUE; } /* parses the configuration file */ CWBool CWParseConfigFile() { if (!(CWConfigFileInitLib())) return CW_FALSE; /* just count the objects */ if (!CWParseTheFile(CW_TRUE)) return CW_FALSE; /* actually parse */ if (!CWParseTheFile(CW_FALSE)) return CW_FALSE; #ifdef CW_DEBUGGING { int i; for (i = 0; i < gConfigValuesCount; i++) { if (gConfigValues[i].type == CW_INTEGER) { CWLog("%s%d", gConfigValues[i].code, gConfigValues[i].value.int_value); } } } CWDebugLog("*** Config File END ***"); #endif return CWConfigFileDestroyLib(); } ================================================ FILE: CWConfigFile.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWConfigFile_HEADER__ #define __CAPWAP_CWConfigFile_HEADER__ typedef char **CWStringArray; typedef struct { enum { CW_INTEGER, CW_STRING, CW_STRING_ARRAY } type; union { int int_value; char *str_value; char **str_array_value; } value; char *code; char *endCode; int count; } CWConfigValue; extern CWConfigValue *gConfigValues; extern int gConfigValuesCount; CWBool CWParseConfigFile(); char *CWGetCommand(FILE * configFile); CWBool CWConfigFileInitLib(void); CWBool CWConfigFileDestroyLib(void); #endif ================================================ FILE: CWErrorHandling.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #ifndef CW_SINGLE_THREAD CWThreadSpecific gLastError; //CWThreadOnce gInitLastErrorOnce = CW_THREAD_ONCE_INIT; #else static CWErrorHandlingInfo *gLastErrorDataPtr; #endif void CWErrorHandlingInitLib() { CWDebugLog("Init Errors "); #ifndef CW_SINGLE_THREAD if (!CWThreadCreateSpecific(&gLastError, NULL)) { CWLog("Critical Error, closing the process..."); exit(1); } #else CW_CREATE_OBJECT_ERR(infoPtr, CWErrorHandlingInfo, return; ); infoPtr->code = CW_ERROR_NONE; gLastErrorDataPtr = infoPtr; #endif } CWBool _CWErrorRaise(CWErrorCode code, const char *msg, const char *fileName, int line) { CWErrorHandlingInfo *infoPtr; #ifndef CW_SINGLE_THREAD infoPtr = CWThreadGetSpecific(&gLastError); if (infoPtr == NULL) { CW_CREATE_OBJECT_ERR(infoPtr, CWErrorHandlingInfo, exit(1); ); infoPtr->code = CW_ERROR_NONE; if (!CWThreadSetSpecific(&gLastError, infoPtr)) { CWLog("Critical Error, closing the process..."); exit(1); } } #else infoPtr = gLastErrorDataPtr; #endif if (infoPtr == NULL) { CWLog("Critical Error: something strange has happened, closing the process..."); exit(1); } infoPtr->code = code; if (msg != NULL) strcpy(infoPtr->message, msg); else infoPtr->message[0] = '\0'; if (fileName != NULL) strcpy(infoPtr->fileName, fileName); infoPtr->line = line; return CW_FALSE; } void CWErrorPrint(CWErrorHandlingInfo * infoPtr, const char *desc, const char *fileName, int line) { if (infoPtr == NULL) return; if (infoPtr->message != NULL && infoPtr->message[0] != '\0') { CWLog("Error: %s. %s .", desc, infoPtr->message); } else { CWLog("Error: %s", desc); } CWLog("(occurred at line %d in file %s, catched at line %d in file %s).", infoPtr->line, infoPtr->fileName, line, fileName); } CWErrorCode CWErrorGetLastErrorCode() { CWErrorHandlingInfo *infoPtr; #ifndef CW_SINGLE_THREAD infoPtr = CWThreadGetSpecific(&gLastError); #else infoPtr = gLastErrorDataPtr; #endif if (infoPtr == NULL) return CW_ERROR_GENERAL; return infoPtr->code; } CWBool _CWErrorHandleLast(const char *fileName, int line) { CWErrorHandlingInfo *infoPtr; #ifndef CW_SINGLE_THREAD infoPtr = CWThreadGetSpecific(&gLastError); #else infoPtr = gLastErrorDataPtr; #endif if (infoPtr == NULL) { CWLog("No Error Pending"); exit((3)); return CW_FALSE; } #define __CW_ERROR_PRINT(str) CWErrorPrint(infoPtr, (str), fileName, line) switch (infoPtr->code) { case CW_ERROR_SUCCESS: case CW_ERROR_NONE: return CW_TRUE; break; case CW_ERROR_OUT_OF_MEMORY: __CW_ERROR_PRINT("Out of Memory"); #ifndef CW_SINGLE_THREAD CWExitThread(); // note: we can manage this on per-thread basis: ex. we can // kill some other thread if we are a manager thread. #else exit(1); #endif break; case CW_ERROR_WRONG_ARG: __CW_ERROR_PRINT("Wrong Arguments in Function"); break; case CW_ERROR_NEED_RESOURCE: __CW_ERROR_PRINT("Missing Resource"); break; case CW_ERROR_GENERAL: __CW_ERROR_PRINT("Error Occurred"); break; case CW_ERROR_CREATING: __CW_ERROR_PRINT("Error Creating Resource"); break; case CW_ERROR_SENDING: __CW_ERROR_PRINT("Error Sending"); break; case CW_ERROR_RECEIVING: __CW_ERROR_PRINT("Error Receiving"); break; case CW_ERROR_INVALID_FORMAT: __CW_ERROR_PRINT("Invalid Format"); break; case CW_ERROR_INTERRUPTED: default: break; } return CW_FALSE; } ================================================ FILE: CWErrorHandling.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWErrorHandling_HEADER__ #define __CAPWAP_CWErrorHandling_HEADER__ typedef enum { CW_ERROR_SUCCESS = 1, CW_ERROR_OUT_OF_MEMORY, CW_ERROR_WRONG_ARG, CW_ERROR_INTERRUPTED, CW_ERROR_NEED_RESOURCE, CW_ERROR_COMUNICATING, CW_ERROR_CREATING, CW_ERROR_GENERAL, CW_ERROR_OPERATION_ABORTED, CW_ERROR_SENDING, CW_ERROR_RECEIVING, CW_ERROR_INVALID_FORMAT, CW_ERROR_TIME_EXPIRED, CW_ERROR_NONE } CWErrorCode; typedef struct { CWErrorCode code; char message[256]; int line; char fileName[64]; } CWErrorHandlingInfo; #define CWErrorRaiseSystemError(error) { \ char buf[256]; \ strerror_r(errno, buf, 256); \ CWErrorRaise(error, buf); \ return CW_FALSE; \ } #define CWErrorRaise(code, msg) _CWErrorRaise(code, msg, __FILE__, __LINE__) #define CWErr(arg) ((arg) || _CWErrorHandleLast(__FILE__, __LINE__)) #define CWErrorHandleLast() _CWErrorHandleLast(__FILE__, __LINE__) CWBool _CWErrorRaise(CWErrorCode code, const char *msg, const char *fileName, int line); void CWErrorPrint(CWErrorHandlingInfo * infoPtr, const char *desc, const char *fileName, int line); CWErrorCode CWErrorGetLastErrorCode(void); CWBool _CWErrorHandleLast(const char *fileName, int line); #endif ================================================ FILE: CWFreqPayloads.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_Freq_Payloads__ #define __CAPWAP_Freq_Payloads__ #define CW_FREQ_CELL_INFO_PAYLOAD_SIZE 65 #define CW_FREQ_ACK_SIZE 8 #endif ================================================ FILE: CWList.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif // adds an element at the head of the list // CW_TRUE if the operation is successful, CW_FALSE otherwise CWBool CWAddElementToList(CWList * list, void *element) { CWListElement *newElem; if (element == NULL || list == NULL) return CW_FALSE; if ((*list) == NULL) { // first element CW_CREATE_OBJECT_ERR((*list), CWListElement, return CW_FALSE; ); (*list)->data = element; (*list)->next = NULL; return CW_TRUE; } CW_CREATE_OBJECT_ERR(newElem, CWListElement, return CW_FALSE; ); newElem->data = element; newElem->next = (*list); (*list) = newElem; return CW_TRUE; } // adds an element at the tail of the list // CW_TRUE if the operation is successful, CW_FALSE otherwise CWBool CWAddElementToListTail(CWList * list, void *element) { CWListElement *newElem; if (element == NULL || list == NULL) return CW_FALSE; if ((*list) == NULL) { // first element CW_CREATE_OBJECT_ERR((*list), CWListElement, return CW_FALSE; ); (*list)->data = element; (*list)->next = NULL; return CW_TRUE; } newElem = *list; while (newElem->next != NULL) { newElem = newElem->next; } CW_CREATE_OBJECT_ERR(newElem->next, CWListElement, return CW_FALSE; ); newElem->next->data = element; newElem->next->next = NULL; return CW_TRUE; } CWList CWListGetFirstElem(CWList * list) { CWList auxList; if (list == NULL || *list == NULL) return NULL; auxList = *list; *list = (*list)->next; auxList->next = NULL; return auxList; } // not thread safe! void *CWListGetNext(CWList list, CWListIterateMode mode) { static CWList l = NULL; void *data; if (list == NULL) return NULL; if (mode == CW_LIST_ITERATE_RESET) { l = list; } else if (l == NULL) return NULL; data = l->data; l = l->next; return data; } // search baseElement in list using compareFunc // NULL if there was an error, the element otherwise void *CWSearchInList(CWList list, void *baseElement, CWBool(*compareFunc) (void *, void *)) { CWListElement *el = NULL; if (baseElement == NULL || compareFunc == NULL) return NULL; for (el = list; el != NULL; el = el->next) { if (compareFunc(baseElement, el->data)) { return el->data; } } return NULL; } // search baseElement in list using compareFunc, removes the element from the list and returns it // NULL if there was an error, the element otherwise void *CWDeleteInList(CWList * list, void *baseElement, CWBool(*compareFunc) (void *, void *)) { CWListElement *el = NULL, *oldEl = NULL; if (baseElement == NULL || compareFunc == NULL || list == NULL) return NULL; for (el = (*list); el != NULL; oldEl = el, el = el->next) { if (compareFunc(baseElement, el->data)) { void *data = el->data; if (oldEl != NULL) { oldEl->next = el->next; CW_FREE_OBJECT(el); return data; } else { // first element (*list) = el->next; CW_FREE_OBJECT(el); return data; } } } return NULL; } // deletes a list, deleting each element with a call to the given deleteFunc void CWDeleteList(CWList * list, void (*deleteFunc) (void *)) { CWListElement *el = NULL; if (list == NULL || (*list) == NULL || deleteFunc == NULL) return; do { el = (*list); (*list) = (*list)->next; deleteFunc(el->data); CW_FREE_OBJECT(el); } while ((*list) != NULL); } int CWCountElementInList(CWList list) { CWListElement *current; int count = 0; current = list; while (current != NULL) { count++; current = current->next; } return count; } /* CWList *FindLastElementInList (CWList list) { CWListElement *current; current=list; while (current!= NULL) {current= current->next;} return ¤t; } */ ================================================ FILE: CWList.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWList_HEADER__ #define __CAPWAP_CWList_HEADER__ #define CW_LIST_INIT NULL typedef struct _s { void *data; struct _s *next; } CWListElement; typedef enum { CW_LIST_ITERATE_RESET, CW_LIST_ITERATE } CWListIterateMode; typedef CWListElement *CWList; CWBool CWAddElementToList(CWList * list, void *element); CWBool CWAddElementToListTail(CWList * list, void *element); CWList CWListGetFirstElem(CWList * list); void *CWListGetNext(CWList list, CWListIterateMode mode); void *CWSearchInList(CWList list, void *baseElement, CWBool(*compareFunc) (void *, void *)); void *CWDeleteInList(CWList * list, void *baseElement, CWBool(*compareFunc) (void *, void *)); void CWDeleteList(CWList * list, void (*deleteFunc) (void *)); int CWCountElementInList(CWList list); //CWList * FindLastElementInList (CWList list); #endif ================================================ FILE: CWLog.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" //#define WRITE_STD_OUTPUT 1 #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif static FILE *gLogFile = NULL; #ifndef CW_SINGLE_THREAD CWThreadMutex gFileMutex; #endif void CWLogInitFile(char *fileName) { if (fileName == NULL) { CWLog("Wrong File Name for Log File"); } if ((gLogFile = fopen(fileName, "w")) == NULL) { CWLog("Can't open log file: %s", strerror(errno)); exit(1); } #ifndef CW_SINGLE_THREAD if (!CWCreateThreadMutex(&gFileMutex)) { CWLog("Can't Init File Mutex for Log"); exit(1); } #endif } static CWBool checkResetFile() { long fileSize = 0; if ((fileSize = ftell(gLogFile)) == -1) { CWLog("An error with log file occurred: %s", strerror(errno)); return 0; } if (fileSize >= gMaxLogFileSize) { fclose(gLogFile); if ((gLogFile = fopen(gLogFileName, "w")) == NULL) { CWLog("Can't open log file: %s", strerror(errno)); return 0; } } return 1; } void CWLogCloseFile() { #ifndef CW_SINGLE_THREAD CWDestroyThreadMutex(&gFileMutex); #endif fclose(gLogFile); } void CWVLog(const char *format, va_list args) { char *logStr = NULL; time_t now; char *nowReadable = NULL; if (format == NULL) return; now = time(NULL); nowReadable = ctime(&now); nowReadable[strlen(nowReadable) - 1] = '\0'; // return in case of memory err: we're not performing a critical task CW_CREATE_STRING_ERR(logStr, (strlen(format) + strlen(nowReadable) + 100), return; ); //sprintf(logStr, "[CAPWAP::%s]\t\t %s\n", nowReadable, format); sprintf(logStr, "[CAPWAP::%s]\t%08x\t %s\n", nowReadable, (unsigned int)CWThreadSelf(), format); if (gLogFile != NULL) { char fileLine[256]; #ifndef CW_SINGLE_THREAD CWThreadMutexLock(&gFileMutex); fseek(gLogFile, 0L, SEEK_END); #endif vsnprintf(fileLine, 255, logStr, args); if (!checkResetFile()) { CWThreadMutexUnlock(&gFileMutex); exit(1); } fwrite(fileLine, strlen(fileLine), 1, gLogFile); fflush(gLogFile); #ifndef CW_SINGLE_THREAD CWThreadMutexUnlock(&gFileMutex); #endif } #ifdef WRITE_STD_OUTPUT //vprintf(logStr, args); #endif CW_FREE_OBJECT(logStr); } void CWLog(const char *format, ...) { va_list args; va_start(args, format); if (gEnabledLog) { CWVLog(format, args); } va_end(args); } void CWDebugLog(const char *format, ...) { #ifdef CW_DEBUGGING char *logStr = NULL; va_list args; time_t now; char *nowReadable = NULL; if (!gEnabledLog) { return; } if (format == NULL) { #ifdef WRITE_STD_OUTPUT printf("\n"); #endif return; } now = time(NULL); nowReadable = ctime(&now); nowReadable[strlen(nowReadable) - 1] = '\0'; // return in case of memory err: we're not performing a critical task CW_CREATE_STRING_ERR(logStr, (strlen(format) + strlen(nowReadable) + 100), return; ); //sprintf(logStr, "[[CAPWAP::%s]]\t\t %s\n", nowReadable, format); sprintf(logStr, "[CAPWAP::%s]\t%08x\t %s\n", nowReadable, (unsigned int)CWThreadSelf(), format); va_start(args, format); if (gLogFile != NULL) { char fileLine[256]; #ifndef CW_SINGLE_THREAD CWThreadMutexLock(&gFileMutex); fseek(gLogFile, 0L, SEEK_END); #endif vsnprintf(fileLine, 255, logStr, args); if (!checkResetFile()) { CWThreadMutexUnlock(&gFileMutex); exit(1); } fwrite(fileLine, strlen(fileLine), 1, gLogFile); fflush(gLogFile); #ifndef CW_SINGLE_THREAD CWThreadMutexUnlock(&gFileMutex); #endif } #ifdef WRITE_STD_OUTPUT vprintf(logStr, args); #endif va_end(args); CW_FREE_OBJECT(logStr); #endif } ================================================ FILE: CWLog.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWLog_HEADER__ #define __CAPWAP_CWLog_HEADER__ extern char gLogFileName[]; void CWVLog(const char *format, va_list args); void CWLog(const char *format, ...); void CWDebugLog(const char *format, ...); void CWLogInitFile(char *fileName); void CWLogCloseFile(); #endif ================================================ FILE: CWNetwork.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWNetworkLev3Service gNetworkPreferredFamily = CW_IPv4; /* * Assume address is valid */ __inline__ int CWNetworkGetAddressSize(CWNetworkLev4Address * addrPtr) { switch (((struct sockaddr *)(addrPtr))->sa_family) { #ifdef IPV6 /* IPv6 is defined in Stevens' library */ case AF_INET6: return sizeof(struct sockaddr_in6); break; #endif case AF_INET: default: return sizeof(struct sockaddr_in); } } /* * Send buf on an unconnected UDP socket. Unsafe means that we don't use DTLS. */ CWBool CWNetworkSendUnsafeUnconnected(CWSocket sock, CWNetworkLev4Address * addrPtr, unsigned char *buf, int len) { if (buf == NULL || addrPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWUseSockNtop(addrPtr, CWDebugLog(str); ); while (sendto(sock, buf, len, 0, (struct sockaddr *)addrPtr, CWNetworkGetAddressSize(addrPtr)) < 0) { if (errno == EINTR) continue; CWNetworkRaiseSystemError(CW_ERROR_SENDING); } return CW_TRUE; } /* * Send buf on a "connected" UDP socket. Unsafe means that we don't use DTLS. */ CWBool CWNetworkSendUnsafeConnected(CWSocket sock, unsigned char *buf, int len) { if (buf == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); while (send(sock, buf, len, 0) < 0) { if (errno == EINTR) continue; CWNetworkRaiseSystemError(CW_ERROR_SENDING); } return CW_TRUE; } /* * Receive a datagram on an connected UDP socket (blocking). * Unsafe means that we don't use DTLS. */ CWBool CWNetworkReceiveUnsafeConnected(CWSocket sock, unsigned char *buf, int len, int *readBytesPtr) { if (buf == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); while ((*readBytesPtr = recv(sock, buf, len, 0)) < 0) { if (errno == EINTR) continue; CWNetworkRaiseSystemError(CW_ERROR_RECEIVING); } return CW_TRUE; } /* * Receive a datagram on an unconnected UDP socket (blocking). * Unsafe means that we don't use DTLS. */ CWBool CWNetworkReceiveUnsafe(CWSocket sock, unsigned char *buf, int len, int flags, CWNetworkLev4Address * addrPtr, int *readBytesPtr) { socklen_t addrLen = sizeof(CWNetworkLev4Address); if (buf == NULL || addrPtr == NULL || readBytesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); while ((*readBytesPtr = recvfrom(sock, buf, len, flags, (struct sockaddr *)addrPtr, &addrLen)) < 0) { if (errno == EINTR) continue; CWNetworkRaiseSystemError(CW_ERROR_RECEIVING); } return CW_TRUE; } /* * Init network for client. */ CWBool CWNetworkInitSocketClient(CWSocket * sockPtr, CWNetworkLev4Address * addrPtr) { int yes = 1; #ifdef IPv6 struct sockaddr_in6 sockaddr; #else struct sockaddr_in sockaddr; #endif socklen_t addrlen = sizeof(sockaddr); if (sockPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #ifdef IPv6 if (((*sockPtr) = socket((gNetworkPreferredFamily == CW_IPv4) ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #else if (((*sockPtr) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #endif CWNetworkRaiseSystemError(CW_ERROR_CREATING); } memset(&sockaddr, 0, addrlen); #ifdef IPv6 sockaddr.sin6_family = (gNetworkPreferredFamily == CW_IPv4) ? AF_INET : AF_INET6; #else sockaddr.sin_family = AF_INET; #endif if (bind(*sockPtr, (const struct sockaddr *)&sockaddr, addrlen) < 0) { close(*sockPtr); CWDebugLog("failed to bind Client socket in <%s> line:%d.\n", __func__, __LINE__); return CW_FALSE; } if (getsockname(*sockPtr, (struct sockaddr *)&sockaddr, &addrlen) < 0) CWNetworkRaiseSystemError(CW_ERROR_GENERAL); #ifdef IPv6 CWLog("Created Client socket on %s UDP port %d\n", sockaddr.sin6_family == AF_INET6 ? "IPv6" : "IPv4", sockaddr.sin6_port); #else CWLog("Created Client socket on IPv4 UDP port %d\n", sockaddr.sin_port); #endif /* NULL addrPtr means that we don't want to connect to a * specific address */ if (addrPtr != NULL) { CWUseSockNtop(((struct sockaddr *)addrPtr), CWDebugLog(str); ); if (connect((*sockPtr), ((struct sockaddr *)addrPtr), CWNetworkGetAddressSize(addrPtr)) < 0) { CWNetworkRaiseSystemError(CW_ERROR_CREATING); } } /* allow sending broadcast packets */ setsockopt(*sockPtr, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)); return CW_TRUE; } /* * Init data channel network for client */ CWBool CWNetworkInitSocketClientDataChannel(CWSocket * sockPtr, CWNetworkLev4Address * addrPtr) { #ifdef IPv6 struct sockaddr_in6 sockaddr; #else struct sockaddr_in sockaddr; #endif socklen_t addrlen = sizeof(sockaddr); CWNetworkLev4Address addrPtrDataChannel; if (sockPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #ifdef IPv6 if (((*sockPtr) = socket((gNetworkPreferredFamily == CW_IPv4) ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #else if (((*sockPtr) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #endif CWNetworkRaiseSystemError(CW_ERROR_CREATING); } memset(&sockaddr, 0, addrlen); #ifdef IPv6 sockaddr.sin6_family = (gNetworkPreferredFamily == CW_IPv4) ? AF_INET : AF_INET6; #else sockaddr.sin_family = AF_INET; //sockaddr.sin_port = htons(CW_DATA_PORT); #endif if (bind(*sockPtr, (const struct sockaddr *)&sockaddr, addrlen) < 0) { close(*sockPtr); CWDebugLog("failed to bind Client socket in <%s> line:%d.\n", __func__, __LINE__); return CW_FALSE; } if (getsockname(*sockPtr, (struct sockaddr *)&sockaddr, &addrlen) < 0) CWNetworkRaiseSystemError(CW_ERROR_GENERAL); #ifdef IPv6 CWLog("Created Client socket on %s UDP data port %d\n", sockaddr.sin6_family == AF_INET6 ? "IPv6" : "IPv4", sockaddr.sin6_port); #else CWLog("Created Client socket on IPv4 UDP data port %d\n", sockaddr.sin_port); #endif /* NULL addrPtr means that we don't want to connect to a * specific address */ if (addrPtr != NULL) { CW_COPY_NET_ADDR_PTR(&addrPtrDataChannel, addrPtr); sock_set_port_cw((struct sockaddr *)&addrPtrDataChannel, htons(CW_DATA_PORT)); CWUseSockNtop((struct sockaddr *)&addrPtrDataChannel, CWDebugLog(str); ); if (connect ((*sockPtr), (struct sockaddr *)&addrPtrDataChannel, CWNetworkGetAddressSize(&addrPtrDataChannel)) < 0) { CWNetworkRaiseSystemError(CW_ERROR_CREATING); } } return CW_TRUE; } /* * Wrapper for select */ CWBool CWNetworkTimedPollRead(CWSocket sock, struct timeval * timeout) { int r; fd_set fset; if (timeout == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); FD_ZERO(&fset); FD_SET(sock, &fset); if ((r = select(sock + 1, &fset, NULL, NULL, timeout)) == 0) { CWDebugLog("Select Time Expired"); return CWErrorRaise(CW_ERROR_TIME_EXPIRED, NULL); } else if (r < 0) { CWDebugLog("Select Error"); if (errno == EINTR) { CWDebugLog("Select Interrupted by signal"); return CWErrorRaise(CW_ERROR_INTERRUPTED, NULL); } CWNetworkRaiseSystemError(CW_ERROR_GENERAL); } return CW_TRUE; } /* * Given an host int the form of C string (e.g. "192.168.1.2" or "localhost"), * returns the address. */ CWBool CWNetworkGetAddressForHost(char *host, CWNetworkLev4Address * addrPtr) { struct addrinfo hints, *res, *ressave; char serviceName[5]; CWSocket sock; if (host == NULL || addrPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_ZERO_MEMORY(&hints, sizeof(struct addrinfo)); #ifdef IPv6 if (gNetworkPreferredFamily == CW_IPv6) { hints.ai_family = AF_INET6; hints.ai_flags = AI_V4MAPPED; } else { hints.ai_family = AF_INET; } #else hints.ai_family = AF_INET; #endif hints.ai_socktype = SOCK_DGRAM; /* endianness will be handled by getaddrinfo */ snprintf(serviceName, 5, "%d", CW_CONTROL_PORT); if (getaddrinfo(host, serviceName, &hints, &res) != 0) { return CWErrorRaise(CW_ERROR_GENERAL, "Can't resolve hostname"); } ressave = res; do { if ((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) { /* try next address */ continue; } /* success */ break; } while ((res = res->ai_next) != NULL); close(sock); if (res == NULL) { /* error on last iteration */ CWNetworkRaiseSystemError(CW_ERROR_CREATING); } CW_COPY_NET_ADDR_PTR(addrPtr, (res->ai_addr)); freeaddrinfo(ressave); return CW_TRUE; } ================================================ FILE: CWNetwork.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWNetwork_HEADER__ #define __CAPWAP_CWNetwork_HEADER__ #include #include #include #include #include #include #include "CWStevens.h" typedef int CWSocket; typedef struct sockaddr_storage CWNetworkLev4Address; typedef enum { CW_IPv6, CW_IPv4 } CWNetworkLev3Service; extern CWNetworkLev3Service gNetworkPreferredFamily; #define CW_COPY_NET_ADDR_PTR(addr1, addr2) sock_cpy_addr_port(((struct sockaddr*)(addr1)), ((struct sockaddr*)(addr2))) #define CW_COPY_NET_ADDR(addr1, addr2) CW_COPY_NET_ADDR_PTR(&(addr1), &(addr2)) #define CWUseSockNtop(sa, block) { \ char __str[128]; \ char *str; str = sock_ntop_r(((struct sockaddr*)(sa)), __str);\ {block} \ } #define CWNetworkRaiseSystemError(error) { \ char buf[256]; \ if(strerror_r(errno, buf, 256) < 0) { \ CWErrorRaise(error, NULL); \ return CW_FALSE; \ } \ CWErrorRaise(error, NULL); \ return CW_FALSE; \ } #define CWNetworkCloseSocket(x) { shutdown(SHUT_RDWR, x); close(x); } int CWNetworkGetAddressSize(CWNetworkLev4Address * addrPtr); CWBool CWNetworkSendUnsafeConnected(CWSocket sock, unsigned char *buf, int len); CWBool CWNetworkSendUnsafeUnconnected(CWSocket sock, CWNetworkLev4Address * addrPtr, unsigned char *buf, int len); CWBool CWNetworkReceiveUnsafe(CWSocket sock, unsigned char *buf, int len, int flags, CWNetworkLev4Address * addrPtr, int *readBytesPtr); CWBool CWNetworkReceiveUnsafeConnected(CWSocket sock, unsigned char *buf, int len, int *readBytesPtr); CWBool CWNetworkInitSocketClient(CWSocket * sockPtr, CWNetworkLev4Address * addrPtr); CWBool CWNetworkInitSocketClientDataChannel(CWSocket * sockPtr, CWNetworkLev4Address * addrPtr); CWBool CWNetworkTimedPollRead(CWSocket sock, struct timeval *timeout); CWBool CWNetworkGetAddressForHost(char *host, CWNetworkLev4Address * addrPtr); //CWBool CWNetworkInitLib(void); //CWBool CWNetworkInitSocketServer(CWSocket *sockPtr, int port); //CWBool CWNetworkSendUnsafeConnected(CWSocket sock, const char *buf, int len); #endif ================================================ FILE: CWOpenSSLBio.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif static int memory_write(BIO * h, const char *buf, int num); static int memory_read(BIO * h, char *buf, int size); static int memory_puts(BIO * h, const char *str); static long memory_ctrl(BIO * h, int cmd, long arg1, void *arg2); static int memory_new(BIO * h); static int memory_free(BIO * data); #ifndef IP_MTU #define IP_MTU 14 #endif typedef struct { CWSocket sock; CWNetworkLev4Address sendAddress; CWSafeList *pRecvAddress; unsigned int nMtu; } BIO_memory_data; static BIO_METHOD methods_memory = { BIO_TYPE_DGRAM, "memory packet", memory_write, memory_read, memory_puts, NULL, /* dgram_gets, */ memory_ctrl, memory_new, memory_free, NULL, }; BIO_METHOD *BIO_s_memory(void) { return (&methods_memory); } BIO *BIO_new_memory(CWSocket sock, CWNetworkLev4Address * pSendAddress, CWSafeList * pRecvAddress) { BIO *ret; BIO_memory_data *pData; ret = BIO_new(BIO_s_memory()); if (ret == NULL) return NULL; // pData = (BIO_memory_data *) ret->ptr; pData->sock = sock; memcpy(&pData->sendAddress, pSendAddress, sizeof(CWNetworkLev4Address)); pData->pRecvAddress = pRecvAddress; return ret; } static int memory_new(BIO * bi) { bi->init = 1; bi->num = 0; bi->flags = 0; bi->ptr = (char *)malloc(sizeof(BIO_memory_data)); return 1; } static int memory_free(BIO * a) { if (a == NULL) return 0; free(a->ptr); return 1; } static int memory_read(BIO * b, char *out, int outl) { int ret = -1; char *buf; int size; BIO_memory_data *pData = (BIO_memory_data *) b->ptr; // //BIO_clear_retry_flags(b); // CWLockSafeList(pData->pRecvAddress); // Used only in DTLS handshake while (CWGetCountElementFromSafeList(pData->pRecvAddress) == 0) { CWWaitElementFromSafeList(pData->pRecvAddress); } buf = (char *)CWRemoveHeadElementFromSafeList(pData->pRecvAddress, &size); CWUnlockSafeList(pData->pRecvAddress); if ((buf == NULL) || (size <= 0)) CWLog("Warning empty buffer"); else { ret = ((size < outl) ? size : outl) - 4; memcpy(out, buf + 4, ret); CW_FREE_OBJECT(buf); } return ret; } static int memory_write(BIO * b, const char *in, int inl) { int ret = -1; char strBuffer[MAX_UDP_PACKET_SIZE]; BIO_memory_data *pData = (BIO_memory_data *) b->ptr; // strBuffer[0] = (char)(CW_PROTOCOL_VERSION << 4) | (char)(CW_PACKET_CRYPT); strBuffer[1] = strBuffer[2] = strBuffer[3] = 0; // memcpy(&strBuffer[4], in, inl); // errno = 0; ret = sendto(pData->sock, strBuffer, inl + 4, 0, (struct sockaddr *)&pData->sendAddress, sizeof(struct sockaddr_storage)); //BIO_clear_retry_flags(b); if (ret <= 0) { if (errno == EINTR) BIO_set_retry_write(b); } else { ret -= 4; } return ret; } static long memory_ctrl(BIO * b, int cmd, long num, void *ptr) { long ret = 1; long sockopt_val = 0; unsigned int sockopt_len = 0; BIO_memory_data *pData = (BIO_memory_data *) b->ptr; switch (cmd) { case BIO_CTRL_RESET: ret = 0; break; case BIO_CTRL_EOF: ret = 0; break; case BIO_CTRL_INFO: ret = 0; break; case BIO_CTRL_GET_CLOSE: ret = 0; break; case BIO_CTRL_SET_CLOSE: break; case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_PENDING: ret = 0; break; case BIO_CTRL_DUP: ret = 1; break; case BIO_CTRL_FLUSH: ret = 1; break; case BIO_CTRL_PUSH: ret = 0; break; case BIO_CTRL_POP: ret = 0; case BIO_CTRL_DGRAM_QUERY_MTU:{ sockopt_len = sizeof(sockopt_val); if ((ret = getsockopt(pData->sock, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, &sockopt_len)) < 0 || sockopt_val < 0) { ret = 0; } else { pData->nMtu = sockopt_val; ret = sockopt_val; } break; } case BIO_CTRL_DGRAM_GET_MTU: ret = pData->nMtu; break; case BIO_CTRL_DGRAM_SET_MTU: pData->nMtu = num; ret = num; break; default: ret = 0; break; } return ret; } static int memory_puts(BIO * bp, const char *str) { return memory_write(bp, str, strlen(str)); } ================================================ FILE: CWProtocol.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #include "CWVendorPayloads.h" #include "WUM.h" pthread_mutex_t gRADIO_MAC_mutex; #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif static const int gCWIANATimes256 = CW_IANA_ENTERPRISE_NUMBER * 256; static const int gMaxDTLSHeaderSize = 25; // see http://crypto.stanford.edu/~nagendra/papers/dtls.pdf static const int gMaxCAPWAPHeaderSize = 8; // note: this include optional Wireless field unsigned char gRADIO_MAC[6]; // note: this include optional Wireless field // stores 8 bits in the message, increments the current offset in bytes void CWProtocolStore8(CWProtocolMessage * msgPtr, unsigned char val) { CW_COPY_MEMORY(&((msgPtr->msg)[(msgPtr->offset)]), &(val), 1); (msgPtr->offset) += 1; } // stores 16 bits in the message, increments the current offset in bytes void CWProtocolStore16(CWProtocolMessage * msgPtr, unsigned short val) { val = htons(val); CW_COPY_MEMORY(&((msgPtr->msg)[(msgPtr->offset)]), &(val), 2); (msgPtr->offset) += 2; } // stores 32 bits in the message, increments the current offset in bytes void CWProtocolStore32(CWProtocolMessage * msgPtr, unsigned int val) { val = htonl(val); CW_COPY_MEMORY(&((msgPtr->msg)[(msgPtr->offset)]), &(val), 4); (msgPtr->offset) += 4; } // stores a string in the message, increments the current offset in bytes. Doesn't store // the '\0' final character. void CWProtocolStoreStr(CWProtocolMessage * msgPtr, char *str) { int len = strlen(str); CW_COPY_MEMORY(&((msgPtr->msg)[(msgPtr->offset)]), str, len); (msgPtr->offset) += len; } // stores another message in the message, increments the current offset in bytes. void CWProtocolStoreMessage(CWProtocolMessage * msgPtr, CWProtocolMessage * msgToStorePtr) { CW_COPY_MEMORY(&((msgPtr->msg)[(msgPtr->offset)]), msgToStorePtr->msg, msgToStorePtr->offset); (msgPtr->offset) += msgToStorePtr->offset; } // stores len bytes in the message, increments the current offset in bytes. void CWProtocolStoreRawBytes(CWProtocolMessage * msgPtr, unsigned char *bytes, int len) { CW_COPY_MEMORY(&((msgPtr->msg)[(msgPtr->offset)]), bytes, len); (msgPtr->offset) += len; } // retrieves 8 bits from the message, increments the current offset in bytes. unsigned char CWProtocolRetrieve8(CWProtocolMessage * msgPtr) { unsigned char val; CW_COPY_MEMORY(&val, &((msgPtr->msg)[(msgPtr->offset)]), 1); (msgPtr->offset) += 1; return val; } // retrieves 16 bits from the message, increments the current offset in bytes. unsigned short CWProtocolRetrieve16(CWProtocolMessage * msgPtr) { unsigned short val; CW_COPY_MEMORY(&val, &((msgPtr->msg)[(msgPtr->offset)]), 2); (msgPtr->offset) += 2; return ntohs(val); } // retrieves 32 bits from the message, increments the current offset in bytes. unsigned int CWProtocolRetrieve32(CWProtocolMessage * msgPtr) { unsigned int val; CW_COPY_MEMORY(&val, &((msgPtr->msg)[(msgPtr->offset)]), 4); (msgPtr->offset) += 4; return ntohl(val); } // retrieves a string (not null-terminated) from the message, increments the current offset in bytes. // Adds the '\0' char at the end of the string which is returned char *CWProtocolRetrieveStr(CWProtocolMessage * msgPtr, int len) { char *str; CW_CREATE_OBJECT_SIZE_ERR(str, (len + 1), return NULL; ); CW_COPY_MEMORY(str, &((msgPtr->msg)[(msgPtr->offset)]), len); str[len] = '\0'; (msgPtr->offset) += len; return str; } // retrieves len bytes from the message, increments the current offset in bytes. unsigned char *CWProtocolRetrieveRawBytes(CWProtocolMessage * msgPtr, unsigned int len) { unsigned char *bytes; CW_CREATE_OBJECT_SIZE_ERR(bytes, len, return NULL; ); CW_COPY_MEMORY(bytes, &((msgPtr->msg)[(msgPtr->offset)]), len); (msgPtr->offset) += len; return bytes; } void CWProtocolDestroyMsgElemData(void *f) { CW_FREE_OBJECT(f); } // Assemble a Message Element creating the appropriate header and storing the message. CWBool CWAssembleMsgElem(CWProtocolMessage * msgPtr, unsigned int type) { CWProtocolMessage completeMsg; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(completeMsg, 6 + (msgPtr->offset), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // store header CWProtocolStore16(&completeMsg, type); CWProtocolStore16(&completeMsg, msgPtr->offset); // size of the body // store body CWProtocolStoreMessage(&completeMsg, msgPtr); CW_FREE_PROTOCOL_MESSAGE(*msgPtr); msgPtr->msg = completeMsg.msg; msgPtr->offset = completeMsg.offset; return CW_TRUE; } // Assembles the Transport Header CWBool CWAssembleTransportHeader(CWProtocolMessage * transportHdrPtr, CWProtocolTransportHeaderValues * valuesPtr) { char radio_mac_present = 0; int i; for (i = 0; i < 6; i++) { //printf(":::: %02X\n",gRADIO_MAC[i]); if (gRADIO_MAC[i] != 0) { radio_mac_present = 8; break; } } unsigned int val = 0; if (transportHdrPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (valuesPtr->bindingValuesPtr != NULL) { CW_CREATE_PROTOCOL_MESSAGE(*transportHdrPtr, gMaxCAPWAPHeaderSizeBinding + radio_mac_present, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } else { CW_CREATE_PROTOCOL_MESSAGE(*transportHdrPtr, 8 + radio_mac_present, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // meaningful bytes of the header (no wirless header and MAC address) } CWSetField32(val, CW_TRANSPORT_HEADER_VERSION_START, CW_TRANSPORT_HEADER_VERSION_LEN, CW_PROTOCOL_VERSION); // current version of CAPWAP CWSetField32(val, CW_TRANSPORT_HEADER_TYPE_START, CW_TRANSPORT_HEADER_TYPE_LEN, (valuesPtr->payloadType == CW_PACKET_PLAIN) ? 0 : 1); if (radio_mac_present) if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN, (CW_BINDING_HLEN + 2)); else CWSetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN, (2 + 2)); else if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN, CW_BINDING_HLEN); else CWSetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN, 2); CWSetField32(val, CW_TRANSPORT_HEADER_RID_START, CW_TRANSPORT_HEADER_RID_LEN, 0); // only one radio per WTP? CWSetField32(val, CW_TRANSPORT_HEADER_WBID_START, CW_TRANSPORT_HEADER_WBID_LEN, 1); // Wireless Binding ID if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_T_START, CW_TRANSPORT_HEADER_T_LEN, 1); else if (valuesPtr->type == 1) CWSetField32(val, CW_TRANSPORT_HEADER_T_START, CW_TRANSPORT_HEADER_T_LEN, 1); else CWSetField32(val, CW_TRANSPORT_HEADER_T_START, CW_TRANSPORT_HEADER_T_LEN, 0); CWSetField32(val, CW_TRANSPORT_HEADER_F_START, CW_TRANSPORT_HEADER_F_LEN, valuesPtr->isFragment); // is fragment CWSetField32(val, CW_TRANSPORT_HEADER_L_START, CW_TRANSPORT_HEADER_L_LEN, valuesPtr->last); // last fragment if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_W_START, CW_TRANSPORT_HEADER_W_LEN, 1); //wireless header else CWSetField32(val, CW_TRANSPORT_HEADER_W_START, CW_TRANSPORT_HEADER_W_LEN, 0); if (radio_mac_present) CWSetField32(val, CW_TRANSPORT_HEADER_M_START, CW_TRANSPORT_HEADER_M_LEN, 1); //radio MAC address else CWSetField32(val, CW_TRANSPORT_HEADER_M_START, CW_TRANSPORT_HEADER_M_LEN, 0); // no radio MAC address CWSetField32(val, CW_TRANSPORT_HEADER_K_START, CW_TRANSPORT_HEADER_K_LEN, 0); // Keep alive flag CWSetField32(val, CW_TRANSPORT_HEADER_FLAGS_START, CW_TRANSPORT_HEADER_FLAGS_LEN, 0); // required CWProtocolStore32(transportHdrPtr, val); // end of first 32 bits val = 0; CWSetField32(val, CW_TRANSPORT_HEADER_FRAGMENT_ID_START, CW_TRANSPORT_HEADER_FRAGMENT_ID_LEN, valuesPtr->fragmentID); // fragment ID CWSetField32(val, CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_START, CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_LEN, valuesPtr->fragmentOffset); // fragment offset CWSetField32(val, CW_TRANSPORT_HEADER_RESERVED_START, CW_TRANSPORT_HEADER_RESERVED_LEN, 0); // required CWProtocolStore32(transportHdrPtr, val); // end of second 32 bits if (radio_mac_present) { CWProtocolStore8(transportHdrPtr, 6); CWThreadMutexLock(&gRADIO_MAC_mutex); CWProtocolStoreRawBytes(transportHdrPtr, gRADIO_MAC, 6); CWThreadMutexUnlock(&gRADIO_MAC_mutex); CWProtocolStore8(transportHdrPtr, 0); } if (valuesPtr->bindingValuesPtr != NULL) { if (!CWAssembleTransportHeaderBinding(transportHdrPtr, valuesPtr->bindingValuesPtr)) return CW_FALSE; } return CW_TRUE; } // Assembles the Transport Header CWBool CWAssembleTransportHeaderKeepAliveData(CWProtocolMessage * transportHdrPtr, CWProtocolTransportHeaderValues * valuesPtr, int keepAlive) { unsigned int val = 0; if (transportHdrPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (valuesPtr->bindingValuesPtr != NULL) { CW_CREATE_PROTOCOL_MESSAGE(*transportHdrPtr, gMaxCAPWAPHeaderSizeBinding, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } else { CW_CREATE_PROTOCOL_MESSAGE(*transportHdrPtr, 8, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // meaningful bytes of the header (no wirless header and MAC address) } CWSetField32(val, CW_TRANSPORT_HEADER_VERSION_START, CW_TRANSPORT_HEADER_VERSION_LEN, CW_PROTOCOL_VERSION); // current version of CAPWAP CWSetField32(val, CW_TRANSPORT_HEADER_TYPE_START, CW_TRANSPORT_HEADER_TYPE_LEN, (valuesPtr->payloadType == CW_PACKET_PLAIN) ? 0 : 1); if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN, CW_BINDING_HLEN); else CWSetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN, 2); CWSetField32(val, CW_TRANSPORT_HEADER_RID_START, CW_TRANSPORT_HEADER_RID_LEN, 0); // only one radio per WTP? CWSetField32(val, CW_TRANSPORT_HEADER_WBID_START, CW_TRANSPORT_HEADER_WBID_LEN, 1); // Wireless Binding ID if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_T_START, CW_TRANSPORT_HEADER_T_LEN, 1); else CWSetField32(val, CW_TRANSPORT_HEADER_T_START, CW_TRANSPORT_HEADER_T_LEN, 0); CWSetField32(val, CW_TRANSPORT_HEADER_F_START, CW_TRANSPORT_HEADER_F_LEN, valuesPtr->isFragment); // is fragment CWSetField32(val, CW_TRANSPORT_HEADER_L_START, CW_TRANSPORT_HEADER_L_LEN, valuesPtr->last); // last fragment if (valuesPtr->bindingValuesPtr != NULL) CWSetField32(val, CW_TRANSPORT_HEADER_W_START, CW_TRANSPORT_HEADER_W_LEN, 1); //wireless header else CWSetField32(val, CW_TRANSPORT_HEADER_W_START, CW_TRANSPORT_HEADER_W_LEN, 0); CWSetField32(val, CW_TRANSPORT_HEADER_M_START, CW_TRANSPORT_HEADER_M_LEN, 0); // no radio MAC address CWSetField32(val, CW_TRANSPORT_HEADER_K_START, CW_TRANSPORT_HEADER_K_LEN, keepAlive); // Keep alive flag CWSetField32(val, CW_TRANSPORT_HEADER_FLAGS_START, CW_TRANSPORT_HEADER_FLAGS_LEN, 0); // required CWProtocolStore32(transportHdrPtr, val); // end of first 32 bits val = 0; CWSetField32(val, CW_TRANSPORT_HEADER_FRAGMENT_ID_START, CW_TRANSPORT_HEADER_FRAGMENT_ID_LEN, valuesPtr->fragmentID); // fragment ID CWSetField32(val, CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_START, CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_LEN, valuesPtr->fragmentOffset); // fragment offset CWSetField32(val, CW_TRANSPORT_HEADER_RESERVED_START, CW_TRANSPORT_HEADER_RESERVED_LEN, 0); // required CWProtocolStore32(transportHdrPtr, val); // end of second 32 bits if (valuesPtr->bindingValuesPtr != NULL) { if (!CWAssembleTransportHeaderBinding(transportHdrPtr, valuesPtr->bindingValuesPtr)) return CW_FALSE; } return CW_TRUE; } // Assembles the Control Header CWBool CWAssembleControlHeader(CWProtocolMessage * controlHdrPtr, CWControlHeaderValues * valPtr) { if (controlHdrPtr == NULL || valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*controlHdrPtr, 8, // meaningful bytes of the header return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore32(controlHdrPtr, valPtr->messageTypeValue); CWProtocolStore8(controlHdrPtr, valPtr->seqNum); CWProtocolStore16(controlHdrPtr, (CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS + (valPtr->msgElemsLen))); // 7 is for the next 8+32+16 bits (= 7 bytes), MessageElementsLength+flags + timestamp CWProtocolStore8(controlHdrPtr, 0); // flags //CWProtocolStore32(controlHdrPtr, ((unsigned int)(time(NULL))) ); // timestamp return CW_TRUE; } /*Update 2009: Attach a payload with a result code to the message */ CWBool CWAssembleVendorMsgElemResultCodeWithPayload(CWProtocolMessage * msgPtr, CWProtocolResultCode code, CWProtocolVendorSpecificValues * payload) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); int payloadSize = 0; CWVendorUciValues *uciPayload; CWVendorWumValues *wumPayload; uciPayload = (CWVendorUciValues *) payload->payload; wumPayload = (CWVendorWumValues *) payload->payload; switch (payload->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: wumPayload = NULL; if (uciPayload->response != NULL) payloadSize = (strlen(uciPayload->response) * sizeof(unsigned char)); break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: uciPayload = NULL; payloadSize = sizeof(unsigned char); /* default, only type */ if (wumPayload->type == WTP_VERSION_RESPONSE) payloadSize = sizeof(unsigned char) * 4; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Invalid vendorPayloadType"); } // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, (sizeof(unsigned short) * 2) + (sizeof(unsigned int) * 2) + payloadSize, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore32(msgPtr, code); // CWDebugLog("Result Code: %d", code); // switch (payload->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: /*Store what type of payload we have */ CWProtocolStore16(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE); /*Store what type of vendor payload we have */ CWProtocolStore16(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI); /*Store payload size */ CWProtocolStore32(msgPtr, payloadSize); if (uciPayload->response != NULL) /*Store the payload */ CWProtocolStoreStr(msgPtr, uciPayload->response); break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: /* Store what type of payload we have */ CWProtocolStore16(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE); /* Store what type of vendor payload we have */ CWProtocolStore16(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM); /* Store payload size */ CWProtocolStore32(msgPtr, payloadSize); CWProtocolStore8(msgPtr, wumPayload->type); if (wumPayload->type == WTP_VERSION_RESPONSE) { CWProtocolStore8(msgPtr, wumPayload->_major_v_); CWProtocolStore8(msgPtr, wumPayload->_minor_v_); CWProtocolStore8(msgPtr, wumPayload->_revision_v_); } break; } return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE_WITH_PAYLOAD); } CWBool CWAssembleMsgElemResultCode(CWProtocolMessage * msgPtr, CWProtocolResultCode code) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 4, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore32(msgPtr, code); // CWDebugLog("Result Code: %d", code); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE); } // Assemble a CAPWAP Control Packet, with the given Message Elements, Sequence Number and Message Type. Create Transport and Control Headers. // completeMsgPtr is an array of fragments (can be of size 1 if the packet doesn't need fragmentation CWBool CWAssembleMessage(CWProtocolMessage ** completeMsgPtr, int *fragmentsNumPtr, int PMTU, int seqNum, int msgTypeValue, CWProtocolMessage * msgElems, const int msgElemNum, CWProtocolMessage * msgElemsBinding, const int msgElemBindingNum) { CWDebugLog("CWAssembleMessage()"); CWProtocolMessage transportHdr, controlHdr, msg; int msgElemsLen = 0; int i; CWProtocolTransportHeaderValues transportVal; CWControlHeaderValues controlVal; if (completeMsgPtr == NULL || fragmentsNumPtr == NULL || (msgElems == NULL && msgElemNum > 0) || (msgElemsBinding == NULL && msgElemBindingNum > 0)) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); //Calculate the whole size of the Msg Elements for (i = 0; i < msgElemNum; i++) msgElemsLen += msgElems[i].offset; for (i = 0; i < msgElemBindingNum; i++) msgElemsLen += msgElemsBinding[i].offset; //Assemble Control Header controlVal.messageTypeValue = msgTypeValue; controlVal.msgElemsLen = msgElemsLen; controlVal.seqNum = seqNum; if (!(CWAssembleControlHeader(&controlHdr, &controlVal))) { CW_FREE_PROTOCOL_MESSAGE(controlHdr); for (i = 0; i < msgElemNum; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); for (i = 0; i < msgElemBindingNum; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElemsBinding[i]); } CW_FREE_OBJECT(msgElemsBinding); return CW_FALSE; // will be handled by the caller } // assemble the message putting all the data consecutively CW_CREATE_PROTOCOL_MESSAGE(msg, controlHdr.offset + msgElemsLen, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreMessage(&msg, &controlHdr); for (i = 0; i < msgElemNum; i++) { // store in the request all the Message Elements CWProtocolStoreMessage(&msg, &(msgElems[i])); } for (i = 0; i < msgElemBindingNum; i++) { // store in the request all the Message Elements CWProtocolStoreMessage(&msg, &(msgElemsBinding[i])); } //Free memory not needed anymore CW_FREE_PROTOCOL_MESSAGE(controlHdr); for (i = 0; i < msgElemNum; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); for (i = 0; i < msgElemBindingNum; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElemsBinding[i]); } CW_FREE_OBJECT(msgElemsBinding); CWDebugLog("PMTU: %d", PMTU); // handle fragmentation PMTU = PMTU - gMaxDTLSHeaderSize - gMaxCAPWAPHeaderSize; if (PMTU > 0) { PMTU = (PMTU / 8) * 8; // CAPWAP fragments are made of groups of 8 bytes if (PMTU == 0) goto cw_dont_fragment; CWDebugLog("Aligned PMTU: %d", PMTU); *fragmentsNumPtr = msg.offset / PMTU; if ((msg.offset % PMTU) != 0) (*fragmentsNumPtr)++; CWDebugLog("Fragments #: %d", *fragmentsNumPtr); } else { cw_dont_fragment: *fragmentsNumPtr = 1; } transportVal.bindingValuesPtr = NULL; if (*fragmentsNumPtr == 1) { CWDebugLog("1 Fragment"); CW_CREATE_OBJECT_ERR(*completeMsgPtr, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); transportVal.isFragment = transportVal.last = transportVal.fragmentOffset = transportVal.fragmentID = 0; transportVal.payloadType = CW_PACKET_PLAIN; // transportVal.last = 1; // Assemble Message Elements if (!(CWAssembleTransportHeader(&transportHdr, &transportVal))) { CW_FREE_PROTOCOL_MESSAGE(msg); CW_FREE_PROTOCOL_MESSAGE(transportHdr); CW_FREE_OBJECT(completeMsgPtr); return CW_FALSE; // will be handled by the caller } // assemble the message putting all the data consecutively CW_CREATE_PROTOCOL_MESSAGE(((*completeMsgPtr)[0]), transportHdr.offset + msg.offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreMessage(&((*completeMsgPtr)[0]), &transportHdr); CWProtocolStoreMessage(&((*completeMsgPtr)[0]), &msg); CW_FREE_PROTOCOL_MESSAGE(transportHdr); CW_FREE_PROTOCOL_MESSAGE(msg); } else { int fragID = CWGetFragmentID(); int totalSize = msg.offset; CWDebugLog("%d Fragments", *fragmentsNumPtr); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(*completeMsgPtr, *fragmentsNumPtr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); msg.offset = 0; for (i = 0; i < *fragmentsNumPtr; i++) { // for each fragment to assemble int fragSize; transportVal.isFragment = 1; transportVal.fragmentOffset = msg.offset / 8; transportVal.fragmentID = fragID; transportVal.payloadType = CW_PACKET_PLAIN; if (i < ((*fragmentsNumPtr) - 1)) { // not last fragment fragSize = PMTU; transportVal.last = 0; } else { // last fragment fragSize = totalSize - (((*fragmentsNumPtr) - 1) * PMTU); transportVal.last = 1; } CWDebugLog("Fragment #:%d, offset:%d, bytes stored:%d/%d", i, transportVal.fragmentOffset, fragSize, totalSize); // Assemble Transport Header for this fragment if (!(CWAssembleTransportHeader(&transportHdr, &transportVal))) { CW_FREE_PROTOCOL_MESSAGE(msg); CW_FREE_PROTOCOL_MESSAGE(transportHdr); CW_FREE_OBJECT(completeMsgPtr); return CW_FALSE; // will be handled by the caller } CW_CREATE_PROTOCOL_MESSAGE(((*completeMsgPtr)[i]), transportHdr.offset + fragSize, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreMessage(&((*completeMsgPtr)[i]), &transportHdr); CWProtocolStoreRawBytes(&((*completeMsgPtr)[i]), &((msg.msg)[msg.offset]), fragSize); msg.offset += fragSize; CW_FREE_PROTOCOL_MESSAGE(transportHdr); } CW_FREE_PROTOCOL_MESSAGE(msg); } return CW_TRUE; } void CWProtocolDestroyFragment(void *f) { CW_FREE_OBJECT(((CWProtocolFragment *) f)->data); CW_FREE_OBJECT(f); } CWBool CWCompareFragment(void *newFrag, void *oldFrag) { CWProtocolFragment *newEl = (CWProtocolFragment *) newFrag; CWProtocolFragment *oldEl = (CWProtocolFragment *) oldFrag; if ((newEl->transportVal.fragmentID == oldEl->transportVal.fragmentID) && (newEl->transportVal.fragmentOffset == oldEl->transportVal.fragmentOffset)) { return CW_TRUE; } return CW_FALSE; } // parse a sigle fragment. If it is the last fragment we need or the only fragment, return the reassembled message in // *reassembleMsg. If we need at lest one more fragment, save this fragment in the list. You then call this function again // with a new fragment and the same list untill we got all the fragments. CWBool CWProtocolParseFragment(unsigned char *buf, int readBytes, CWList * fragmentsListPtr, CWProtocolMessage * reassembledMsg, CWBool * dataFlagPtr, unsigned char *RadioMAC) { CWProtocolTransportHeaderValues values; CWProtocolMessage msg; int totalSize; msg.msg = buf; msg.offset = 0; if (!CWParseTransportHeader(&msg, &values, dataFlagPtr, RadioMAC)) { CWDebugLog("CWParseTransportHeader failed"); return CW_FALSE; } if (values.isFragment == 0) { // single fragment /* if(*fragmentsListPtr != NULL) { // we are receiving another fragmented message, return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Received Fragment with Different ID"); // discard this packet } */ CW_CREATE_PROTOCOL_MESSAGE(*reassembledMsg, (readBytes - msg.offset), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreRawBytes(reassembledMsg, &(buf[msg.offset]), (readBytes - msg.offset)); reassembledMsg->data_msgType = msg.data_msgType; return CW_TRUE; } else { CWListElement *el; CWProtocolFragment *fragPtr; int currentSize; CW_CREATE_OBJECT_ERR(fragPtr, CWProtocolFragment, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); fragPtr->transportVal.fragmentID = values.fragmentID; fragPtr->transportVal.fragmentOffset = values.fragmentOffset; fragPtr->transportVal.last = values.last; CWDebugLog("Received Fragment ID:%d, offset:%d, notLast:%d", fragPtr->transportVal.fragmentID, fragPtr->transportVal.fragmentOffset, fragPtr->transportVal.last); fragPtr->dataLen = (readBytes - msg.offset); if (*fragmentsListPtr == NULL || // empty list (((CWProtocolFragment *) ((*fragmentsListPtr)->data))->transportVal.fragmentID) == fragPtr->transportVal.fragmentID) // this fragment is in the set of fragments we are receiving /* { CW_CREATE_OBJECT_SIZE_ERR(fragPtr->data, fragPtr->dataLen, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); CW_COPY_MEMORY(fragPtr->data, &(buf[msg.offset]), fragPtr->dataLen); if(!CWAddElementToList(fragmentsListPtr, fragPtr)) { CWDeleteList(fragmentsListPtr, CWProtocolDestroyFragment); CW_FREE_OBJECT(fragPtr); return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } } */ { CWListElement *aux = NULL; aux = CWSearchInList(*fragmentsListPtr, fragPtr, CWCompareFragment); if (aux == NULL) { CW_CREATE_OBJECT_SIZE_ERR(fragPtr->data, fragPtr->dataLen, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_COPY_MEMORY(fragPtr->data, &(buf[msg.offset]), fragPtr->dataLen); if (!CWAddElementToList(fragmentsListPtr, fragPtr)) { CWDeleteList(fragmentsListPtr, CWProtocolDestroyFragment); CW_FREE_OBJECT(fragPtr); return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } } else { CWDebugLog("Received a copy of a fragment already in List"); CW_FREE_OBJECT(fragPtr); return CWErrorRaise(CW_ERROR_NEED_RESOURCE, NULL); } } else { CWDebugLog("Discarded old fragments for different fragment ID: %d Vs %d", fragPtr->transportVal.fragmentID, (((CWProtocolFragment *) ((*fragmentsListPtr)->data))->transportVal).fragmentID); CWDeleteList(fragmentsListPtr, CWProtocolDestroyFragment); CW_CREATE_OBJECT_SIZE_ERR(fragPtr->data, fragPtr->dataLen, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_COPY_MEMORY(fragPtr->data, &(buf[msg.offset]), fragPtr->dataLen); if (!CWAddElementToList(fragmentsListPtr, fragPtr)) { CWDeleteList(fragmentsListPtr, CWProtocolDestroyFragment); CW_FREE_OBJECT(fragPtr); return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); } } // check if we have all the fragments for (el = *fragmentsListPtr, totalSize = 0; el != NULL; el = el->next) { if ((((CWProtocolFragment *) (el->data))->transportVal.last) == 1) { // last element totalSize = (((CWProtocolFragment *) (el->data))->transportVal.fragmentOffset) * 8; totalSize += (((CWProtocolFragment *) (el->data))->dataLen); } } if (totalSize == 0) { // we haven't the last fragment return CWErrorRaise(CW_ERROR_NEED_RESOURCE, NULL); // we need at least one more fragment } // calculate the size of all the fragments we have so far for (el = *fragmentsListPtr, currentSize = 0; el != NULL; el = el->next) { currentSize += (((CWProtocolFragment *) (el->data))->dataLen); //CWDebugLog("size %d/%d", currentSize, totalSize); } CWDebugLog("totalSize = %d , currentSize = %d", totalSize, currentSize); if (currentSize != totalSize) { return CWErrorRaise(CW_ERROR_NEED_RESOURCE, NULL); // we need at least one mpre fragment } else { int currentOffset = 0; CWLog("_______________________"); CWDebugLog("Received All Fragments"); CW_CREATE_PROTOCOL_MESSAGE(*reassembledMsg, (totalSize), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_REPEAT_FOREVER { CWBool found = CW_FALSE; // find the fragment in the list with the currend offset for (el = *fragmentsListPtr, currentSize = 0; el != NULL; el = el->next) { if ((((CWProtocolFragment *) (el->data))->transportVal.fragmentOffset) == currentOffset) { found = CW_TRUE; break; } } if (!found) { // mmm... we should have all the fragment, but we haven't a fragment for the current offset CWDeleteList(fragmentsListPtr, CWProtocolDestroyFragment); CW_FREE_PROTOCOL_MESSAGE(*reassembledMsg); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Bad Fragmented Messsage"); } CWProtocolStoreRawBytes(reassembledMsg, (((CWProtocolFragment *) (el->data))->data), (((CWProtocolFragment *) (el->data))->dataLen)); reassembledMsg->data_msgType = msg.data_msgType; if ((((CWProtocolFragment *) (el->data))->transportVal.last) == 1) { // last fragment CWDebugLog("Message Reassembled"); CWDeleteList(fragmentsListPtr, CWProtocolDestroyFragment); return CW_TRUE; } currentOffset += ((((CWProtocolFragment *) (el->data))->dataLen) / 8); } } } } // Parse Transport Header CWBool CWParseTransportHeader(CWProtocolMessage * msgPtr, CWProtocolTransportHeaderValues * valuesPtr, CWBool * dataFlagPtr, unsigned char *RadioMAC) { int transport4BytesLen; int val; int optionalWireless = 0; int version, rid; int m = 0; if (msgPtr == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); //CWDebugLog("Parse Transport Header"); val = CWProtocolRetrieve32(msgPtr); if (CWGetField32(val, CW_TRANSPORT_HEADER_VERSION_START, CW_TRANSPORT_HEADER_VERSION_LEN) != CW_PROTOCOL_VERSION) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Wrong Protocol Version"); version = CWGetField32(val, CW_TRANSPORT_HEADER_VERSION_START, CW_TRANSPORT_HEADER_VERSION_LEN); //CWDebugLog("VERSION: %d", version); valuesPtr->payloadType = CWGetField32(val, CW_TRANSPORT_HEADER_TYPE_START, CW_TRANSPORT_HEADER_TYPE_LEN); //CWDebugLog("PAYLOAD TYPE: %d", valuesPtr->payloadType); transport4BytesLen = CWGetField32(val, CW_TRANSPORT_HEADER_HLEN_START, CW_TRANSPORT_HEADER_HLEN_LEN); CWDebugLog("HLEN: %d", transport4BytesLen); rid = CWGetField32(val, CW_TRANSPORT_HEADER_RID_START, CW_TRANSPORT_HEADER_RID_LEN); CWDebugLog("RID: %d", rid); CWDebugLog("WBID: %d", CWGetField32(val, CW_TRANSPORT_HEADER_WBID_START, CW_TRANSPORT_HEADER_WBID_LEN)); valuesPtr->type = CWGetField32(val, CW_TRANSPORT_HEADER_T_START, CW_TRANSPORT_HEADER_T_LEN); CWDebugLog("TYPE: %d", valuesPtr->type); //CWDebugLog("TYPE: %d", valuesPtr->type); valuesPtr->isFragment = CWGetField32(val, CW_TRANSPORT_HEADER_F_START, CW_TRANSPORT_HEADER_F_LEN); //CWDebugLog("IS FRAGMENT: %d", valuesPtr->isFragment); valuesPtr->last = CWGetField32(val, CW_TRANSPORT_HEADER_L_START, CW_TRANSPORT_HEADER_L_LEN); //CWDebugLog("NOT LAST: %d", valuesPtr->last); optionalWireless = CWGetField32(val, CW_TRANSPORT_HEADER_W_START, CW_TRANSPORT_HEADER_W_LEN); // CWDebugLog("OPTIONAL WIRELESS: %d", optionalWireless); m = CWGetField32(val, CW_TRANSPORT_HEADER_M_START, CW_TRANSPORT_HEADER_M_LEN); valuesPtr->keepAlive = CWGetField32(val, CW_TRANSPORT_HEADER_K_START, CW_TRANSPORT_HEADER_K_LEN); // CWDebugLog("KEEP ALIVE: %d", valuesPtr->keepAlive); val = CWProtocolRetrieve32(msgPtr); valuesPtr->fragmentID = CWGetField32(val, CW_TRANSPORT_HEADER_FRAGMENT_ID_START, CW_TRANSPORT_HEADER_FRAGMENT_ID_LEN); // CWDebugLog("FRAGMENT_ID: %d", valuesPtr->fragmentID); valuesPtr->fragmentOffset = CWGetField32(val, CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_START, CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_LEN); // CWDebugLog("FRAGMENT_OFFSET: %d", valuesPtr->fragmentOffset); valuesPtr->bindingValuesPtr = NULL; if (*dataFlagPtr == CW_TRUE) { if (valuesPtr->keepAlive) { // Keep Alive packet CWDebugLog("Keep-Alive packet"); msgPtr->data_msgType = CW_DATA_MSG_KEEP_ALIVE_TYPE; } else if (valuesPtr->type == 0) { //IEEE 802.3 frame CWDebugLog("802.3 frame"); if (optionalWireless) { CW_CREATE_OBJECT_ERR(valuesPtr->bindingValuesPtr, CWBindingTransportHeaderValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!CWParseTransportHeaderBinding(msgPtr, valuesPtr->bindingValuesPtr)) { CW_FREE_OBJECT(valuesPtr->bindingValuesPtr); return CW_FALSE; } } msgPtr->data_msgType = CW_IEEE_802_3_FRAME_TYPE; } else if (valuesPtr->type == 1) { //IEEE 802.11 frame CWDebugLog("802.11 frame"); if (optionalWireless) { CW_CREATE_OBJECT_ERR(valuesPtr->bindingValuesPtr, CWBindingTransportHeaderValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!CWParseTransportHeaderBinding(msgPtr, valuesPtr->bindingValuesPtr)) { CW_FREE_OBJECT(valuesPtr->bindingValuesPtr); return CW_FALSE; } } msgPtr->data_msgType = CW_IEEE_802_11_FRAME_TYPE; } else { CWLog("Todo: This should be a keep-alive data packet!!!!"); } if (m) { //CW_CREATE_OBJECT_ERR( valuesPtr->MACValuesPtr, CWMACTransportHeaderValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY,NULL);); if (!CWParseTransportHeaderMACAddress(msgPtr, RadioMAC)) { //CW_FREE_OBJECT(valuesPtr->bindingValuesPtr); return CW_FALSE; } } } else { if (transport4BytesLen == 4 && optionalWireless == 1) { *dataFlagPtr = CW_TRUE; CW_CREATE_OBJECT_ERR(valuesPtr->bindingValuesPtr, CWBindingTransportHeaderValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!CWParseTransportHeaderBinding(msgPtr, valuesPtr->bindingValuesPtr)) { CW_FREE_OBJECT(valuesPtr->bindingValuesPtr); return CW_FALSE; } } else if (m) { //CW_CREATE_OBJECT_ERR( valuesPtr->MACValuesPtr, CWMACTransportHeaderValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY,NULL);); if (!CWParseTransportHeaderMACAddress(msgPtr, RadioMAC)) { //CW_FREE_OBJECT(valuesPtr->bindingValuesPtr); return CW_FALSE; } } } CWDebugLog(NULL); return (transport4BytesLen == 2 || (transport4BytesLen == 4 && optionalWireless == 1) || m) ? CW_TRUE : CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Malformed Transport Header"); //TEMP? } // Parse Control Header CWBool CWParseControlHeader(CWProtocolMessage * msgPtr, CWControlHeaderValues * valPtr) { if (msgPtr == NULL || valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // CWDebugLog("Parse Control Header"); valPtr->messageTypeValue = CWProtocolRetrieve32(msgPtr); // CWDebugLog("MESSAGE_TYPE: %u", valPtr->messageTypeValue); valPtr->seqNum = CWProtocolRetrieve8(msgPtr); // CWDebugLog("SEQUENCE_NUMBER: %u", valPtr->seqNum ); valPtr->msgElemsLen = CWProtocolRetrieve16(msgPtr); // CWDebugLog("MESSAGE_ELEMENT_LENGTH: %u", valPtr->msgElemsLen ); CWProtocolRetrieve8(msgPtr); // CWDebugLog("FLAGS: %u", flags); // valPtr->timestamp = CWProtocolRetrieve32(msgPtr); // CWDebugLog("TIME_STAMP: %u", valPtr->timestamp); CWDebugLog(NULL); return CW_TRUE; } //## Assemble a Message Response containing a Failure (Unrecognized Message) Result Code CWBool CWAssembleUnrecognizedMessageResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, int msgType) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 1; CWProtocolMessage *msgElemsBinding = NULL; int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Unrecognized Message Response..."); CW_CREATE_OBJECT_ERR(msgElems, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWAssembleMsgElemResultCode(msgElems, CW_PROTOCOL_FAILURE_UNRECOGNIZED_REQ))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } if (! (CWAssembleMessage (messagesPtr, fragmentsNumPtr, PMTU, seqNum, msgType, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Unrecognized Message Response Assembled"); return CW_TRUE; } CWBool CWAssembleMsgElemSessionID(CWProtocolMessage * msgPtr, unsigned char *sessionID) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 16, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreRawBytes(msgPtr, sessionID, 16); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_SESSION_ID_CW_TYPE); } CWBool CWParseACName(CWProtocolMessage * msgPtr, int len, char **valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieveStr(msgPtr, len); if (valPtr == NULL) return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); // CWDebugLog("AC Name:%s", *valPtr); CWParseMessageElementEnd(); } CWBool CWParseWTPRadioAdminState(CWProtocolMessage * msgPtr, int len, CWRadioAdminInfoValues * valPtr) { CWParseMessageElementStart(); valPtr->ID = CWProtocolRetrieve8(msgPtr); valPtr->state = CWProtocolRetrieve8(msgPtr); //valPtr->cause = CWProtocolRetrieve8(msgPtr); // CWDebugLog("WTP Radio Admin State: %d - %d - %d", valPtr->ID, valPtr->state, valPtr->cause); CWParseMessageElementEnd(); } CWBool CWParseWTPRadioOperationalState(CWProtocolMessage * msgPtr, int len, CWRadioOperationalInfoValues * valPtr) { CWParseMessageElementStart(); valPtr->ID = CWProtocolRetrieve8(msgPtr); valPtr->state = CWProtocolRetrieve8(msgPtr); valPtr->cause = CWProtocolRetrieve8(msgPtr); CWDebugLog("WTP Radio Operational State: %d - %d - %d", valPtr->ID, valPtr->state, valPtr->cause); CWParseMessageElementEnd(); } CWBool CWParseFormatMsgElem(CWProtocolMessage * completeMsg, unsigned short int *type, unsigned short int *len) { *type = CWProtocolRetrieve16(completeMsg); *len = CWProtocolRetrieve16(completeMsg); return CW_TRUE; } CWBool CWParseResultCode(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * valPtr) { CWParseMessageElementStart(); *valPtr = CWProtocolRetrieve32(msgPtr); // CWDebugLog("Result Code: %d", *valPtr); CWParseMessageElementEnd(); } void CWWTPResetRadioStatistics(WTPRadioStatisticsInfo * radioStatistics) { radioStatistics->lastFailureType = UNKNOWN_TYPE; radioStatistics->resetCount = 0; radioStatistics->SWFailureCount = 0; radioStatistics->HWFailuireCount = 0; radioStatistics->otherFailureCount = 0; radioStatistics->unknownFailureCount = 0; radioStatistics->configUpdateCount = 0; radioStatistics->channelChangeCount = 0; radioStatistics->bandChangeCount = 0; radioStatistics->currentNoiseFloor = 0; } void CWFreeMessageFragments(CWProtocolMessage * messages, int fragmentsNum) { int i; for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } } unsigned char *CWParseSessionID(CWProtocolMessage * msgPtr, int len) { return CWProtocolRetrieveRawBytes(msgPtr, 16); } ================================================ FILE: CWProtocol.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_CWProtocol_HEADER__ #define __CAPWAP_CWProtocol_HEADER__ //#define CWSetField32(obj, start, val) ((obj)[start/64]) |= ((val) << (start%64)) //#define CWGetField32(obj, start, len) (((obj)[start/64]) & ((0xFFFFFFFFFFFFFFFF >> (64-(len))) << (start%64)) ) >> (start%64) /*_____________________________________________________*/ /* *******************___MACRO___******************* */ //#define CWSetField32(obj, start, val) ((obj)[start/32]) |= ((val) << (start%32)) //#define CWGetField32(obj, start, len) (((obj)[start/32]) & ((0xFFFFFFFFUL >> (32-(len))) << (start%32)) ) >> (start%32) #define CWSetField32(src,start,len,val) src |= ((~(0xFFFFFFFF << len)) & val) << (32 - start - len) #define CWGetField32(src,start,len) ((~(0xFFFFFFFF<> (32 - start - len))) #define CW_REWIND_BYTES(buf, bytes, type) (buf) = (type*)(((char*) (buf)) - bytes) #define CW_SKIP_BYTES(buf, bytes, type) (buf) = (type*)(((char*) (buf)) + bytes) #define CW_SKIP_BITS(buf, bits, type) (buf) = (type*)(((char*) (buf)) + ((bits) / 8)) #define CW_BYTES_TO_STORE_BITS(bits) ((((bits) % 8) == 0) ? ((bits) / 8) : (((bits) / 8)+1)) #define CW_CREATE_PROTOCOL_MESSAGE(mess, size, err) CW_CREATE_OBJECT_SIZE_ERR(((mess).msg), (size), err); \ CW_ZERO_MEMORY(((mess).msg), (size)); \ (mess).offset = 0; #define CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(ar_name, ar_size, on_err) {\ CW_CREATE_ARRAY_ERR(ar_name, ar_size, CWProtocolMessage, on_err)\ int i;\ for(i=0;i<(ar_size); i++) {\ (ar_name)[i].msg = NULL;\ (ar_name)[i].offset = 0; \ }\ } #define CW_FREE_PROTOCOL_MESSAGE(mess) CW_FREE_OBJECT(((mess).msg)); \ (mess).offset = 0; #define CWParseMessageElementStart() int oldOffset; \ if(msgPtr == NULL || valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); \ oldOffset = msgPtr->offset #define CWParseMessageElementEnd() CWDebugLog(NULL); \ return ((msgPtr->offset) - oldOffset) == len ? CW_TRUE : \ CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message Element Malformed"); /*_________________________________________________________*/ /* *******************___CONSTANTS___******************* */ // to be defined #define MAX_UDP_PACKET_SIZE 65536 #define CW_CONTROL_PORT 5246 #define CW_DATA_PORT 5247 #define CW_PROTOCOL_VERSION 0 #define CW_IANA_ENTERPRISE_NUMBER 13277 #define CW_IANA_ENTERPRISE_NUMBER_VENDOR_IANA 18357 #define CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS 3 //Offset "Seq Num" - "Message Elements" #define CW_MAX_SEQ_NUM 255 #define CW_MAX_FRAGMENT_ID 65535 #define CLEAR_DATA 1 #define DTLS_ENABLED_DATA 2 #define CW_PACKET_PLAIN 0 #define CW_PACKET_CRYPT 1 #define CW_DATA_MSG_FRAME_TYPE 1 #define CW_DATA_MSG_STATS_TYPE 2 #define CW_DATA_MSG_FREQ_STATS_TYPE 3 /* 2009 Update */ #define CW_IEEE_802_3_FRAME_TYPE 4 #define CW_DATA_MSG_KEEP_ALIVE_TYPE 5 #define CW_IEEE_802_11_FRAME_TYPE 6 // // CAPWAP version (currently 0) #define CW_TRANSPORT_HEADER_VERSION_START 0 #define CW_TRANSPORT_HEADER_VERSION_LEN 4 // Mauro #define CW_TRANSPORT_HEADER_TYPE_START 4 #define CW_TRANSPORT_HEADER_TYPE_LEN 4 // Radio ID number (for WTPs with multiple radios) #define CW_TRANSPORT_HEADER_RID_START 13 #define CW_TRANSPORT_HEADER_RID_LEN 5 // Length of CAPWAP tunnel header in 4 byte words #define CW_TRANSPORT_HEADER_HLEN_START 8 #define CW_TRANSPORT_HEADER_HLEN_LEN 5 // Wireless Binding ID #define CW_TRANSPORT_HEADER_WBID_START 18 #define CW_TRANSPORT_HEADER_WBID_LEN 5 // Format of the frame #define CW_TRANSPORT_HEADER_T_START 23 #define CW_TRANSPORT_HEADER_T_LEN 1 // Is a fragment? #define CW_TRANSPORT_HEADER_F_START 24 #define CW_TRANSPORT_HEADER_F_LEN 1 // Is NOT the last fragment? #define CW_TRANSPORT_HEADER_L_START 25 #define CW_TRANSPORT_HEADER_L_LEN 1 // Is the Wireless optional header present? #define CW_TRANSPORT_HEADER_W_START 26 #define CW_TRANSPORT_HEADER_W_LEN 1 // Is the Radio MAC Address optional field present? #define CW_TRANSPORT_HEADER_M_START 27 #define CW_TRANSPORT_HEADER_M_LEN 1 // Is the message a keep alive? #define CW_TRANSPORT_HEADER_K_START 28 #define CW_TRANSPORT_HEADER_K_LEN 1 // Set to 0 in this version of the protocol #define CW_TRANSPORT_HEADER_FLAGS_START 29 #define CW_TRANSPORT_HEADER_FLAGS_LEN 3 // ID of the group of fragments #define CW_TRANSPORT_HEADER_FRAGMENT_ID_START 0 #define CW_TRANSPORT_HEADER_FRAGMENT_ID_LEN 16 // Position of this fragment in the group #define CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_START 16 #define CW_TRANSPORT_HEADER_FRAGMENT_OFFSET_LEN 13 // Set to 0 in this version of the protocol #define CW_TRANSPORT_HEADER_RESERVED_START 29 #define CW_TRANSPORT_HEADER_RESERVED_LEN 3 // // Message Type Values #define CW_MSG_TYPE_VALUE_DISCOVERY_REQUEST 1 #define CW_MSG_TYPE_VALUE_DISCOVERY_RESPONSE 2 #define CW_MSG_TYPE_VALUE_JOIN_REQUEST 3 #define CW_MSG_TYPE_VALUE_JOIN_RESPONSE 4 #define CW_MSG_TYPE_VALUE_CONFIGURE_REQUEST 5 #define CW_MSG_TYPE_VALUE_CONFIGURE_RESPONSE 6 #define CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_REQUEST 7 #define CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE 8 #define CW_MSG_TYPE_VALUE_WTP_EVENT_REQUEST 9 #define CW_MSG_TYPE_VALUE_WTP_EVENT_RESPONSE 10 #define CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_REQUEST 11 #define CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_RESPONSE 12 #define CW_MSG_TYPE_VALUE_ECHO_REQUEST 13 #define CW_MSG_TYPE_VALUE_ECHO_RESPONSE 14 #define CW_MSG_TYPE_VALUE_IMAGE_DATA_REQUEST 15 #define CW_MSG_TYPE_VALUE_IMAGE_DATA_RESPONSE 16 #define CW_MSG_TYPE_VALUE_RESET_REQUEST 17 #define CW_MSG_TYPE_VALUE_RESET_RESPONSE 18 #define CW_MSG_TYPE_VALUE_PRIMARY_DISCOVERY_REQUEST 19 #define CW_MSG_TYPE_VALUE_PRIMARY_DISCOVERY_RESPONSE 20 #define CW_MSG_TYPE_VALUE_DATA_TRANSFER_REQUEST 21 #define CW_MSG_TYPE_VALUE_DATA_TRANSFER_RESPONSE 22 #define CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_REQUEST 23 #define CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_RESPONSE 24 #define CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_REQUEST 25 #define CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE 26 // IEEE 802.11 Binding Type #define CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_REQUEST 3398913 #define CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_RESPONSE 3398914 // Message Elements Type Values #define CW_MSG_ELEMENT_AC_DESCRIPTOR_CW_TYPE 1 #define CW_MSG_ELEMENT_AC_IPV4_LIST_CW_TYPE 2 #define CW_MSG_ELEMENT_AC_IPV6_LIST_CW_TYPE 3 #define CW_MSG_ELEMENT_AC_NAME_CW_TYPE 4 #define CW_MSG_ELEMENT_AC_NAME_INDEX_CW_TYPE 5 #define CW_MSG_ELEMENT_TIMESTAMP_CW_TYPE 6 #define CW_MSG_ELEMENT_ADD_MAC_ACL_CW_TYPE 7 #define CW_MSG_ELEMENT_ADD_STATION_CW_TYPE 8 #define CW_MSG_ELEMENT_ADD_STATIC_MAC_ACL_CW_TYPE 9 #define CW_MSG_ELEMENT_CW_CONTROL_IPV4_ADDRESS_CW_TYPE 10 #define CW_MSG_ELEMENT_CW_CONTROL_IPV6_ADDRESS_CW_TYPE 11 #define CW_MSG_ELEMENT_CW_TIMERS_CW_TYPE 12 #define CW_MSG_ELEMENT_DATA_TRANSFER_DATA_CW_TYPE 13 #define CW_MSG_ELEMENT_DATA_TRANSFER_MODE_CW_TYPE 14 #define CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_CW_TYPE 15 #define CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_PERIOD_CW_TYPE 16 #define CW_MSG_ELEMENT_DELETE_MAC_ACL_CW_TYPE 17 #define CW_MSG_ELEMENT_DELETE_STATION_CW_TYPE 18 #define CW_MSG_ELEMENT_DELETE_STATIC_MAC_ACL_CW_TYPE 19 #define CW_MSG_ELEMENT_DISCOVERY_TYPE_CW_TYPE 20 #define CW_MSG_ELEMENT_DUPLICATE_IPV4_ADDRESS_CW_TYPE 21 #define CW_MSG_ELEMENT_DUPLICATE_IPV6_ADDRESS_CW_TYPE 22 #define CW_MSG_ELEMENT_IDLE_TIMEOUT_CW_TYPE 23 #define CW_MSG_ELEMENT_IMAGE_DATA_CW_TYPE 24 #define CW_MSG_ELEMENT_IMAGE_IDENTIFIER_CW_TYPE 25 #define CW_MSG_ELEMENT_IMAGE_INFO_CW_TYPE 26 #define CW_MSG_ELEMENT_INITIATED_DOWNLOAD_CW_TYPE 27 #define CW_MSG_ELEMENT_LOCATION_DATA_CW_TYPE 28 #define CW_MSG_ELEMENT_MAX_MSG_LEN_CW_TYPE 29 #define CW_MSG_ELEMENT_WTP_IPV4_ADDRESS_CW_TYPE 30 #define CW_MSG_ELEMENT_RADIO_ADMIN_STATE_CW_TYPE 31 #define CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE 32 #define CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE 33 #define CW_MSG_ELEMENT_RETURNED_MSG_ELEM_CW_TYPE 34 #define CW_MSG_ELEMENT_SESSION_ID_CW_TYPE 35 #define CW_MSG_ELEMENT_STATISTICS_TIMER_CW_TYPE 36 #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_BW_CW_TYPE 37 #define CW_MSG_ELEMENT_WTP_BOARD_DATA_CW_TYPE 38 #define CW_MSG_ELEMENT_WTP_DESCRIPTOR_CW_TYPE 39 #define CW_MSG_ELEMENT_WTP_FALLBACK_CW_TYPE 40 #define CW_MSG_ELEMENT_WTP_FRAME_TUNNEL_MODE_CW_TYPE 41 #define CW_MSG_ELEMENT_WTP_MAC_TYPE_CW_TYPE 44 #define CW_MSG_ELEMENT_WTP_NAME_CW_TYPE 45 #define CW_MSG_ELEMENT_WTP_OPERAT_STATISTICS_CW_TYPE 46 #define CW_MSG_ELEMENT_WTP_RADIO_STATISTICS_CW_TYPE 47 #define CW_MSG_ELEMENT_WTP_REBOOT_STATISTICS_CW_TYPE 48 #define CW_MSG_ELEMENT_WTP_STATIC_IP_CW_TYPE 49 /*Update 2009: Message type to return a payload together with the configuration update response*/ #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE 57 #define CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE_WITH_PAYLOAD 58 #define CW_MSG_ELEMENT_MTU_DISCOVERY_PADDING_CW_TYPE 59 //Vendor Specific data #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_AC_PRIORITY 128 #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_AC_PRIORITY_LEN 1 #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_AC_PRIORITY_DEFAULT 3 // IEEE 802.11 Message Element #define CW_MSG_ELEMENT_IEEE80211_ADD_WLAN_CW_TYPE 1024 #define CW_MSG_ELEMENT_IEEE80211_DELETE_WLAN_CW_TYPE 1027 #define CW_MSG_ELEMENT_IEEE80211_MULTI_DOMAIN_CAPABILITY_CW_TYPE 1032 #define CW_MSG_ELEMENT_IEEE80211_SUPPORTED_RATES_CW_TYPE 1040 #define CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE 1048 // CAPWAP Protocol Variables #define CW_MAX_RETRANSMIT_DEFAULT 1 #define CW_WAIT_JOIN_DEFAULT 60 #define CW_REPORT_INTERVAL_DEFAULT 120 #define CW_STATISTIC_TIMER_DEFAULT 120 #ifdef CW_DEBUGGING #define CW_JOIN_INTERVAL_DEFAULT 60 #else #define CW_JOIN_INTERVAL_DEFAULT 60 #endif #ifdef CW_DEBUGGING #define CW_CHANGE_STATE_INTERVAL_DEFAULT 10 #else #define CW_CHANGE_STATE_INTERVAL_DEFAULT 25 #endif #ifdef CW_DEBUGGING #define CW_RETRANSMIT_INTERVAL_DEFAULT 10 #else #define CW_RETRANSMIT_INTERVAL_DEFAULT 10 #endif #ifdef CW_DEBUGGING #define CW_NEIGHBORDEAD_INTERVAL_DEFAULT 33 #define CW_NEIGHBORDEAD_RESTART_DISCOVERY_DELTA_DEFAULT ((CW_NEIGHBORDEAD_INTERVAL_DEFAULT) + 40) #else #define CW_NEIGHBORDEAD_INTERVAL_DEFAULT 33 #define CW_NEIGHBORDEAD_RESTART_DISCOVERY_DELTA_DEFAULT ((CW_NEIGHBORDEAD_INTERVAL_DEFAULT) + 40) #endif #ifdef CW_DEBUGGING #define CW_ECHO_INTERVAL_DEFAULT 30 #define CW_DATA_CHANNEL_KEEP_ALIVE_DEFAULT 30 #else #define CW_ECHO_INTERVAL_DEFAULT 30 #define CW_DATA_CHANNEL_KEEP_ALIVE_DEFAULT 30 #endif /*_________________________________________________________*/ /* *******************___VARIABLES___******************* */ /*_____________________________________________________*/ /* *******************___TYPES___******************* */ typedef struct { int type; int value; } CWMsgElemData; typedef unsigned char CWMACAddress[6]; typedef enum { CW_PROTOCOL_SUCCESS = 0, // Success CW_PROTOCOL_FAILURE_AC_LIST = 1, // AC List message MUST be present CW_PROTOCOL_SUCCESS_NAT = 2, // NAT detected CW_PROTOCOL_FAILURE = 3, // unspecified CW_PROTOCOL_FAILURE_RES_DEPLETION = 4, // Resource Depletion CW_PROTOCOL_FAILURE_UNKNOWN_SRC = 5, // Unknown Source CW_PROTOCOL_FAILURE_INCORRECT_DATA = 6, // Incorrect Data CW_PROTOCOL_FAILURE_ID_IN_USE = 7, // Session ID Alreadyin Use CW_PROTOCOL_FAILURE_WTP_HW_UNSUPP = 8, // WTP Hardware not supported CW_PROTOCOL_FAILURE_BINDING_UNSUPP = 9, // Binding not supported CW_PROTOCOL_FAILURE_UNABLE_TO_RESET = 10, // Unable to reset CW_PROTOCOL_FAILURE_FIRM_WRT_ERROR = 11, // Firmware write error CW_PROTOCOL_FAILURE_SERVICE_PROVIDED_ANYHOW = 12, // Unable to apply requested configuration CW_PROTOCOL_FAILURE_SERVICE_NOT_PROVIDED = 13, // Unable to apply requested configuration CW_PROTOCOL_FAILURE_INVALID_CHECKSUM = 14, // Image Data Error: invalid checksum CW_PROTOCOL_FAILURE_INVALID_DATA_LEN = 15, // Image Data Error: invalid data length CW_PROTOCOL_FAILURE_OTHER_ERROR = 16, // Image Data Error: other error CW_PROTOCOL_FAILURE_IMAGE_ALREADY_PRESENT = 17, // Image Data Error: image already present CW_PROTOCOL_FAILURE_INVALID_STATE = 18, // Message unexpected: invalid in current state CW_PROTOCOL_FAILURE_UNRECOGNIZED_REQ = 19, // Message unexpected: unrecognized request CW_PROTOCOL_FAILURE_MISSING_MSG_ELEM = 20, // Failure: missing mandatory message element CW_PROTOCOL_FAILURE_UNRECOGNIZED_MSG_ELEM = 21 // Failure: unrecognized message element } CWProtocolResultCode; typedef struct { unsigned char *msg; int offset; int data_msgType; } CWProtocolMessage; #define MAX_PENDING_REQUEST_MSGS 15 #define UNUSED_MSG_TYPE 0 typedef struct { unsigned char msgType; unsigned char seqNum; int timer_sec; void (*timer_hdl) (void *); CWTimerArg timer_arg; CWTimerID timer; int retransmission; CWProtocolMessage *msgElems; int fragmentsNum; } CWPendingRequestMessage; #include "CWBinding.h" typedef struct { int payloadType; int type; int isFragment; int last; int fragmentID; int fragmentOffset; int keepAlive; CWBindingTransportHeaderValues *bindingValuesPtr; } CWProtocolTransportHeaderValues; typedef struct { unsigned int messageTypeValue; unsigned char seqNum; unsigned short msgElemsLen; // unsigned int timestamp; } CWControlHeaderValues; typedef struct { unsigned char *data; int dataLen; CWProtocolTransportHeaderValues transportVal; } CWProtocolFragment; typedef struct { int vendorIdentifier; enum { CW_WTP_MODEL_NUMBER = 0, CW_WTP_SERIAL_NUMBER = 1, CW_BOARD_ID = 2, CW_BOARD_REVISION = 3, CW_WTP_HARDWARE_VERSION = 0, CW_WTP_SOFTWARE_VERSION = 1, CW_BOOT_VERSION = 2 } type; int length; unsigned char *valuePtr; } CWWTPVendorInfoValues; typedef struct { int vendorInfosCount; CWWTPVendorInfoValues *vendorInfos; } CWWTPVendorInfos; typedef struct { unsigned short WBID; unsigned int encryptionCapabilities; } CWWTPEncryptCapValues; typedef struct { int encryptCapsCount; CWWTPEncryptCapValues *encryptCaps; } CWWTPEncryptCaps; typedef struct { int maxRadios; int radiosInUse; CWWTPEncryptCaps encCapabilities; CWWTPVendorInfos vendorInfos; } CWWTPDescriptor; typedef enum { CW_RESERVE = 1, CW_LOCAL_BRIDGING = 2, CW_802_DOT_3_BRIDGING = 4, CW_NATIVE_BRIDGING = 8, CW_ALL_ENC = 15 } CWframeTunnelMode; typedef enum { CW_TUNNEL_MODE_LOCAL_BRIDGING = 0, CW_TUNNEL_MODE_802_DOT_3_TUNNEL = 1, CW_TUNNEL_MODE_802_DOT_11_TUNNEL = 2 } CWTunnelMode; typedef enum { CW_LOCAL_MAC = 0, CW_SPLIT_MAC = 1, CW_BOTH = 2 } CWMACType; typedef struct { enum { CW_MSG_ELEMENT_DISCOVERY_TYPE_BROADCAST = 0, CW_MSG_ELEMENT_DISCOVERY_TYPE_CONFIGURED = 1 } type; CWWTPVendorInfos WTPBoardData; CWWTPDescriptor WTPDescriptor; CWframeTunnelMode frameTunnelMode; CWMACType MACType; } CWDiscoveryRequestValues; typedef enum { CW_X509_CERTIFICATE = 2, CW_PRESHARED = 4 } CWAuthSecurity; typedef struct { CWNetworkLev4Address addr; struct sockaddr_in addrIPv4; int WTPCount; } CWProtocolNetworkInterface; typedef struct { int WTPCount; struct sockaddr_in addr; } CWProtocolIPv4NetworkInterface; typedef struct { int WTPCount; struct sockaddr_in6 addr; } CWProtocolIPv6NetworkInterface; typedef struct { int vendorIdentifier; enum { CW_AC_HARDWARE_VERSION = 4, CW_AC_SOFTWARE_VERSION = 5 } type; int length; int *valuePtr; } CWACVendorInfoValues; typedef struct { int vendorInfosCount; CWACVendorInfoValues *vendorInfos; } CWACVendorInfos; typedef struct { int rebootCount; int ACInitiatedCount; int linkFailurerCount; int SWFailureCount; int HWFailuireCount; int otherFailureCount; int unknownFailureCount; enum { NOT_SUPPORTED = 0, AC_INITIATED = 1, LINK_FAILURE = 2, SW_FAILURE = 3, HD_FAILURE = 4, OTHER_FAILURE = 5, UNKNOWN = 255 } lastFailureType; } WTPRebootStatisticsInfo; typedef struct { int radioID; int reportInterval; } WTPDecryptErrorReportValues; typedef struct { int radiosCount; WTPDecryptErrorReportValues *radios; } WTPDecryptErrorReport; typedef struct { int index; char *ACName; } CWACNameWithIndexValues; typedef struct { int count; CWACNameWithIndexValues *ACNameIndex; } CWACNamesWithIndex; typedef struct { int ID; enum { CW_802_DOT_11b = 1, CW_802_DOT_11a = 2, CW_802_DOT_11g = 4, CW_802_DOT_11n = 8, CW_ALL_RADIO_TYPES = 0x0F } type; } CWRadioInformationValues; typedef struct { int radiosCount; CWRadioInformationValues *radios; } CWRadiosInformation; typedef enum { ENABLED = 1, DISABLED = 2 } CWstate; typedef enum { AD_NORMAL = 1, AD_RADIO_FAILURE = 2, AD_SOFTWARE_FAILURE = 3, AD_RADAR_DETECTION = 4 } CWAdminCause; typedef enum { OP_NORMAL = 0, OP_RADIO_FAILURE = 1, OP_SOFTWARE_FAILURE = 2, OP_ADMINISTRATIVELY_SET = 3 } CWOperationalCause; typedef struct { int ID; CWstate state; CWAdminCause cause; } CWRadioAdminInfoValues; typedef struct { int radiosCount; CWRadioAdminInfoValues *radios; } CWRadiosAdminInfo; typedef struct { int ID; CWstate state; CWOperationalCause cause; } CWRadioOperationalInfoValues; typedef struct { int radiosCount; CWRadioOperationalInfoValues *radios; } CWRadiosOperationalInfo; typedef struct { int ID; unsigned char numEntries; unsigned char length; CWMACAddress *decryptErrorMACAddressList; } CWDecryptErrorReportValues; typedef struct { int radiosCount; CWDecryptErrorReportValues *radios; } CWDecryptErrorReportInfo; typedef struct { enum { STATISTICS_NOT_SUPPORTED = 0, SW_FAILURE_TYPE = 1, HD_FAILURE_TYPE = 2, OTHER_TYPES = 3, UNKNOWN_TYPE = 255 } lastFailureType; short int resetCount; short int SWFailureCount; short int HWFailuireCount; short int otherFailureCount; short int unknownFailureCount; short int configUpdateCount; short int channelChangeCount; short int bandChangeCount; short int currentNoiseFloor; } WTPRadioStatisticsInfo; typedef struct { unsigned int radioID; //Station Mac Address List CWList decryptErrorMACAddressList; unsigned int reportInterval; CWstate adminState; CWAdminCause adminCause; CWstate operationalState; CWOperationalCause operationalCause; unsigned int TxQueueLevel; unsigned int wirelessLinkFramesPerSec; WTPRadioStatisticsInfo statistics; void *bindingValuesPtr; } CWWTPRadioInfoValues; typedef struct { int radioCount; CWWTPRadioInfoValues *radiosInfo; } CWWTPRadiosInfo; /*Update 2009: Helper structure to keep track of requested UCI commands (via Vendor specific message)*/ typedef struct { unsigned short vendorPayloadType; void *payload; } CWProtocolVendorSpecificValues; #include "CWList.h" /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ unsigned int CWGetSeqNum(); // provided by the user of CWProtocol lib int CWGetFragmentID(); // provided by the user of CWProtocol lib void CWWTPResetRadioStatistics(WTPRadioStatisticsInfo * radioStatistics); void CWProtocolDestroyMsgElemData(void *f); void CWFreeMessageFragments(CWProtocolMessage * messages, int fragmentsNum); void CWProtocolStore8(CWProtocolMessage * msgPtr, unsigned char val); void CWProtocolStore16(CWProtocolMessage * msgPtr, unsigned short val); void CWProtocolStore32(CWProtocolMessage * msgPtr, unsigned int val); void CWProtocolStoreStr(CWProtocolMessage * msgPtr, char *str); void CWProtocolStoreMessage(CWProtocolMessage * msgPtr, CWProtocolMessage * msgToStorePtr); void CWProtocolStoreRawBytes(CWProtocolMessage * msgPtr, unsigned char *bytes, int len); unsigned char CWProtocolRetrieve8(CWProtocolMessage * msgPtr); unsigned short CWProtocolRetrieve16(CWProtocolMessage * msgPtr); unsigned int CWProtocolRetrieve32(CWProtocolMessage * msgPtr); char *CWProtocolRetrieveStr(CWProtocolMessage * msgPtr, int len); unsigned char *CWProtocolRetrieveRawBytes(CWProtocolMessage * msgPtr, unsigned int len); CWBool CWProtocolParseFragment(unsigned char *buf, int readBytes, CWList * fragmentsListPtr, CWProtocolMessage * reassembledMsg, CWBool * dataFlag, unsigned char *RadioMAC); void CWProtocolDestroyFragment(void *f); CWBool CWParseTransportHeader(CWProtocolMessage * msgPtr, CWProtocolTransportHeaderValues * valuesPtr, CWBool * dataFlag, unsigned char *RadioMAC); CWBool CWParseControlHeader(CWProtocolMessage * msgPtr, CWControlHeaderValues * valPtr); CWBool CWParseFormatMsgElem(CWProtocolMessage * completeMsg, unsigned short int *type, unsigned short int *len); CWBool CWAssembleTransportHeader(CWProtocolMessage * transportHdrPtr, CWProtocolTransportHeaderValues * valuesPtr); CWBool CWAssembleTransportHeaderKeepAliveData(CWProtocolMessage * transportHdrPtr, CWProtocolTransportHeaderValues * valuesPtr, int keepAlive); CWBool CWAssembleControlHeader(CWProtocolMessage * controlHdrPtr, CWControlHeaderValues * valPtr); CWBool CWAssembleMessage(CWProtocolMessage ** completeMsgPtr, int *fragmentsNumPtr, int PMTU, int seqNum, int msgTypeValue, CWProtocolMessage * msgElems, const int msgElemNum, CWProtocolMessage * msgElemsBinding, const int msgElemBindingNum); CWBool CWAssembleMsgElem(CWProtocolMessage * msgPtr, unsigned int type); CWBool CWAssembleUnrecognizedMessageResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, int msgType); CWBool CWAssembleMsgElemRadioAdminState(CWProtocolMessage * msgPtr); //29 CWBool CWAssembleMsgElemRadioOperationalState(int radioID, CWProtocolMessage * msgPtr); //30 CWBool CWAssembleMsgElemResultCode(CWProtocolMessage * msgPtr, CWProtocolResultCode code); //31 CWBool CWAssembleVendorMsgElemResultCodeWithPayload(CWProtocolMessage * msgPtr, CWProtocolResultCode code, CWProtocolVendorSpecificValues * payload); //49 CWBool CWAssembleMsgElemSessionID(CWProtocolMessage * msgPtr, unsigned char *sessionID); //32 CWBool CWParseACName(CWProtocolMessage * msgPtr, int len, char **valPtr); CWBool CWParseWTPRadioOperationalState(CWProtocolMessage * msgPtr, int len, CWRadioOperationalInfoValues * valPtr); //30 CWBool CWParseResultCode(CWProtocolMessage * msgPtr, int len, CWProtocolResultCode * valPtr); //31 unsigned char *CWParseSessionID(CWProtocolMessage * msgPtr, int len); #endif ================================================ FILE: CWRandom.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif __inline__ void CWRandomInitLib() { // set seed srand((unsigned)time(NULL)); } __inline__ int CWRandomIntInRange(int min, int max) { return min + (rand() % (max - min)); } ================================================ FILE: CWRandom.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWRandom_HEADER__ #define __CAPWAP_CWRandom_HEADER__ void CWRandomInitLib(); int CWRandomIntInRange(int min, int max); #endif ================================================ FILE: CWSafeList.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWCreateSafeList(CWSafeList * pSafeList) { CWPrivateSafeList *pNewList; if (pSafeList == NULL) return CW_FALSE; CW_CREATE_OBJECT_ERR(pNewList, CWPrivateSafeList, return CW_FALSE; ); // pNewList->pThreadMutex = NULL; pNewList->pThreadCond = NULL; // pNewList->nCount = 0; pNewList->pFirstElement = NULL; pNewList->pLastElement = NULL; // (*pSafeList) = (CWSafeList) pNewList; return CW_TRUE; } void CWDestroySafeList(CWSafeList safeList) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if (pList == NULL) return; // CW_FREE_OBJECT(pList); } void CWSetMutexSafeList(CWSafeList safeList, CWThreadMutex * pThreadMutex) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if (pList == NULL) return; pList->pThreadMutex = pThreadMutex; } void CWSetConditionSafeList(CWSafeList safeList, CWThreadCondition * pThreadCond) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if (pList == NULL) return; pList->pThreadCond = pThreadCond; } CWBool CWLockSafeList(CWSafeList safeList) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if ((pList == NULL) || (pList->pThreadMutex == NULL)) return CW_FALSE; // return CWThreadMutexLock(pList->pThreadMutex); } void CWUnlockSafeList(CWSafeList safeList) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if ((pList == NULL) || (pList->pThreadMutex == NULL)) return; // CWThreadMutexUnlock(pList->pThreadMutex); } CWBool CWWaitElementFromSafeList(CWSafeList safeList) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if ((pList == NULL) || (pList->pThreadMutex == NULL) || (pList->pThreadCond == NULL)) return CW_FALSE; return CWWaitThreadCondition(pList->pThreadCond, pList->pThreadMutex); } CWBool CWSignalElementSafeList(CWSafeList safeList) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if ((pList == NULL) || (pList->pThreadCond == NULL)) return CW_FALSE; CWSignalThreadCondition(pList->pThreadCond); return CW_TRUE; } unsigned long CWGetCountElementFromSafeList(CWSafeList safeList) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if (pList == NULL) return 0; return pList->nCount; } // No thread-safe CWBool CWAddElementToSafeListHead(CWSafeList safeList, void *pData, int nSize) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; CWPrivateSafeElement *pNewElement; if ((pList == NULL) || (pData == NULL)) return CW_FALSE; CW_CREATE_OBJECT_ERR(pNewElement, CWPrivateSafeElement, return CW_FALSE; ); pNewElement->pData = pData; pNewElement->nSize = nSize; pNewElement->pNext = pList->pFirstElement; pNewElement->pPrev = NULL; if (pList->pFirstElement != NULL) pList->pFirstElement->pPrev = pNewElement; pList->pFirstElement = pNewElement; if (pList->pLastElement == NULL) pList->pLastElement = pNewElement; pList->nCount++; CWSignalElementSafeList(safeList); return CW_TRUE; } // No thread-safe void *CWGetHeadElementFromSafeList(CWSafeList safeList, int *pSize) { CWPrivateSafeElement *pElement; CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; if ((pList == NULL) || (pList->pFirstElement == NULL)) return NULL; pElement = pList->pFirstElement; if (pSize != NULL) *pSize = pElement->nSize; return pElement->pData; } // No thread-safe void *CWRemoveHeadElementFromSafeList(CWSafeList safeList, int *pSize) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; CWPrivateSafeElement *pElement; void *pData; if ((pList == NULL) || (pList->pFirstElement == NULL)) return NULL; pElement = pList->pFirstElement; pList->pFirstElement = pList->pFirstElement->pNext; if (pList->pFirstElement == NULL) pList->pLastElement = NULL; else pList->pFirstElement->pPrev = NULL; pData = pElement->pData; if (pSize != NULL) *pSize = pElement->nSize; CW_FREE_OBJECT(pElement); pList->nCount--; return pData; } // No thread-safe void *CWRemoveHeadElementFromSafeListwithDataFlag(CWSafeList safeList, int *pSize, CWBool * dataFlag) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; CWPrivateSafeElement *pElement; void *pData; if ((pList == NULL) || (pList->pFirstElement == NULL)) return NULL; pElement = pList->pFirstElement; pList->pFirstElement = pList->pFirstElement->pNext; if (pList->pFirstElement == NULL) pList->pLastElement = NULL; else pList->pFirstElement->pPrev = NULL; pData = pElement->pData; *dataFlag = pElement->dataFlag; if (pSize != NULL) *pSize = pElement->nSize; CW_FREE_OBJECT(pElement); pList->nCount--; return pData; } // No thread-safe CWBool CWAddElementToSafeListTail(CWSafeList safeList, void *pData, int nSize) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; CWPrivateSafeElement *pNewElement; if ((pList == NULL) || (pData == NULL)) return CW_FALSE; CW_CREATE_OBJECT_ERR(pNewElement, CWPrivateSafeElement, return CW_FALSE; ); pNewElement->pData = pData; pNewElement->nSize = nSize; pNewElement->pNext = NULL; pNewElement->pPrev = pList->pLastElement; if (pList->pLastElement != NULL) pList->pLastElement->pNext = pNewElement; pList->pLastElement = pNewElement; if (pList->pFirstElement == NULL) pList->pFirstElement = pNewElement; pList->nCount++; CWSignalElementSafeList(safeList); return CW_TRUE; } CWBool CWAddElementToSafeListTailwitDataFlag(CWSafeList safeList, void *pData, int nSize, CWBool dataFlag) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; CWPrivateSafeElement *pNewElement; if ((pList == NULL) || (pData == NULL)) return CW_FALSE; CW_CREATE_OBJECT_ERR(pNewElement, CWPrivateSafeElement, return CW_FALSE; ); pNewElement->pData = pData; pNewElement->nSize = nSize; pNewElement->dataFlag = dataFlag; pNewElement->pNext = NULL; pNewElement->pPrev = pList->pLastElement; if (pList->pLastElement != NULL) pList->pLastElement->pNext = pNewElement; pList->pLastElement = pNewElement; if (pList->pFirstElement == NULL) pList->pFirstElement = pNewElement; pList->nCount++; CWSignalElementSafeList(safeList); return CW_TRUE; } // No thread-safe void *CWRemoveTailElementFromSafeList(CWSafeList safeList, int *pSize) { CWPrivateSafeList *pList = (CWPrivateSafeList *) safeList; CWPrivateSafeElement *pElement; void *pData; if ((pList == NULL) || (pList->pLastElement == NULL)) return NULL; pElement = pList->pLastElement; pList->pLastElement = pList->pLastElement->pPrev; if (pList->pLastElement == NULL) pList->pFirstElement = NULL; else pList->pLastElement->pNext = NULL; pData = pElement->pData; if (pSize != NULL) *pSize = pElement->nSize; CW_FREE_OBJECT(pElement); pList->nCount--; return pData; } // No thread-safe void CWCleanSafeList(CWSafeList safeList, void (*deleteFunc) (void *)) { void *pData; CW_REPEAT_FOREVER { pData = CWRemoveHeadElementFromSafeList(safeList, NULL); if (pData == NULL) break; if (deleteFunc != NULL) deleteFunc(pData); } } ================================================ FILE: CWSafeList.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWSafeList_HEADER__ #define __CAPWAP_CWSafeList_HEADER__ #include "CWThread.h" typedef void *CWSafeList; typedef struct _CWPrivateSafeElement { void *pData; int nSize; CWBool dataFlag; struct _CWPrivateSafeElement *pPrev; struct _CWPrivateSafeElement *pNext; } CWPrivateSafeElement; typedef struct _CWPrivateSafeList { CWThreadMutex *pThreadMutex; CWThreadCondition *pThreadCond; unsigned long nCount; CWPrivateSafeElement *pFirstElement; CWPrivateSafeElement *pLastElement; } CWPrivateSafeList; CWBool CWCreateSafeList(CWSafeList * pSafeList); void CWDestroySafeList(CWSafeList safeList); void CWSetMutexSafeList(CWSafeList safeList, CWThreadMutex * pThreadMutex); void CWSetConditionSafeList(CWSafeList safeList, CWThreadCondition * pThreadCond); CWBool CWLockSafeList(CWSafeList safeList); void CWUnlockSafeList(CWSafeList safeList); CWBool CWWaitElementFromSafeList(CWSafeList safeList); CWBool CWSignalElementSafeList(CWSafeList safeList); unsigned long CWGetCountElementFromSafeList(CWSafeList safeList); CWBool CWAddElementToSafeListHead(CWSafeList safeList, void *pData, int nSize); void *CWGetHeadElementFromSafeList(CWSafeList safeList, int *pSize); void *CWRemoveHeadElementFromSafeList(CWSafeList safeList, int *pSize); void *CWRemoveHeadElementFromSafeListwithDataFlag(CWSafeList safeList, int *pSize, CWBool * dataFlag); CWBool CWAddElementToSafeListTail(CWSafeList safeList, void *pData, int nSize); CWBool CWAddElementToSafeListTailwitDataFlag(CWSafeList safeList, void *pData, int nSize, CWBool dataFlag); void *CWRemoveTailElementFromSafeList(CWSafeList safeList, int *pSize); void CWCleanSafeList(CWSafeList safeList, void (*deleteFunc) (void *)); #endif ================================================ FILE: CWSecurity.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #include "CWAC.h" #include #include #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define CW_DTLS_CERT_VERIFY_DEPTH 1 #if (OPENSSL_VERSION_NUMBER < 0x000908000) #error "Must use CAPWAP Hacked OpenSSL 0.9.8a or later" #endif static char *gSecurityPassword; static CWBool useCertificate; static CWThreadMutex *mutexOpensslBuf = NULL; CWBool CWSecurityVerifyPeerCertificateForCAPWAP(SSL * ssl, CWBool isClient); static int CWDTLSPasswordCB(char *buf, int num, int rwflag, void *userdata); int CWSecurityVerifyCB(int ok, X509_STORE_CTX * ctx); unsigned int CWSecurityPSKClientCB(SSL * ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len); unsigned int CWSecurityPSKServerCB(SSL * ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len); int psk_key2bn(const char *psk_key, unsigned char *psk, unsigned int max_psk_len); void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, unsigned int (*callback)(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len)); void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, unsigned int (*callback)(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len)); #define CWSecurityGetErrorStr() ((const char *) ERR_error_string(ERR_get_error(), NULL)) #define CWDTLSGetError() "Err" #define CWSecurityRaiseError(error) { \ char buf[256]; \ ERR_error_string(ERR_get_error(), buf); \ CWErrorRaise(error, buf); \ return CW_FALSE; \ } #define CWSecurityRaiseSystemError(error) { \ char buf[256]; \ strerror_r(errno, buf, 256); \ CWErrorRaise(error, buf); \ return CW_FALSE; \ } #define CWSecurityManageSSLError(arg, session, stuff) { \ char ___buf[256]; \ int r; \ \ if((r=(arg)) <= 0) { \ {stuff} \ ERR_error_string(/*SSL_get_error((session),r)*/ ERR_get_error(), ___buf); \ CWDebugLog(strerror(errno));CWErrorRaise(CW_ERROR_GENERAL, ___buf); \ return CW_FALSE; \ } \ } static void CWSslLockingFunc(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) CWThreadMutexLock(&mutexOpensslBuf[n]); else CWThreadMutexUnlock(&mutexOpensslBuf[n]); return; } static unsigned long CWSslIdFunction() { return (unsigned long)pthread_self(); } void CWSslCleanUp() { int i; if (mutexOpensslBuf == NULL) return; for (i = 0; i < CRYPTO_num_locks(); i++) { CWDestroyThreadMutex(&mutexOpensslBuf[i]); } CW_FREE_OBJECT(mutexOpensslBuf); mutexOpensslBuf = NULL; return; } CWBool CWSecurityInitLib() { int i; SSL_load_error_strings(); SSL_library_init(); /* setup mutexes for openssl internal locking */ CW_CREATE_ARRAY_ERR(mutexOpensslBuf, CRYPTO_num_locks() * sizeof(CWThreadMutex), CWThreadMutex, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, "Cannot create openssl mutexes"); ) CW_ZERO_MEMORY(mutexOpensslBuf, CRYPTO_num_locks() * sizeof(CWThreadMutex)); for (i = 0; i < CRYPTO_num_locks(); i++) { CWBool rv; rv = CWCreateThreadMutex(&mutexOpensslBuf[i]); if (rv != CW_TRUE) { CWSslCleanUp(); return CWErrorRaise(CW_ERROR_CREATING, "Cannot create openssl mutexes"); } } CRYPTO_set_id_callback(CWSslIdFunction); CRYPTO_set_locking_callback(CWSslLockingFunc); return CW_TRUE; } CWBool CWSecurityInitSessionClient(CWSocket sock, CWNetworkLev4Address * addrPtr, CWSafeList packetReceiveList, CWSecurityContext ctx, CWSecuritySession * sessionPtr, int *PMTUPtr) { BIO *sbio = NULL; CWNetworkLev4Address peer; int peerlen = sizeof(peer); if (ctx == NULL || sessionPtr == NULL || PMTUPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((*sessionPtr = SSL_new(ctx)) == NULL) { CWSecurityRaiseError(CW_ERROR_CREATING); } #ifdef CW_DEBUGGING CWDebugLog("My Certificate"); PEM_write_X509(stdout, SSL_get_certificate(*sessionPtr)); #endif if ((sbio = BIO_new_memory(sock, addrPtr, packetReceiveList)) == NULL) { SSL_free(*sessionPtr); CWSecurityRaiseError(CW_ERROR_CREATING); } if (getsockname(sock, (struct sockaddr *)&peer, (void *)&peerlen) < 0) { SSL_free(*sessionPtr); CWSecurityRaiseSystemError(CW_ERROR_GENERAL); } /* BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); // TO-DO (pass MTU?) */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); /* * TO-DO if we don't set a big MTU, the DTLS implementation will * not be able to use a big certificate */ /* BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_MTU, 10000, NULL); */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_MTU, 1388, NULL); /* * Let the verify_callback catch the verify_depth error so that we get * an appropriate error in the logfile. */ SSL_set_verify_depth((*sessionPtr), CW_DTLS_CERT_VERIFY_DEPTH + 1); SSL_set_options((*sessionPtr), SSL_OP_NO_QUERY_MTU); SSL_set_mtu((*sessionPtr), 1388); /* required by DTLS implementation to avoid data loss */ SSL_set_read_ahead((*sessionPtr), 1); SSL_set_bio((*sessionPtr), sbio, sbio); SSL_set_connect_state((*sessionPtr)); CWDebugLog("Before HS"); CWSecurityManageSSLError(SSL_do_handshake(*sessionPtr), *sessionPtr, SSL_free(*sessionPtr); ); CWDebugLog("After HS"); if (SSL_get_verify_result(*sessionPtr) == X509_V_OK) { CWDebugLog("Certificate Verified"); } else { CWDebugLog("Certificate Error (%d)", SSL_get_verify_result(*sessionPtr)); } /* *PMTUPtr = BIO_ctrl(sbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); */ *PMTUPtr = BIO_ctrl(sbio, BIO_CTRL_DGRAM_GET_MTU, 0, NULL); CWDebugLog("PMTU: %d", *PMTUPtr); if (useCertificate) { if (CWSecurityVerifyPeerCertificateForCAPWAP((*sessionPtr), CW_TRUE)) { CWDebugLog("Certificate Ok for CAPWAP"); } else { CWDebugLog("Certificate Not Ok for CAPWAP"); #ifndef CW_DEBUGGING return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Certificate Not Ok for CAPWAP"); #endif } } return CW_TRUE; } void CWSecurityCloseSession(CWSecuritySession * sPtr) { SSL_free(*sPtr); } CWBool CWSecurityReceive(CWSecuritySession session, char *buf, int len, int *readBytesPtr) { CWSecurityManageSSLError((*readBytesPtr = SSL_read(session, buf, len)), session,; ); CWDebugLog("Received packet\n"); /* if(SSL_read(session, buf, len) <= 0) { if((SSL_get_shutdown(session) & SSL_RECEIVED_SHUTDOWN) == SSL_RECEIVED_SHUTDOWN) { // session aborted by peer CWDebugLog("Connection Aborted by Peer"); SSL_shutdown(session); // respond return CW_ABORTED; } // error... } */ return CW_TRUE; } CWBool CWSecuritySend(CWSecuritySession session, const char *buf, int len) { if (buf == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWSecurityManageSSLError(SSL_write(session, buf, len), session,; ); CWDebugLog("Packet Sent\n"); return CW_TRUE; } CWBool CWSecurityInitSessionServer(CWWTPManager * pWtp, CWSocket sock, CWSecurityContext ctx, CWSecuritySession * sessionPtr, int *PMTUPtr) { BIO *sbio = NULL; if (ctx == NULL || sessionPtr == NULL || PMTUPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((*sessionPtr = SSL_new(ctx)) == NULL) { CWSecurityRaiseError(CW_ERROR_CREATING); } if ((sbio = BIO_new_memory(sock, &pWtp->address, pWtp->packetReceiveList)) == NULL) { SSL_free(*sessionPtr); CWSecurityRaiseError(CW_ERROR_CREATING); } /* BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); // TO-DO (pass MTU?) */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); /* * TO-DO if we don't set a big MTU, the DTLS implementation will * not be able to use a big certificate */ /* BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_MTU, 10000, NULL); */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_MTU, 1388, NULL); /* * Let the verify_callback catch the verify_depth error so that we get * an appropriate error in the logfile. */ SSL_set_verify_depth((*sessionPtr), CW_DTLS_CERT_VERIFY_DEPTH + 1); SSL_set_options((*sessionPtr), SSL_OP_NO_QUERY_MTU); SSL_set_mtu((*sessionPtr), 1388); /* required by DTLS implementation to avoid data loss */ SSL_set_read_ahead((*sessionPtr), 1); /* turn on cookie exchange */ SSL_set_options((*sessionPtr), SSL_OP_COOKIE_EXCHANGE); /* set the same bio for reading and writing */ SSL_set_bio((*sessionPtr), sbio, sbio); /* tell OpenSSL we are a server */ SSL_set_accept_state((*sessionPtr)); CWDebugLog("Before HS"); CWSecurityManageSSLError(SSL_do_handshake(*sessionPtr), *sessionPtr, SSL_free(*sessionPtr); ); CWDebugLog("After HS"); if (SSL_get_verify_result(*sessionPtr) == X509_V_OK) { CWDebugLog("Certificate Verified"); } else { CWDebugLog("Certificate Error (%d)", SSL_get_verify_result(*sessionPtr)); } if (useCertificate) { if (CWSecurityVerifyPeerCertificateForCAPWAP((*sessionPtr), CW_FALSE)) { CWDebugLog("Certificate Ok for CAPWAP"); } else { CWDebugLog("Certificate Not Ok for CAPWAP"); #ifndef CW_DEBUGGING return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Certificate Not Ok for CAPWAP"); #endif } } /* PMTUPtr = BIO_ctrl(sbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); */ *PMTUPtr = BIO_ctrl(sbio, BIO_CTRL_DGRAM_GET_MTU, 0, NULL); CWDebugLog("PMTU: %d", *PMTUPtr); return CW_TRUE; } /* * NULL caList means that we want pre-shared keys */ CWBool CWSecurityInitContext(CWSecurityContext * ctxPtr, const char *caList, const char *keyfile, const char *passw, CWBool isClient, int (*hackPtr) (void *)) { if (ctxPtr == NULL || (caList != NULL && (keyfile == NULL || passw == NULL))) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } if (((*ctxPtr) = SSL_CTX_new((isClient) ? DTLSv1_client_method() : DTLSv1_server_method())) == NULL) { CWSecurityRaiseError(CW_ERROR_CREATING); } /* certificates */ if (caList != NULL) { useCertificate = CW_TRUE; /* load keys and certificates */ if (!(SSL_CTX_use_certificate_file((*ctxPtr), keyfile, SSL_FILETYPE_PEM))) { SSL_CTX_free((*ctxPtr)); CWSecurityRaiseError(CW_ERROR_GENERAL); } /* store password */ gSecurityPassword = (char *)passw; SSL_CTX_set_default_passwd_cb((*ctxPtr), CWDTLSPasswordCB); if (!(SSL_CTX_use_PrivateKey_file((*ctxPtr), keyfile, SSL_FILETYPE_PEM))) { SSL_CTX_free((*ctxPtr)); CWSecurityRaiseError(CW_ERROR_GENERAL); } if (!SSL_CTX_check_private_key((*ctxPtr))) { SSL_CTX_free((*ctxPtr)); CWSecurityRaiseError(CW_ERROR_GENERAL); } /* load the CAs we trust */ if (!(SSL_CTX_load_verify_locations((*ctxPtr), caList, 0))) { SSL_CTX_free((*ctxPtr)); CWSecurityRaiseError(CW_ERROR_GENERAL); } SSL_CTX_set_default_verify_paths((*ctxPtr)); if (!isClient) { /* require client authentication */ SSL_CTX_set_verify((*ctxPtr), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, CWSecurityVerifyCB); } else { SSL_CTX_set_verify((*ctxPtr), SSL_VERIFY_PEER, CWSecurityVerifyCB); } /* RFC 5415 ciphers: * * MUST support: * - TLS_RSA_WITH_AES_128_CBC_SHA * * SHOULD support: * - TLS_DHE_RSA_WITH_AES_128_CBC_SHA * - TLS_RSA_WITH_AES_256_CBC_SHA * * MAY support: * - TLS_DHE_RSA_WITH_AES_256_CBC_SHA * * Explicitly add ECDHE ciphers as they are much faster, especialy on slower hardware */ /* set the ciphers supported by CAPWAP */ SSL_CTX_set_cipher_list((*ctxPtr), "ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES128-SHA"); } else { /* pre-shared keys */ /* RFC 5415 ciphers: * * MUST support: * - TLS_PSK_WITH_AES_128_CBC_SHA * - TLS_DHE_PSK_WITH_AES_128_CBC_SHA (not supported in OpenSSL) * * MAY support: * - TLS_PSK_WITH_AES_256_CBC_SHA * - TLS_DHE_PSK_WITH_AES_256_CBC_SHA (not supported in OpenSSL) */ useCertificate = CW_FALSE; SSL_CTX_set_cipher_list((*ctxPtr), "PSK-AES128-CBC-SHA:PSK-AES256-CBC-SHA"); if(isClient) { CWDebugLog("Client PSK"); SSL_CTX_set_psk_client_callback( (*ctxPtr), CWSecurityPSKClientCB); } else { CWDebugLog("Server PSK"); SSL_CTX_set_psk_server_callback( (*ctxPtr), CWSecurityPSKServerCB); } } /* needed for DTLS */ SSL_CTX_set_read_ahead((*ctxPtr), 1); return CW_TRUE; } void CWSecurityDestroyContext(CWSecurityContext ctx) { if (ctx != NULL) SSL_CTX_free(ctx); } void CWSecurityDestroySession(CWSecuritySession s) { if (s != NULL) { //if(s->rbio != NULL) BIO_free(s->rbio); SSL_free(s); } } CWBool CWSecurityVerifyCertEKU(X509 * x509, const char *const expected_oid) { EXTENDED_KEY_USAGE *eku = NULL; CWBool fFound = CW_FALSE; /* LE-03-02-2010.02 */ if (x509 == NULL) return CW_FALSE; if ((eku = (EXTENDED_KEY_USAGE *) X509_get_ext_d2i(x509, NID_ext_key_usage, NULL, NULL)) == NULL) { CWDebugLog("Certificate does not have extended key usage extension"); } else { int i; CWDebugLog("Validating certificate extended key usage"); for (i = 0; !fFound && i < sk_ASN1_OBJECT_num(eku); i++) { ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(eku, i); char szOid[1024]; if (!fFound && OBJ_obj2txt(szOid, sizeof(szOid), oid, 0) != -1) { CWDebugLog("Certificate has EKU (str) %s, expects %s", szOid, expected_oid); if (!strcmp(expected_oid, szOid)) { fFound = CW_TRUE; } } if (!fFound && OBJ_obj2txt(szOid, sizeof(szOid), oid, 1) != -1) { CWDebugLog("Certificate has EKU (oid) %s, expects %s", szOid, expected_oid); if (!strcmp(expected_oid, szOid)) { fFound = CW_TRUE; } } } } if (eku != NULL) { sk_ASN1_OBJECT_pop_free(eku, ASN1_OBJECT_free); } return fFound; } /* * modificare questa funzione */ CWBool CWSecurityVerifyPeerCertificateForCAPWAP(SSL * ssl, CWBool isClient) { if (ssl == NULL) return CW_FALSE; if (!isClient) { return CWSecurityVerifyCertEKU(SSL_get_peer_certificate(ssl), "1.3.6.1.5.5.7.3.19"); /* value expected for WTP */ } else { return CWSecurityVerifyCertEKU(SSL_get_peer_certificate(ssl), "1.3.6.1.5.5.7.3.18"); /* value expected for AC */ } } /* * callbacks */ static int CWDTLSPasswordCB(char *buf, int num, int rwflag, void *userdata) { if (buf == NULL || num < strlen(gSecurityPassword) + 1) return 0; strcpy(buf, gSecurityPassword); return strlen(gSecurityPassword); } int CWSecurityVerifyCB(int ok, X509_STORE_CTX * ctx) { char buf[256]; X509 *err_cert; int err, depth; int preverify_ok = 1; err_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); CWDebugLog(X509_verify_cert_error_string(err)); depth = X509_STORE_CTX_get_error_depth(ctx); /* * Retrieve the pointer to the SSL of the connection currently treated * and the application specific data stored into the SSL object. */ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); /* * Catch a too long certificate chain. The depth limit set using * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so * That whenever the "depth>verify_depth" condition is met, we * have violated the limit and want to log this error condition. * We must do it here, because the CHAIN_TOO_LONG error would not * be found explicitly; only errors introduced by cutting off the * additional certificates would be logged. */ if (depth > CW_DTLS_CERT_VERIFY_DEPTH) { preverify_ok = 0; err = X509_V_ERR_CERT_CHAIN_TOO_LONG; X509_STORE_CTX_set_error(ctx, err); } if (!preverify_ok) { CWDebugLog("verify error:num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf); } else { CWDebugLog("depth=%d:%s\n", depth, buf); } /* * At this point, err contains the last verification error. We can use * it for something special */ if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) { X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); CWDebugLog("issuer= %s\n", buf); } return preverify_ok; } unsigned int CWSecurityPSKClientCB(SSL * ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { /* TO-DO load identity from config */ if (snprintf(identity, max_identity_len, "CLient_identity") < 0) return 0; /* TO-DO load keys from... Plain-text config file? Leave them hard-coded? */ return psk_key2bn("1a2b3c", psk, max_psk_len); } unsigned int CWSecurityPSKServerCB(SSL * ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { CWDebugLog("Identity: %s, PSK: %s", identity, psk); /* TO-DO load keys from... Plain-text config file? Leave them hard-coded? */ return psk_key2bn("1a2b3c", psk, max_psk_len); } /* * Convert the PSK key (psk_key) in ascii to binary (psk). */ int psk_key2bn(const char *psk_key, unsigned char *psk, unsigned int max_psk_len) { unsigned int psk_len = 0; int ret; BIGNUM *bn = NULL; ret = BN_hex2bn(&bn, psk_key); if (!ret) { printf("Could not convert PSK key '%s' to BIGNUM\n", psk_key); if (bn) BN_free(bn); return 0; } if (BN_num_bytes(bn) > max_psk_len) { printf("psk buffer of callback is too small (%d) for key (%d)\n", max_psk_len, BN_num_bytes(bn)); BN_free(bn); return 0; } psk_len = BN_bn2bin(bn, psk); BN_free(bn); if (psk_len < 0) goto out_err; return psk_len; out_err: return 0; } ================================================ FILE: CWSecurity.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWSecurity_HEADER__ #define __CAPWAP_CWSecurity_HEADER__ #include #include #include typedef SSL_CTX *CWSecurityContext; typedef SSL *CWSecuritySession; #define CWSecuritySetPeerForSession(session, addrPtr) BIO_ctrl((session)->rbio, BIO_CTRL_DGRAM_SET_PEER, 1, (addrPtr)) CWBool CWSecurityInitLib(void); CWBool CWSecurityInitSessionClient(CWSocket sock, CWNetworkLev4Address * addrPtr, CWSafeList packetReceiveList, CWSecurityContext ctx, CWSecuritySession * sessionPtr, int *PMTUPtr); CWBool CWSecuritySend(CWSecuritySession session, const char *buf, int len); CWBool CWSecurityReceive(CWSecuritySession session, char *buf, int len, int *readBytesPtr); CWBool CWSecurityInitContext(CWSecurityContext * ctxPtr, const char *caList, const char *keyfile, const char *passw, CWBool isClient, int (*hackPtr) (void *)); void CWSecurityDestroyContext(CWSecurityContext ctx); void CWSecurityDestroySession(CWSecuritySession s); BIO *BIO_new_memory(CWSocket sock, CWNetworkLev4Address * pSendAddress, CWSafeList * pRecvAddress); void CWSslCleanUp(); #endif ================================================ FILE: CWStevens.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #include #ifdef HAVE_SOCKADDR_DL_STRUCT #include #endif #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif // an extension to Unix Network Programming's library: a thread-safe version of sock_ntop and a couple of // functions to manage port number in IPv4/6 /* include sock_ntop */ char *sock_ntop_r(const struct sockaddr *sa, char *str) { char portstr[8]; switch (sa->sa_family) { case AF_INET:{ struct sockaddr_in *sin = (struct sockaddr_in *)sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, 128) == 0) return (NULL); if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port)); strcat(str, portstr); } return (str); } /* end sock_ntop */ #ifdef IPV6 case AF_INET6:{ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; str[0] = '['; if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, 128 - 1) == NULL) return (NULL); if (ntohs(sin6->sin6_port) != 0) { snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port)); strcat(str, portstr); return (str); } return (str + 1); } #endif #ifdef AF_UNIX case AF_UNIX:{ struct sockaddr_un *unp = (struct sockaddr_un *)sa; /* OK to have no pathname bound to the socket: happens on every connect() unless client calls bind() first. */ if (unp->sun_path[0] == 0) strcpy(str, "(no pathname bound)"); else snprintf(str, 128, "%s", unp->sun_path); return (str); } #endif #ifdef HAVE_SOCKADDR_DL_STRUCT case AF_LINK:{ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_nlen > 0) snprintf(str, 128, "%*s (index %d)", sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index); else snprintf(str, 128, "AF_LINK, index=%d", sdl->sdl_index); return (str); } #endif default: snprintf(str, 128, "sock_ntop: unknown AF_xxx: %d", sa->sa_family); return (str); } return (NULL); } int sock_cpy_addr_port(struct sockaddr *sa1, const struct sockaddr *sa2) { sa1->sa_family = sa2->sa_family; switch (sa1->sa_family) { case AF_INET:{ (memcpy(&((struct sockaddr_in *)sa1)->sin_addr, &((struct sockaddr_in *)sa2)->sin_addr, sizeof(struct in_addr))); ((struct sockaddr_in *)sa1)->sin_port = ((struct sockaddr_in *)sa2)->sin_port; return 0; } #ifdef IPV6 case AF_INET6:{ (memcpy(&((struct sockaddr_in6 *)sa1)->sin6_addr, &((struct sockaddr_in6 *)sa2)->sin6_addr, sizeof(struct in6_addr))); (((struct sockaddr_in6 *)sa1)->sin6_port = ((struct sockaddr_in6 *)sa2)->sin6_port); return 0; } #endif #ifdef AF_UNIX case AF_UNIX:{ (strcpy(((struct sockaddr_un *)sa1)->sun_path, ((struct sockaddr_un *)sa2)->sun_path)); return 0; } #endif #ifdef HAVE_SOCKADDR_DL_STRUCT case AF_LINK:{ return (-1); /* no idea what to copy here ? */ } #endif } return (-1); } void sock_set_port_cw(struct sockaddr *sa, int port) { switch (sa->sa_family) { case AF_INET:{ struct sockaddr_in *sin = (struct sockaddr_in *)sa; sin->sin_port = port; return; } #ifdef IPV6 case AF_INET6:{ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; sin6->sin6_port = port; return; } #endif } return; } struct ifi_info *get_ifi_info(int family, int doaliases) { struct ifi_info *ifi, *ifihead, **ifipnext; int sockfd, len, lastlen, flags, idx = 0; char *ptr, *buf, lastname[IFNAMSIZ], *cptr, *sdlname; struct ifconf ifc; struct ifreq *ifr, ifrcopy; struct sockaddr_in *sinptr; struct sockaddr_in6 *sin6ptr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); lastlen = 0; len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ for (;;) { buf = (char *)malloc(len); ifc.ifc_len = len; ifc.ifc_buf = buf; if (ioctl(sockfd, SIOCGIFCONF, &ifc) >= 0) { if (ifc.ifc_len == lastlen) break; /* success, len has not changed */ lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); /* increment */ free(buf); } ifihead = NULL; ifipnext = &ifihead; lastname[0] = 0; sdlname = NULL; for (ptr = buf; ptr < buf + ifc.ifc_len;) { ifr = (struct ifreq *)ptr; #ifdef HAVE_SOCKADDR_SA_LEN len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); #else switch (ifr->ifr_addr.sa_family) { #ifdef IPV6 case AF_INET6: len = sizeof(struct sockaddr_in6); break; #endif case AF_INET: default: len = sizeof(struct sockaddr); break; } #endif /* HAVE_SOCKADDR_SA_LEN */ ptr += sizeof(struct ifreq); /* for next one in buffer */ #ifdef HAVE_SOCKADDR_DL_STRUCT /* assumes that AF_LINK precedes AF_INET or AF_INET6 */ if (ifr->ifr_addr.sa_family == AF_LINK) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; sdlname = ifr->ifr_name; idx = sdl->sdl_index; haddr = sdl->sdl_data + sdl->sdl_nlen; hlen = sdl->sdl_alen; } #endif if (ifr->ifr_addr.sa_family != family) continue; /* ignore if not desired address family */ if ((cptr = strchr(ifr->ifr_name, ':')) != NULL) *cptr = 0; /* replace colon with null */ if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { if (doaliases == 0) continue; /* already processed this interface */ } memcpy(lastname, ifr->ifr_name, IFNAMSIZ); ifrcopy = *ifr; ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); flags = ifrcopy.ifr_flags; if ((flags & IFF_UP) == 0) continue; /* ignore if interface not up */ ifi = (struct ifi_info *)calloc(1, sizeof(struct ifi_info)); *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ ifi->ifi_flags = flags; /* IFF_xxx values */ memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); ifi->ifi_name[IFI_NAME - 1] = '\0'; /* If the sockaddr_dl is from a different interface, ignore it */ if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0) idx = 0; ifi->ifi_index = idx; switch (ifr->ifr_addr.sa_family) { case AF_INET: sinptr = (struct sockaddr_in *)&ifr->ifr_addr; ifi->ifi_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); #ifdef SIOCGIFBRDADDR if (flags & IFF_BROADCAST) { ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy); sinptr = (struct sockaddr_in *)&ifrcopy.ifr_broadaddr; ifi->ifi_brdaddr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); } #endif /* * LE03 - Donato Capitella */ break; case AF_INET6: sin6ptr = (struct sockaddr_in6 *)&ifr->ifr_addr; ifi->ifi_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6)); break; default: break; } } free(buf); return (ifihead); /* pointer to first structure in linked list */ } /* end get_ifi_info4 */ /* include free_ifi_info */ void free_ifi_info(struct ifi_info *ifihead) { struct ifi_info *ifi, *ifinext; for (ifi = ifihead; ifi != NULL; ifi = ifinext) { if (ifi->ifi_addr != NULL) free(ifi->ifi_addr); if (ifi->ifi_brdaddr != NULL) free(ifi->ifi_brdaddr); ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ free(ifi); /* the ifi_info{} itself */ } } /* end free_ifi_info */ int sock_cmp_port(const struct sockaddr *sa1, const struct sockaddr *sa2, socklen_t salen) { if (sa1->sa_family != sa2->sa_family) return (-1); switch (sa1->sa_family) { case AF_INET:{ return (memcmp(&((struct sockaddr_in *)sa1)->sin_port, &((struct sockaddr_in *)sa2)->sin_port, sizeof(((struct sockaddr_in *) sa1)->sin_port))); } #ifdef IPV6 case AF_INET6:{ return (memcmp(&((struct sockaddr_in6 *)sa1)->sin6_port, &((struct sockaddr_in6 *)sa2)->sin6_port, sizeof(((struct sockaddr_in6 *) sa1)->sin6_port))); } #endif #ifdef AF_UNIX case AF_UNIX:{ return (-1); } #endif #ifdef HAVE_SOCKADDR_DL_STRUCT case AF_LINK:{ return (-1); /* no idea what to compare here ? */ } #endif } return (-1); } int sock_cmp_addr(const struct sockaddr *sa1, const struct sockaddr *sa2, socklen_t salen) { if (sa1->sa_family != sa2->sa_family) return (-1); switch (sa1->sa_family) { case AF_INET:{ return (memcmp(&((struct sockaddr_in *)sa1)->sin_addr, &((struct sockaddr_in *)sa2)->sin_addr, sizeof(struct in_addr))); } #ifdef IPV6 case AF_INET6:{ return (memcmp(&((struct sockaddr_in6 *)sa1)->sin6_addr, &((struct sockaddr_in6 *)sa2)->sin6_addr, sizeof(struct in6_addr))); } #endif #ifdef AF_UNIX case AF_UNIX:{ return (strcmp(((struct sockaddr_un *)sa1)->sun_path, ((struct sockaddr_un *)sa2)->sun_path)); } #endif #ifdef HAVE_SOCKADDR_DL_STRUCT case AF_LINK:{ return (-1); /* no idea what to compare here ? */ } #endif } return (-1); } int mcast_join(int sockfd, const struct sockaddr *grp, socklen_t grplen, const char *ifname, u_int ifindex) { /* include mcast_join2 */ switch (grp->sa_family) { case AF_INET:{ struct ip_mreq mreq; struct ifreq ifreq; memcpy(&mreq.imr_multiaddr, &((const struct sockaddr_in *)grp)->sin_addr, sizeof(struct in_addr)); if (ifindex > 0) { if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) { errno = ENXIO; /* i/f index not found */ return (-1); } goto doioctl; } else if (ifname != NULL) { strncpy(ifreq.ifr_name, ifname, IFNAMSIZ); doioctl: if (ioctl(sockfd, SIOCGIFADDR, &ifreq) < 0) return (-1); memcpy(&mreq.imr_interface, &((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr, sizeof(struct in_addr)); } else mreq.imr_interface.s_addr = htonl(INADDR_ANY); return (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))); } /* end mcast_join2 */ /* include mcast_join3 */ #ifdef IPV6 #ifndef IPV6_JOIN_GROUP /* APIv0 compatibility */ #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif case AF_INET6:{ struct ipv6_mreq mreq6; memcpy(&mreq6.ipv6mr_multiaddr, &((const struct sockaddr_in6 *)grp)->sin6_addr, sizeof(struct in6_addr)); if (ifindex > 0) { mreq6.ipv6mr_interface = ifindex; } else if (ifname != NULL) { if ((mreq6.ipv6mr_interface = if_nametoindex(ifname)) == 0) { errno = ENXIO; /* i/f name not found */ return (-1); } } else mreq6.ipv6mr_interface = 0; return (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6))); } #endif default: errno = EAFNOSUPPORT; return (-1); } } /* end mcast_join3 */ int /* Write "n" bytes to a descriptor. */ writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nwritten = send(fd, ptr, nleft, 0)) <= 0) { if (errno == EINTR) nwritten = 0; /* and call write() again */ else return (-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return (n); } int Writen(int fd, void *ptr, size_t nbytes) { if (writen(fd, ptr, nbytes) != nbytes) return -1; return nbytes; } ================================================ FILE: CWStevens.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWStevens_HEADER__ #define __CAPWAP_CWStevens_HEADER__ #include #include #define IFI_NAME 16 /* same as IFNAMSIZ in */ #define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ struct ifi_info { char ifi_name[IFI_NAME]; /* interface name, null-terminated */ short ifi_index; /* interface index */ short ifi_flags; /* IFF_xxx constants from */ struct sockaddr *ifi_addr; /* primary address */ struct sockaddr *ifi_brdaddr; /* broadcast address */ struct ifi_info *ifi_next; /* next of these structures */ }; struct ifi_info *get_ifi_info(int, int); void free_ifi_info(struct ifi_info *); char *sock_ntop_r(const struct sockaddr *sa, char *str); int sock_cpy_addr_port(struct sockaddr *sa1, const struct sockaddr *sa2); void sock_set_port_cw(struct sockaddr *sa, int port); int sock_cmp_port(const struct sockaddr *sa1, const struct sockaddr *sa2, socklen_t salen); int sock_cmp_addr(const struct sockaddr *sa1, const struct sockaddr *sa2, socklen_t salen); int mcast_join(int sockfd, const struct sockaddr *grp, socklen_t grplen, const char *ifname, u_int ifindex); int Writen(int fd, void *ptr, size_t nbytes); #endif /* __CAPWAP_CWStevens_HEADER__ */ ================================================ FILE: CWThread.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #include #include #include #include #include #define CW_USE_THREAD_TIMERS #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CW_THREAD_RETURN_TYPE CWThreadManageTimers(void *arg); // Creates a thread that will execute a given function with a given parameter CWBool CWCreateThread(CWThread * newThread, CW_THREAD_FUNCTION threadFunc, void *arg) { if (newThread == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Create Thread\n"); if (pthread_create(newThread, NULL, threadFunc, arg) != 0) { return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Can't create thread (maybe there are too many other threads)"); } return CW_TRUE; } // Creates a thread condition (wrapper for pthread_cond_init) CWBool CWCreateThreadCondition(CWThreadCondition * theCondition) { if (theCondition == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); switch (pthread_cond_init(theCondition, NULL)) { case 0: // success break; case ENOMEM: return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); default: return CWErrorRaise(CW_ERROR_GENERAL, "Can't create thread condition"); } return CW_TRUE; } // Frees a thread condition (wrapper for pthread_cond_destroy) void CWDestroyThreadCondition(CWThreadCondition * theCondition) { if (theCondition == NULL) return; pthread_cond_destroy(theCondition); } // Wait for a thread condition (wrapper for pthread_cond_wait) CWBool CWWaitThreadCondition(CWThreadCondition * theCondition, CWThreadMutex * theMutex) { if (theCondition == NULL || theMutex == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); switch (pthread_cond_wait(theCondition, theMutex)) { case 0: // success break; case ETIMEDOUT: return CWErrorRaise(CW_ERROR_TIME_EXPIRED, NULL); default: return CWErrorRaise(CW_ERROR_GENERAL, "Error waiting on thread condition"); } return CW_TRUE; } // Wait for a thread condition (wrapper for pthread_cond_wait) CWBool CWWaitThreadConditionTimeout(CWThreadCondition * theCondition, CWThreadMutex * theMutex, struct timespec * pTimeout) { if (theCondition == NULL || theMutex == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); switch (pthread_cond_timedwait(theCondition, theMutex, pTimeout)) { case 0: // success break; case ETIMEDOUT: return CWErrorRaise(CW_ERROR_TIME_EXPIRED, NULL); default: return CWErrorRaise(CW_ERROR_GENERAL, "Error waiting on thread condition"); } return CW_TRUE; } // Signal a thread condition (wrapper for pthread_cond_signal) void CWSignalThreadCondition(CWThreadCondition * theCondition) { if (theCondition == NULL) return; pthread_cond_signal(theCondition); } // Creates a thread mutex (wrapper for pthread_mutex_init) CWBool CWCreateThreadMutex(CWThreadMutex * theMutex) { if (theMutex == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); switch (pthread_mutex_init(theMutex, NULL)) { case 0: // success break; case ENOMEM: return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); default: return CWErrorRaise(CW_ERROR_GENERAL, "Can't create thread mutex"); } return CW_TRUE; } // Free a thread mutex (wrapper for pthread_mutex_destroy) void CWDestroyThreadMutex(CWThreadMutex * theMutex) { if (theMutex == NULL) return; pthread_mutex_destroy(theMutex); } // locks a mutex among threads at the specified address (blocking) CWBool CWThreadMutexLock(CWThreadMutex * theMutex) { if (theMutex == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (pthread_mutex_lock(theMutex) != 0) { return CWErrorRaise(CW_ERROR_GENERAL, "Can't lock thread mutex"); } /* fprintf(stdout, "Mutex %p locked by %p.\n", theMutex, pthread_self()); fflush(stdout); */ return CW_TRUE; } // locks a mutex among threads at the specified address (non-blocking). // CW_TRUE if lock was acquired, CW_FALSE otherwise CWBool CWThreadMutexTryLock(CWThreadMutex * theMutex) { if (theMutex == NULL) { return CW_FALSE; } if (pthread_mutex_trylock(theMutex) == EBUSY) return CW_FALSE; else return CW_TRUE; } // unlocks a mutex among threads at the specified address void CWThreadMutexUnlock(CWThreadMutex * theMutex) { if (theMutex == NULL) return; pthread_mutex_unlock(theMutex); /* fprintf(stdout, "Mutex %p UNlocked by %p.\n", theMutex, pthread_self()); fflush(stdout); */ } // creates a semaphore CWBool CWThreadCreateSem(CWThreadSem * semPtr, int value) { if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // we use named semaphore on platforms that support only them (e.g. Mac OS X) #ifdef CW_USE_NAMED_SEMAPHORES { static int semCount = 0; char name[32]; snprintf(name, 32, "/CWSem-%d-%4.4d", getpid(), semCount++); if ((semPtr->semPtr = sem_open(name, O_CREAT, 0600, value)) == (sem_t *) SEM_FAILED) { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } else { sem_unlink(name); } } #else if (sem_init(semPtr, 0, value) < 0) { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } #endif return CW_TRUE; } // destroy a semaphore void CWThreadDestroySem(CWThreadSem * semPtr) { #ifdef CW_USE_NAMED_SEMAPHORES if (semPtr == NULL || semPtr->semPtr == NULL) return; #else if (semPtr == NULL) return; #endif #ifdef CW_USE_NAMED_SEMAPHORES sem_close(semPtr->semPtr); #else sem_destroy(semPtr); #endif } // perform wait on a semaphore CWBool CWThreadSemWait(CWThreadSem * semPtr) { #ifdef CW_USE_NAMED_SEMAPHORES if (semPtr == NULL || semPtr->semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #else if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #endif //CWDebugLog("Sem Wait"); #ifdef CW_USE_NAMED_SEMAPHORES while (sem_wait(semPtr->semPtr) < 0) { #else while (sem_wait(semPtr) < 0) { #endif if (errno == EINTR) continue; else { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } } return CW_TRUE; } // perform post on a semaphore CWBool CWThreadSemPost(CWThreadSem * semPtr) { #ifdef CW_USE_NAMED_SEMAPHORES if (semPtr == NULL || semPtr->semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #else if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #endif #ifdef CW_USE_NAMED_SEMAPHORES if (sem_post(semPtr->semPtr) < 0) { #else if (sem_post(semPtr) < 0) { #endif CWErrorRaiseSystemError(CW_ERROR_GENERAL); } return CW_TRUE; } // get the value of a semaphore CWBool CWThreadSemGetValue(CWThreadSem * semPtr, int *valuePtr) { #ifdef CW_USE_NAMED_SEMAPHORES if (valuePtr == NULL || semPtr == NULL || semPtr->semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #else if (valuePtr == NULL || semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #endif #ifdef CW_USE_NAMED_SEMAPHORES if (sem_getvalue(semPtr->semPtr, valuePtr) < 0) { // note: broken on Mac OS X? Btw we don't need it CWErrorRaiseSystemError(CW_ERROR_GENERAL); } #else if (sem_getvalue(semPtr, valuePtr) < 0) { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } #endif if (*valuePtr < 0) { *valuePtr = 0; } return CW_TRUE; } sem_t *CWThreadGetSemT(CWThreadSem * semPtr) { #ifdef CW_USE_NAMED_SEMAPHORES return (semPtr->semPtr); #else return semPtr; #endif } // creates a semaphore that can be used with CWThreadTimedSemWait(). This type of semaphore // is different from CWThreadSemaphore to support platforms that don't have sem_timedwait() (e.g. Mac OS X) CWBool CWThreadCreateTimedSem(CWThreadTimedSem * semPtr, int value) { #ifdef HAVE_SEM_TIMEDWAIT return CWThreadCreateSem(semPtr, value); #else // if we don't have sem_timedwait(), the timed semaphore is a pair of unix domain sockets. // We write a dummy packet on a socket (client) when we want to post, and select() with timer on the other socket // when we want to wait. struct sockaddr_un serverAddr, clientAddr; int i; if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((((*semPtr)[0] = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) || (((*semPtr)[1] = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) { // create a pair of datagram unix domain socket close((*semPtr)[0]); CWErrorRaiseSystemError(CW_ERROR_CREATING); } CW_ZERO_MEMORY(&serverAddr, sizeof(serverAddr)); serverAddr.sun_family = AF_LOCAL; if (tmpnam((char *)&(serverAddr.sun_path)) == NULL) { CWErrorRaiseSystemError(CW_ERROR_CREATING); } CW_ZERO_MEMORY(&clientAddr, sizeof(clientAddr)); clientAddr.sun_family = AF_LOCAL; if (tmpnam((char *)&(clientAddr.sun_path)) == NULL) { CWErrorRaiseSystemError(CW_ERROR_CREATING); } if ((bind((*semPtr)[0], (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) || (bind((*semPtr)[1], (struct sockaddr *)&clientAddr, sizeof(clientAddr)) < 0) || (connect((*semPtr)[1], (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) || // connect each socket to the other (connect((*semPtr)[0], (struct sockaddr *)&clientAddr, sizeof(clientAddr)) < 0) ) { close((*semPtr)[0]); close((*semPtr)[1]); CWErrorRaiseSystemError(CW_ERROR_CREATING); } for (i = 0; i < value; i++) { if (!CWThreadTimedSemPost(semPtr)) return CW_FALSE; } return CW_TRUE; #endif } // CW_TRUE if the semaphore has zero value, CW_FALSE otherwise CWBool CWThreadTimedSemIsZero(CWThreadTimedSem * semPtr) { #ifdef HAVE_SEM_TIMEDWAIT int value; if (!CWThreadSemGetValue(semPtr, &value)) return CW_FALSE; return (value == 0) ? CW_TRUE : CW_FALSE; #else fd_set fset; int r; struct timeval timeout; if (semPtr == NULL) return CW_FALSE; FD_ZERO(&fset); FD_SET((*semPtr)[0], &fset); FD_SET((*semPtr)[1], &fset); timeout.tv_sec = 0; // poll timeout.tv_usec = 0; while ((r = select(max((*semPtr)[1], (*semPtr)[0]) + 1, &fset, NULL, NULL, &timeout)) < 0) { if (errno == EINTR) { timeout.tv_sec = 0; timeout.tv_usec = 0; continue; } CWErrorRaiseSystemError(CW_ERROR_GENERAL); } return (r == 0) ? CW_TRUE : CW_FALSE; #endif } CWBool CWThreadTimedSemSetValue(CWThreadTimedSem * semPtr, int value) { #ifdef HAVE_SEM_TIMEDWAIT // note: we can implement this, but our implemntation does't really need it in case // of a system semaphore. This is useful for our Unix Domain Socket Hack return CW_TRUE; //return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Operation Not Supported"); #else fd_set fset; int r, i; struct timeval timeout; if (semPtr == NULL) return CW_FALSE; FD_ZERO(&fset); FD_SET((*semPtr)[0], &fset); FD_SET((*semPtr)[1], &fset); timeout.tv_sec = 0; // poll timeout.tv_usec = 0; // first, remove all the pending packets CW_REPEAT_FOREVER { char dummy; while ((r = select(max((*semPtr)[1], (*semPtr)[0]) + 1, &fset, NULL, NULL, &timeout)) < 0) { if (errno == EINTR) { timeout.tv_sec = 0; timeout.tv_usec = 0; continue; } CWErrorRaiseSystemError(CW_ERROR_GENERAL); } if (r == 0) break; if (FD_ISSET((*semPtr)[0], &fset)) { while (read((*semPtr)[0], &dummy, 1) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_GENERAL); } } if (FD_ISSET((*semPtr)[1], &fset)) { while (read((*semPtr)[1], &dummy, 1) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_GENERAL); } } } // second, send n packets, where n is the value we want to set for the semaphore for (i = 0; i < value; i++) { if (!CWThreadTimedSemPost(semPtr)) return CW_FALSE; } return CW_TRUE; #endif } void CWThreadDestroyTimedSem(CWThreadTimedSem * semPtr) { #ifdef HAVE_SEM_TIMEDWAIT CWThreadDestroySem(semPtr); #else if (semPtr == NULL) return; close((*semPtr)[0]); close((*semPtr)[1]); #endif } CWBool CWThreadTimedSemWait(CWThreadTimedSem * semPtr, time_t sec, time_t nsec) { #ifdef HAVE_SEM_TIMEDWAIT struct timespec timeout; time_t t; #ifdef CW_USE_NAMED_SEMAPHORES if (semPtr == NULL || semPtr->semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #else if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); #endif CWDebugLog("Sem Timed Wait"); time(&t); timeout.tv_sec = t + sec; timeout.tv_nsec = nsec; #ifdef CW_USE_NAMED_SEMAPHORES while (sem_timedwait(semPtr->semPtr, &timeout) < 0) { #else while (sem_timedwait(semPtr, &timeout) < 0) { #endif if (errno == EINTR) { continue; } else if (errno == ETIMEDOUT) { CWDebugLog("sem_timedwait expired"); return CWErrorRaise(CW_ERROR_TIME_EXPIRED, NULL); } else { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } } #else fd_set fset; int r; struct timeval timeout; char dummy; if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Timed Sem Wait"); FD_ZERO(&fset); FD_SET((*semPtr)[0], &fset); timeout.tv_sec = sec; timeout.tv_usec = nsec / 1000; CWDebugLog("Timed Sem Wait Before Select"); while ((r = select(((*semPtr)[0]) + 1, &fset, NULL, NULL, &timeout)) <= 0) { CWDebugLog("Timed Sem Wait Select error"); if (r == 0) { CWDebugLog("Timed Sem Wait Timeout"); return CWErrorRaise(CW_ERROR_TIME_EXPIRED, NULL); } else if (errno == EINTR) { timeout.tv_sec = sec; timeout.tv_usec = nsec / 1000; continue; } CWErrorRaiseSystemError(CW_ERROR_GENERAL); } CWDebugLog("Timed Sem Wait After Select"); // ready to read while (read((*semPtr)[0], &dummy, 1) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_GENERAL); } // send ack (three-way handshake) while (send((*semPtr)[0], &dummy, 1, 0) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_SENDING); } timeout.tv_sec = 2; timeout.tv_usec = 0; CWDebugLog("Timed Sem Wait Before Select 2"); while ((r = select(((*semPtr)[0]) + 1, &fset, NULL, NULL, &timeout)) <= 0) { CWDebugLog("Timed Sem Wait Select error 2"); if (r == 0) { CWDebugLog("Timed Sem Wait Timeout 2"); return CWErrorRaise(CW_ERROR_TIME_EXPIRED, NULL); } else if (errno == EINTR) { timeout.tv_sec = 2; timeout.tv_usec = 0; continue; } CWErrorRaiseSystemError(CW_ERROR_GENERAL); } CWDebugLog("Timed Sem Wait After Select 2"); // read ack while (read((*semPtr)[0], &dummy, 1) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_GENERAL); } #endif CWDebugLog("End of Timed Sem Wait"); return CW_TRUE; } CWBool CWThreadTimedSemPost(CWThreadTimedSem * semPtr) { #ifdef HAVE_SEM_TIMEDWAIT return CWThreadSemPost(semPtr); #else char dummy = 'D'; fd_set fset; int r; struct timeval timeout; if (semPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Timed Sem Post"); while (send((*semPtr)[1], &dummy, 1, 0) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_SENDING); } // read ack (three-way handshake) FD_ZERO(&fset); FD_SET((*semPtr)[1], &fset); timeout.tv_sec = 2; timeout.tv_usec = 0; CWDebugLog("Timed Sem Post Before Select"); while ((r = select(((*semPtr)[1]) + 1, &fset, NULL, NULL, &timeout)) <= 0) { CWDebugLog("Timed Sem Post Select Error"); if (r == 0) { // timeout, server is not responding // note: this is not an error in a traditional semaphore, btw it's an error // according to our logic CWDebugLog("Timed Sem Post Timeout"); return CWErrorRaise(CW_ERROR_GENERAL, "Nobody is Waiting on this Sem"); } else if (errno == EINTR) { timeout.tv_sec = 2; timeout.tv_usec = 0; continue; } CWErrorRaiseSystemError(CW_ERROR_GENERAL); } CWDebugLog("Timed Sem Post After Select"); while (read((*semPtr)[1], &dummy, 1) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_GENERAL); } // send ack while (send((*semPtr)[1], &dummy, 1, 0) < 0) { if (errno == EINTR) continue; CWErrorRaiseSystemError(CW_ERROR_SENDING); } CWDebugLog("End of Sem Post"); return CW_TRUE; #endif } // wrappers for pthread_key_*() CWBool CWThreadCreateSpecific(CWThreadSpecific * specPtr, void (*destructor) (void *)) { if (specPtr == NULL) return CW_FALSE; // NULL destructor is allowed if (pthread_key_create(specPtr, destructor) != 0) { CWDebugLog("Error pthread key create"); return CW_FALSE; } return CW_TRUE; } void CWThreadDestroySpecific(CWThreadSpecific * specPtr) { if (specPtr == NULL) return; pthread_key_delete(*specPtr); } void *CWThreadGetSpecific(CWThreadSpecific * specPtr) { if (specPtr == NULL) return NULL; return pthread_getspecific(*specPtr); } CWBool CWThreadSetSpecific(CWThreadSpecific * specPtr, void *valPtr) { if (specPtr == NULL || valPtr == NULL) return CW_FALSE; switch (pthread_setspecific(*specPtr, valPtr)) { case 0: // success break; case ENOMEM: return CW_FALSE; default: return CW_FALSE; } return CW_TRUE; } // terminate the calling thread void CWExitThread() { printf("\n*** Exit Thread ***\n"); pthread_exit((void *)0); } void CWThreadSetSignals(int how, int num, ...) { sigset_t mask; va_list args; sigemptyset(&mask); va_start(args, num); for (; num > 0; num--) { sigaddset(&mask, va_arg(args, int)); } CWThreadSigMask(how, &mask, NULL); va_end(args); } // timers typedef struct { CWThread *requestedThreadPtr; int signalToRaise; } CWThreadTimerArg; struct { CWThreadSem requestServiceSem; CWThreadMutex requestServiceMutex; CWThreadSem serviceProvidedSem; int requestedSec; enum { CW_TIMER_REQUEST, CW_TIMER_CANCEL, CW_TIMER_NONE } requestedOp; CWThread *requestedThreadPtr; int signalToRaise; CWBool error; CWTimerID timerID; } gTimersData; void CWHandleTimer(CWTimerArg arg) { CWThreadTimerArg *a = (CWThreadTimerArg *) arg; CWThread requestedThreadPtr = *(a->requestedThreadPtr); int signalToRaise = a->signalToRaise; CWThreadSendSignal(requestedThreadPtr, signalToRaise); CWDebugLog("Timer Expired, Sent Signal(%d) to Thread: %08x", signalToRaise, requestedThreadPtr); CW_FREE_OBJECT(a->requestedThreadPtr); CW_FREE_OBJECT(a); return; } CWBool CWTimerRequest(int sec, CWThread * threadPtr, CWTimerID * idPtr, int signalToRaise) { CWThreadTimerArg *arg; CWDebugLog("Timer Request"); if (sec < 0 || threadPtr == NULL || idPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_OBJECT_ERR(arg, CWThreadTimerArg, return CW_FALSE; ); CW_CREATE_OBJECT_ERR(arg->requestedThreadPtr, CWThread, CW_FREE_OBJECT(arg); return CW_FALSE; ); CW_COPY_MEMORY(arg->requestedThreadPtr, threadPtr, sizeof(CWThread)); arg->signalToRaise = signalToRaise; CWDebugLog("Timer Request: thread(%08x), signal(%d)", *(arg->requestedThreadPtr), arg->signalToRaise); if ((*idPtr = timer_add(sec, 0, &CWHandleTimer, arg)) == -1) { return CW_FALSE; } return CW_TRUE; } void CWTimerFreeArg(CWTimerArg arg) { CWThreadTimerArg *a = (CWThreadTimerArg *) arg; /* LE-03-02-2010.01 */ if (a == NULL) return; CW_FREE_OBJECT(a->requestedThreadPtr); CW_FREE_OBJECT(a); return; } CWBool CWTimerCancel(CWTimerID * idPtr) { timer_rem(*idPtr, CWTimerFreeArg); return CW_TRUE; } ================================================ FILE: CWThread.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWThread_HEADER__ #define __CAPWAP_CWThread_HEADER__ #include "CWErrorHandling.h" #include #include #include #include #include "timerlib.h" #ifdef MACOSX /* Mac OS X */ #define CW_USE_NAMED_SEMAPHORES #include typedef struct { sem_t *semPtr; } CWThreadSem; #include #include #define max(a,b) ( (a) > (b) ? (a) : (b) ) #else typedef sem_t CWThreadSem; #endif #ifdef HAVE_SEM_TIMEDWAIT typedef CWThreadSem CWThreadTimedSem; #else typedef int CWThreadTimedSem[2]; /* pair of Unix Domain Socket */ #endif typedef pthread_t CWThread; typedef pthread_mutex_t CWThreadMutex; typedef pthread_cond_t CWThreadCondition; typedef pthread_key_t CWThreadSpecific; typedef pthread_once_t CWThreadOnce; typedef void *(*CW_THREAD_FUNCTION) (void *); typedef int CWThreadId; typedef int CWTimerID; typedef void *CWTimerArg; #define CW_THREAD_RETURN_TYPE void* #define CWThreadSigMask(how, set, old_set) pthread_sigmask(how, set, old_set) #define CWThreadIsEqual(t1, t2) pthread_equal(t1,t2) #define CWThreadSelf() pthread_self() #define CWThreadKill(t1, signal) pthread_kill(t1,signal) #define CWThreadSendSignal CWThreadKill #define CW_THREAD_ONCE_INIT PTHREAD_ONCE_INIT #define CWThreadCallOnce pthread_once sem_t *CWThreadGetSemT(CWThreadSem * semPtr); CWBool CWThreadInitLib(void); CWBool CWCreateThread(CWThread * newThread, CW_THREAD_FUNCTION threadFunc, void *arg); CWBool CWCreateThreadCondition(CWThreadCondition * theCondition); void CWDestroyThreadCondition(CWThreadCondition * theCondition); CWBool CWWaitThreadCondition(CWThreadCondition * theCondition, CWThreadMutex * theMutex); CWBool CWWaitThreadConditionTimeout(CWThreadCondition * theCondition, CWThreadMutex * theMutex, struct timespec *pTimeout); void CWSignalThreadCondition(CWThreadCondition * theCondition); CWBool CWCreateThreadMutex(CWThreadMutex * theMutex); void CWDestroyThreadMutex(CWThreadMutex * theMutex); CWBool CWThreadMutexLock(CWThreadMutex * theMutex); CWBool CWThreadMutexTryLock(CWThreadMutex * theMutex); void CWThreadMutexUnlock(CWThreadMutex * theMutex); CWBool CWThreadCreateSem(CWThreadSem * semPtr, int value); void CWThreadDestroySem(CWThreadSem * semPtr); CWBool CWThreadSemWait(CWThreadSem * semPtr); CWBool CWThreadSemPost(CWThreadSem * semPtr); CWBool CWThreadSemGetValue(CWThreadSem * semPtr, int *valuePtr); CWBool CWThreadCreateSpecific(CWThreadSpecific * specPtr, void (*destructor) (void *)); void CWThreadDestroySpecific(CWThreadSpecific * specPtr); void *CWThreadGetSpecific(CWThreadSpecific * specPtr); CWBool CWThreadSetSpecific(CWThreadSpecific * specPtr, void *valPtr); void CWExitThread(void); //void *CWThreadManageTimers(void *arg); CWBool CWTimerCancel(CWTimerID * idPtr); CWBool CWTimerRequest(int sec, CWThread * threadPtr, CWTimerID * idPtr, int signalToRaise); void CWThreadSetSignals(int how, int num, ...); CWBool CWThreadCreateTimedSem(CWThreadTimedSem * semPtr, int value); CWBool CWThreadTimedSemIsZero(CWThreadTimedSem * semPtr); CWBool CWThreadTimedSemSetValue(CWThreadTimedSem * semPtr, int value); void CWThreadDestroyTimedSem(CWThreadTimedSem * semPtr); CWBool CWThreadTimedSemWait(CWThreadTimedSem * semPtr, time_t sec, time_t nsec); CWBool CWThreadTimedSemPost(CWThreadTimedSem * semPtr); #endif ================================================ FILE: CWTimer.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ /* This file implements routines for handling timeouts. * * User calls are: * _clkini() - initialize clock and timers * _setimr() - set a timer * _cantim() - cancel a timer * #disable_interrupts - disable clock and timer interrupts * #enable_interrupts - enable clock and timer interrupts * * * History: * Originally written for standalone MC68000 with MC6840 timer * Ed Barkmeyer, NBS, September 1983 * * Rewritten for 4.2BSD UNIX with software timer. * Don Libes, NBS, October 1985 * */ #include "CWCommon.h" #include #include #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif typedef short int int2; typedef int int4; #define TIMER_SIGNAL_TYPE CW_TIMER_INTERNAL_SIGNAL #define TIMER_INTERVAL_TYPE ITIMER_REAL struct itimerval timer_value; static unsigned timer_set_timestamp; /* this holds the value of */ /* current_time() whenever an */ /* interval timer is started */ /* The following definitions support conversions between the basic unit of time in the nip (which is tens-of-milliseconds) and time in all the 4.2BSD system calls (which is seconds and microseconds). */ #define USECS_PER_MSEC 1000 #define MSECS_PER_SEC 1000 #define USECS_PER_SEC 1000000 #define MANY_TENS_OF_MSECS (~0) /* unsigned, please */ /* useful for converting from 4.2BSD to nip units */ #define USECS_PER_TEN_MSECS (USECS_PER_MSEC*10) #define TENS_OF_MSECS_PER_SEC (MSECS_PER_SEC/10) /* useful for converting from nip units to 4.2 units */ #define SEC(x) (x/TENS_OF_MSECS_PER_SEC) #define USEC(x) ((x*USECS_PER_TEN_MSECS)%USECS_PER_SEC) /* A timer wakeup queue should be represented as a data structure that can do MIN, INSERT, DELETE and TRAVERSE operations in minimal time. INSERT and DELETE are necessary to support declaring and cancelling of timers MIN is necessary to find out who has timed out and to decide what the next interval to timeout should be. TRAVERSE is necessary for updating all the timers once a time period has elapsed. Unfortunately, I forget what this optimal data structure is. Until I remember, we shall use an array. The array is used as follows: Each entry in the array has a timeout. We will constantly be waiting for the entry with the shortest timeout. When that times out, we will subtract from each timer's timeout, the time that has passed since we first started waiting for the current timer. When a timeout occurs, the event flag is set. A timer is released from use when the timeout is 0 AND the event flag points to 0. */ #define timer_inuse(t) (t->timeout || t->event) struct timer { unsigned int timeout; /* clock ticks to wait for */ int2 *event; /* set to TRUE when time out occurs */ void (*ast) (void *, int); CWTimerArg myArg; } timerq[CW_TIMER_MAX]; /* timer queue */ struct timer *next_timer; /* timer we expect to run down next */ struct timer *shortest_timer(); int oldmask; /* signal mask */ sigset_t mask; /* actually these just fiddle with the interrupt from the timer */ #define disable_interrupts() pthread_sigmask(SIG_BLOCK, &mask, NULL); //oldmask = sigblock(1<<(TIMER_SIGNAL_TYPE-1)) #define enable_interrupts() pthread_sigmask(SIG_UNBLOCK, &mask, NULL); /* used when cancelling timers (if that works) */ struct itimerval cancel_timer = { {0, 0}, {0, 0} }; void _clkini(); int _setimr(unsigned int timeout, int2 * event, void (*ast) (void *, int), CWTimerArg myArg, int4 arg, char *pname, CWTimerID * idPtr); int _cantim(CWTimerID * idPtr); void start_timer(struct timer *t); void cancel_itimer(); void update_all_timers_by(unsigned int time); __inline__ CWBool CWTimersInitLib() { sigemptyset(&mask); sigaddset(&mask, SIGALRM); enable_interrupts(); _clkini(); return CW_TRUE; } void CWTimersInit() { memset(timerq, 0, sizeof(struct timer) * CW_TIMER_MAX); } // create a timer that expires after sec seconds. ID of the timer will be returned in *idPtr, // hdl() will be called with argument arg when the timer expires. __inline__ CWBool CWTimerCreate(int sec, CWTimerID * idPtr, void (*hdl) (CWTimerArg, CWTimerID), CWTimerArg arg) { int2 ev; if (idPtr == NULL || hdl == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (_setimr(sec * 100, &ev, (void *)hdl, arg, 0, NULL, idPtr) == -1) { return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Out of Timers"); } return CW_TRUE; } __inline__ CWTimerArg CWTimerGetArg(CWTimerID * idPtr) { CWTimerArg pResult; if (idPtr == NULL) { CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); return (CWTimerArg) NULL; } // From _cantim disable_interrupts(); pResult = timerq[*idPtr].myArg; enable_interrupts(); return pResult; } __inline__ CWBool CWTimerSetArg(CWTimerID * idPtr, CWTimerArg arg) { if (idPtr == NULL) { CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); return CW_FALSE; } // From _cantim disable_interrupts(); timerq[*idPtr].myArg = arg; enable_interrupts(); return CW_TRUE; } __inline__ CWBool CWTimerDestroy(CWTimerID * idPtr) { if (idPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (_cantim(idPtr) == TRUE) return CW_TRUE; else return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Can't Destroy: Timer not Found"); } // CAPWAP note: don't use directly the following functions, just use the CWTimer*() wrappers void clk_isr(); unsigned int current_time(); stack_t new_stack; struct sigaction siga; // init timers void _clkini() { struct timer *t; /* disable constant interval timing */ timerclear(&timer_value.it_interval); /* if (signal(TIMER_SIGNAL_TYPE, clk_isr) == SIG_ERR) { perror("_clkini: signal failed\n"); exit(-1); } */ if ((new_stack.ss_sp = malloc(SIGSTKSZ)) == NULL) { perror("impossibile allocare memeoria per il nuovo stack"); } new_stack.ss_size = SIGSTKSZ; new_stack.ss_flags = 0; if (sigaltstack(&new_stack, NULL) < 0) { perror("sigaltstack"); } siga.sa_handler = clk_isr; sigfillset(&siga.sa_mask); siga.sa_flags = SA_ONSTACK; if (sigaction(TIMER_SIGNAL_TYPE, &siga, NULL)) { perror("_clkini: signal failed\n"); exit(-1); } for (t = timerq; t < &timerq[CW_TIMER_MAX]; t++) { t->timeout = 0; t->event = 0; } } int _setimr(unsigned int timeout, /* time to wait in 10msec ticks */ int2 * event, /* event flag to set on runout */ void (*ast) (void *, int), /* routine to be called on runout or 0 */ CWTimerArg myArg, int4 arg, /* argument to be provided to timeout ast */ char *pname, CWTimerID * idPtr) { struct timer *free_timer; /* pointer to unused timer entry */ struct timer *t; *event = 0; if (timeout == 0) { /* no time, so enable it and don't put on queue */ *event = TRUE; return (TRUE); } disable_interrupts(); for (*idPtr = 0, t = timerq; t < &timerq[CW_TIMER_MAX]; t++, (*idPtr)++) { if (!timer_inuse(t)) { // CWDebugLog("Found free timer"); free_timer = t; break; } } if (t == &timerq[CW_TIMER_MAX]) { CWDebugLog("Free timer not found"); enable_interrupts() return -1; // out of timers } /* install new timer */ /* cannot initialize free timer here, because cancel_itimer() will */ /* munge with it, so push it into the branches of the the if */ if (!next_timer) { // CWDebugLog("First Timer\n"); /* no timers set at all, so this is shortest */ free_timer->event = event; free_timer->timeout = timeout; free_timer->ast = ast; free_timer->myArg = myArg; start_timer(free_timer); } else if ((timeout + current_time()) < (next_timer->timeout + timer_set_timestamp)) { // CWDebugLog("Shorter Timer\n"); /* new timer is shorter than current one, so */ /* cancel current timer and set up new one */ /* not sure if the next setitimer() is actually necessary */ /* probably not, but I haven't tested to make sure */ cancel_itimer(); free_timer->event = event; free_timer->timeout = timeout; free_timer->ast = ast; free_timer->myArg = myArg; start_timer(free_timer); } else { /* new timer is longer, than current one */ // CWDebugLog("Longer Timer (%d)\n", timeout); free_timer->event = event; free_timer->timeout = timeout + (current_time() - timer_set_timestamp); free_timer->ast = ast; free_timer->myArg = myArg; } CWDebugLog("timer set, index:%d, timeout:%d", *idPtr, timerq[*idPtr].timeout); enable_interrupts(); return (TRUE); } // cancel a timer int _cantim(CWTimerID * idPtr) { struct timer *t; disable_interrupts(); // for (t=timerq;t<&timerq[CW_TIMER_MAX];t++) { t = &timerq[*idPtr]; //if (t->event == event) { t->timeout = 0; t->event = 0; t->myArg = 0; /* check if we were waiting on this one */ if (t == next_timer) { cancel_itimer(); start_timer(shortest_timer()); } enable_interrupts(); return (TRUE); //} //} enable_interrupts(); return (FALSE); } /* clock interrupt handler */ /* this routine is executed when an alarm signal occurs */ void clk_isr() { CWDebugLog("Signal Timer Expired received"); /* the following condition could be set up, if the interrupt was delivered while we were in cantim, cancelling the last timer */ //printf("\n\n\n%d\n\n", pthread_self()); CWDebugLog("Subtract %d from timers", current_time() - timer_set_timestamp); update_all_timers_by(current_time() - timer_set_timestamp); if (next_timer == 0) return; /* start timer for next shortest guy if one exists */ start_timer(shortest_timer()); } /* subtract time from all timers, enabling any that run out along the way */ void update_all_timers_by(unsigned int time) { struct timer *t; int id; CWDebugLog("Update Timers"); for (id = 0, t = timerq; t < &timerq[CW_TIMER_MAX]; t++, id++) { if (t->timeout) { // CWDebugLog("~~~~~~~~~timer set, index:%d, timeout:%d~~~~~~~~~~~~", id, t->timeout); if (time < t->timeout) { // CWDebugLog("timeout(%d) - time(%d)\n", t->timeout, time); t->timeout -= time; // CWDebugLog("timeout(%d)\n", t->timeout); } else { // CWDebugLog("(%d) %d vs %d\n", t, t->timeout, time); // CWDebugLog("~~~~~~~è un segnale mio!~~~~~~~~~"); t->timeout = 0; (t->ast) ((void *)t->myArg, id); // printf("%d vs %d\n", t->timeout, time); /* if this has forced a timeout on */ /* anyone else, enable it */ *t->event = TRUE; t->event = 0; /* remove timer */ } } } } struct timer *shortest_timer() { struct timer *t, *s_t; /* shortest_timer */ unsigned int old_timer = MANY_TENS_OF_MSECS; for (s_t = 0, t = timerq; t < &timerq[CW_TIMER_MAX]; t++) { if (t->timeout > 0 && t->timeout < old_timer) { old_timer = t->timeout; s_t = t; } } return (s_t); } void start_timer(t) struct timer *t; { next_timer = t; /* remember for _cantim and _setimr */ if (!t) return; timer_set_timestamp = current_time(); timer_value.it_value.tv_sec = SEC(next_timer->timeout); timer_value.it_value.tv_usec = USEC(next_timer->timeout); // CWDebugLog("Start System Timer (%d,%d)", timer_value.it_value.tv_sec, timer_value.it_value.tv_usec); if (-1 == setitimer(TIMER_INTERVAL_TYPE, &timer_value, (struct itimerval *)0)) { perror("start_timer: setitimer"); exit(-1); } } /* return time in tens of milliseconds */ unsigned int current_time() { struct timeval tp; (void)gettimeofday(&tp, (struct timezone *)0); /* ignore overflow */ return (tp.tv_sec * TENS_OF_MSECS_PER_SEC + tp.tv_usec / USECS_PER_TEN_MSECS); } void cancel_itimer() { if (-1 == setitimer(TIMER_INTERVAL_TYPE, &cancel_timer, (struct itimerval *)0)) { perror("_setimr: setitimer failed"); exit(-1); } update_all_timers_by(current_time() - timer_set_timestamp); } ================================================ FILE: CWVendorPayloads.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * Authors : Matteo Latini (mtylty@gmail.com) * Donato Capitella (d.capitella@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_VendorPayloads__ #define __CAPWAP_VendorPayloads__ /*#include "CWCommon.h"*/ #include "CWAC.h" /*********************************************************************** * Vendor specific payloads types * *********************************************************************/ #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI 1 #define CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM 2 /*********************************************************************** * UCI Server Port * *********************************************************************/ #define UCI_SERVER_PORT 31337 typedef struct { unsigned char command; char *commandArgs; char *response; } CWVendorUciValues; CWBool CWParseVendorPayload(CWProtocolMessage * msg, int len, CWProtocolVendorSpecificValues * valPtr); CWBool CWParseUCIPayload(CWProtocolMessage * msg, CWVendorUciValues ** payloadPtr); CWBool CWWTPSaveUCIValues(CWVendorUciValues * uciPayload, CWProtocolResultCode * resultCode); CWBool CWAssembleWTPVendorPayloadUCI(CWProtocolMessage * msgPtr); /************************************************************************* * WTP Update Messages *************************************************************************/ typedef struct { unsigned char major_v; unsigned char min_v; unsigned char revision; } mess_version_info; typedef struct { mess_version_info v_info; unsigned int pack_size; } mess_up_req; typedef struct { unsigned int seq_num; unsigned int size; unsigned char *buf; } mess_cup; typedef struct { unsigned char type; /* Message type */ union { mess_version_info v_resp; mess_up_req up_req; mess_cup cup; } args; } CWVendorWumValues; #define _major_v_ args.v_resp.major_v #define _minor_v_ args.v_resp.min_v #define _revision_v_ args.v_resp.revision #define _pack_size_ args.up_req.pack_size #define _seq_num_ args.cup.seq_num #define _cup_ args.cup.buf #define _cup_fragment_size_ args.cup.size #define CUP_FRAGMENT_SIZE 4000 //CWBool CWParseWUMPayload(CWProtocolMessage *msg, CWVendorUciValues **payloadPtr); CWBool CWWTPSaveWUMValues(CWVendorWumValues * wumPayload, CWProtocolResultCode * resultCode); CWBool CWAssembleWTPVendorPayloadWUM(CWProtocolMessage * msgPtr); #endif ================================================ FILE: CWVendorPayloadsAC.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Matteo Latini (mtylty@gmail.com) * * ************************************************************************************************/ #include "CWVendorPayloads.h" #include "WUM.h" #include #include #include #include #include #include #include #include #include #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWAssembleWTPVendorPayloadUCI(CWProtocolMessage * msgPtr) { int *iPtr; unsigned short msgType; CWProtocolVendorSpecificValues *valuesPtr; CWVendorUciValues *uciPtr; CWLog("Assembling Protocol Configuration Update Request [VENDOR CASE]..."); if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } valuesPtr = gWTPs[*iPtr].vendorValues; switch (valuesPtr->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: msgType = CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI; uciPtr = (CWVendorUciValues *) valuesPtr->payload; if (uciPtr->commandArgs != NULL) { /* create message */ CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, sizeof(short) + sizeof(char) + sizeof(int) + (strlen(uciPtr->commandArgs) * sizeof(char)), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore16(msgPtr, (unsigned short)msgType); CWProtocolStore8(msgPtr, (unsigned char)uciPtr->command); CWProtocolStore32(msgPtr, (unsigned int)strlen(uciPtr->commandArgs)); CWProtocolStoreStr(msgPtr, uciPtr->commandArgs); } else { /* create message */ CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, sizeof(short) + sizeof(char) + sizeof(int), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore16(msgPtr, (unsigned short)msgType); CWProtocolStore8(msgPtr, (unsigned char)uciPtr->command); CWProtocolStore32(msgPtr, 0); } break; default: return CW_FALSE; break; } CWLog("Assembling Protocol Configuration Update Request [VENDOR CASE]: Message Assembled."); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE); } CWBool CWAssembleWTPVendorPayloadWUM(CWProtocolMessage * msgPtr) { int *iPtr; unsigned short msgType; CWProtocolVendorSpecificValues *valuesPtr; CWVendorWumValues *wumPtr; CWLog("Assembling Protocol Configuration Update Request [VENDOR CASE]..."); if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((iPtr = ((int *)CWThreadGetSpecific(&gIndexSpecific))) == NULL) { return CW_FALSE; } valuesPtr = gWTPs[*iPtr].vendorValues; switch (valuesPtr->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: /* * Here we assemble the WTP Update Messages. */ msgType = CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM; wumPtr = (CWVendorWumValues *) valuesPtr->payload; switch (wumPtr->type) { case WTP_VERSION_REQUEST: case WTP_COMMIT_UPDATE: case WTP_CANCEL_UPDATE_REQUEST: CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, sizeof(short) + sizeof(char), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); break; case WTP_UPDATE_REQUEST: CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, sizeof(short) + 4 * sizeof(char) + sizeof(unsigned int), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); break; case WTP_CUP_FRAGMENT: CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, sizeof(short) + sizeof(char) + 2 * sizeof(int) + wumPtr->_cup_fragment_size_, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); break; default: CWLog("Error! unknown WUM message type!!!"); return CW_FALSE; } CWProtocolStore16(msgPtr, (unsigned short)msgType); CWProtocolStore8(msgPtr, (unsigned char)wumPtr->type); if (wumPtr->type == WTP_UPDATE_REQUEST) { CWProtocolStore8(msgPtr, wumPtr->_major_v_); CWProtocolStore8(msgPtr, wumPtr->_minor_v_); CWProtocolStore8(msgPtr, wumPtr->_revision_v_); CWProtocolStore32(msgPtr, wumPtr->_pack_size_); } else if (wumPtr->type == WTP_CUP_FRAGMENT) { CWProtocolStore32(msgPtr, wumPtr->_seq_num_); CWProtocolStore32(msgPtr, wumPtr->_cup_fragment_size_); CWProtocolStoreRawBytes(msgPtr, wumPtr->_cup_, wumPtr->_cup_fragment_size_); CW_FREE_OBJECT(wumPtr->_cup_); } break; default: return CW_FALSE; break; } CWLog("Assembling Protocol Configuration Update Request [VENDOR CASE]: Message Assembled."); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE); } ================================================ FILE: CWVendorPayloadsWTP.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Matteo Latini (mtylty@gmail.com) * Donato Capitella (d.capitella@gmail.com) * ************************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #include "CWWTP.h" #include "CWVendorPayloads.h" #include "WUM.h" CWBool CWParseUCIPayload(CWProtocolMessage * msgPtr, CWVendorUciValues ** payloadPtr) { int argsLen; CWVendorUciValues *uciPayload = NULL; CW_CREATE_OBJECT_ERR(uciPayload, CWVendorUciValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); uciPayload->command = (unsigned char)CWProtocolRetrieve8(msgPtr); uciPayload->response = NULL; argsLen = (unsigned int)CWProtocolRetrieve32(msgPtr); if (argsLen != 0) { CW_CREATE_STRING_ERR(uciPayload->commandArgs, argsLen, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); uciPayload->commandArgs = CWProtocolRetrieveStr(msgPtr, argsLen); } else uciPayload->commandArgs = NULL; *payloadPtr = uciPayload; CWLog("Parsed UCI Vendor Payload..."); return CW_TRUE; } CWBool CWParseWUMPayload(CWProtocolMessage * msgPtr, CWVendorWumValues ** payloadPtr) { CWVendorWumValues *wumPayload = NULL; CW_CREATE_OBJECT_ERR(wumPayload, CWVendorWumValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); wumPayload->type = (unsigned char)CWProtocolRetrieve8(msgPtr); /* * According to the type of the message, retrive additional fields */ if (wumPayload->type == WTP_UPDATE_REQUEST) { wumPayload->_major_v_ = (unsigned char)CWProtocolRetrieve8(msgPtr); wumPayload->_minor_v_ = (unsigned char)CWProtocolRetrieve8(msgPtr); wumPayload->_revision_v_ = (unsigned char)CWProtocolRetrieve8(msgPtr); wumPayload->_pack_size_ = (unsigned int)CWProtocolRetrieve32(msgPtr); } else if (wumPayload->type == WTP_CUP_FRAGMENT) { wumPayload->_seq_num_ = (unsigned int)CWProtocolRetrieve32(msgPtr); wumPayload->_cup_fragment_size_ = (unsigned int)CWProtocolRetrieve32(msgPtr); wumPayload->_cup_ = CWProtocolRetrieveRawBytes(msgPtr, wumPayload->_cup_fragment_size_); } *payloadPtr = wumPayload; CWLog("Parsed WUM Vendor Payload..."); return CW_TRUE; } CWBool CWParseVendorPayload(CWProtocolMessage * msgPtr, int len, CWProtocolVendorSpecificValues * valPtr) { CWVendorUciValues *uciPtr; CWVendorWumValues *wumPtr; /*...we choose which payload was used (in this case only uci configuration payloads are used) */ valPtr->vendorPayloadType = (unsigned short)CWProtocolRetrieve16(msgPtr); switch (valPtr->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: if (!(CWParseUCIPayload(msgPtr, &uciPtr))) { CW_FREE_OBJECT(uciPtr->commandArgs); CW_FREE_OBJECT(uciPtr->response); CW_FREE_OBJECT(uciPtr); return CW_FALSE; // will be handled by the caller } valPtr->payload = (void *)uciPtr; break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: if (!(CWParseWUMPayload(msgPtr, &wumPtr))) { CW_FREE_OBJECT(wumPtr); return CW_FALSE; // will be handled by the caller } valPtr->payload = (void *)wumPtr; break; default: return CW_FALSE; // will be handled by the caller } return CW_TRUE; } /************************************************************************ * WTP Update System ************************************************************************/ /* Update System States */ #define WUM_STATE_WAIT 0 /* waiting for WTP_UPDATE_REQUESTs */ #define WUM_STATE_BUSY 1 /* busy receiving CUP fragments */ #define WUM_STATE_READY 2 /* ready to start the update procedure */ struct WUMState { unsigned char state; /* one of the above states */ FILE *cupTmp; /* pointer to the cup file */ int cupSize; /* size of the cup file */ int total_fragments; /* number of fragments of the cup file */ int received_fragments; /* number of fragments already received */ }; struct WUMState wumState = { .state = WUM_STATE_WAIT, .cupTmp = NULL, .cupSize = 0, .total_fragments = 0, .received_fragments = 0 }; #define CUP_TMP_FILE "/tmp/wtp.cup" #define WUA_BIN "WUA" /* * WUMPrepareTmpFile * * After a WTP_UPDATE_REQUEST, calling this function prepares the update system * to accept CUP fragments and reassemble them into a temp file. If something goes * wrong, it returns CW_FALSE; otherwise it returns CW_TRUE, the wumState changes * to BUSY and we are ready to store the fragments we've received. */ CWBool WUMPrepareForUpdate(int size) { if (wumState.state != WUM_STATE_WAIT) { CWLog("Can't start a new update session; the previous one isn't completed yet.\n"); return CW_FALSE; } wumState.cupTmp = fopen(CUP_TMP_FILE, "w"); if (wumState.cupTmp == NULL) { CWLog("Can't open temp file %s for writing.\n", CUP_TMP_FILE); return CW_FALSE; } wumState.cupSize = size; wumState.total_fragments = size / CUP_FRAGMENT_SIZE; if (size % CUP_FRAGMENT_SIZE > 0) wumState.total_fragments++; wumState.received_fragments = 0; wumState.state = WUM_STATE_BUSY; return CW_TRUE; } /* * When in the BUSY State, this function is used to read and store the * fragments that compose the update package (CUP) into a temp file. */ CWBool WUMStoreFragment(CWVendorWumValues * wumValues) { int offset, toWrite; if (wumState.state != WUM_STATE_BUSY) { CWLog("Received an update fragment, but no update session has been initialized yet.\n"); return CW_FALSE; } if (wumValues->_seq_num_ > wumState.total_fragments) { CWLog("Received an update fragment with invalid sequence number.\n"); return CW_FALSE; } offset = wumValues->_seq_num_ * CUP_FRAGMENT_SIZE; if (fseek(wumState.cupTmp, offset, SEEK_SET) != 0) { CWLog("Can't seek required offset in CUP tmp file.\n"); return CW_FALSE; } toWrite = wumValues->_cup_fragment_size_; if (fwrite(wumValues->_cup_, 1, toWrite, wumState.cupTmp) != toWrite) { CWLog("Error while writing CUP tmp file.\n"); return CW_FALSE; } CW_FREE_OBJECT(wumValues->_cup_); wumState.received_fragments++; return CW_TRUE; } /* * Tells if all fragments of an update have been received and reassembled. */ CWBool WUMIsComplete() { if (wumState.state != WUM_STATE_BUSY) { return CW_FALSE; } if (wumState.total_fragments > wumState.received_fragments) return CW_FALSE; return CW_TRUE; } /* * Close the temp file and goes back to the READY State. */ CWBool WUMCloseFile() { fclose(wumState.cupTmp); wumState.cupTmp = NULL; wumState.state = WUM_STATE_READY; return CW_TRUE; } /* * Cancel an Update. */ CWBool WUMCancel() { wumState.state = WUM_STATE_WAIT; if (wumState.cupTmp) fclose(wumState.cupTmp); wumState.cupTmp = NULL; remove(CUP_TMP_FILE); return CW_TRUE; } /* * CWWTPCheckVersion - checks if we are already updated. */ CWBool CWWTPCheckVersion(CWVendorWumValues * wumPayload) { int ret = CW_FALSE; if (wumPayload->_major_v_ > WTP_VERSION_MAJOR) ret = CW_TRUE; else if (wumPayload->_major_v_ == WTP_VERSION_MAJOR) { if (wumPayload->_minor_v_ > WTP_VERSION_MINOR) ret = CW_TRUE; else if (wumPayload->_minor_v_ == WTP_VERSION_MINOR) { if (wumPayload->_revision_v_ > WTP_VERSION_REVISION) ret = CW_TRUE; } } return ret; } CWBool StartWUA() { int pid, fd; struct flock fl; /* The following lock in set just for synchronization purposes */ fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); fd = open(WTP_LOCK_FILE, O_CREAT | O_WRONLY, S_IRWXU); fcntl(fd, F_SETLKW, &fl); /* F_GETLK, F_SETLK, F_SETLKW */ pid = fork(); if (pid == 0) { execl(WUA_BIN, WUA_BIN, CUP_TMP_FILE, NULL); exit(EXIT_FAILURE); } else if (pid < 0) { CWLog("Can't fork!"); close(fd); return CW_FALSE; } return CW_TRUE; } /* * Returns CW_TRUE if the required space is available on the * filesystem where the /tmp dir is mounted. */ CWBool check_free_space(int bytes) { struct statvfs diskStat; if (statvfs("/tmp", &diskStat) != 0) { CWLog("Can't stat filesystem!\n"); return CW_FALSE; } if (diskStat.f_bsize * diskStat.f_bfree > bytes) return CW_TRUE; return CW_FALSE; } CWBool CWWTPSaveWUMValues(CWVendorWumValues * wumPayload, CWProtocolResultCode * resultCode) { /* guards on input values */ if (wumPayload == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; switch (wumPayload->type) { case WTP_VERSION_REQUEST: wumPayload->type = WTP_VERSION_RESPONSE; wumPayload->_major_v_ = WTP_VERSION_MAJOR; wumPayload->_minor_v_ = WTP_VERSION_MINOR; wumPayload->_revision_v_ = WTP_VERSION_REVISION; break; case WTP_UPDATE_REQUEST: /* Check if update can be performed */ CWLog("Received Update Request - Version %d.%d.%d", wumPayload->_major_v_, wumPayload->_minor_v_, wumPayload->_revision_v_); wumPayload->type = WTP_UPDATE_RESPONSE; if (!CWWTPCheckVersion(wumPayload)) { CWLog("WTP already up to date.\n"); *resultCode = CW_PROTOCOL_FAILURE; } else if (!check_free_space(wumPayload->_pack_size_)) { CWLog("No disk space available.\n"); *resultCode = CW_PROTOCOL_FAILURE; } else if (WUMPrepareForUpdate(wumPayload->_pack_size_) == CW_FALSE) { *resultCode = CW_PROTOCOL_FAILURE; } break; case WTP_CUP_FRAGMENT: wumPayload->type = WTP_CUP_ACK; if (!WUMStoreFragment(wumPayload)) { *resultCode = CW_PROTOCOL_FAILURE; } /* if this is the last fragment, close temp file and * pass to the READY state. */ if (WUMIsComplete()) { WUMCloseFile(); } break; case WTP_COMMIT_UPDATE: wumPayload->type = WTP_COMMIT_ACK; /* Check if we are in the correct state */ if (wumState.state != WUM_STATE_READY) { *resultCode = CW_PROTOCOL_FAILURE; } /* Start the Update Agent */ StartWUA(); /* Remember to exit after sending the WTP_COMMIT_ACK */ WTPExitOnUpdateCommit = CW_TRUE; break; case WTP_CANCEL_UPDATE_REQUEST: wumPayload->type = WTP_CANCEL_UPDATE_RESPONSE; if (wumState.state == WUM_STATE_BUSY) { /* Accepting fragments */ WUMCloseFile(); if (!remove(CUP_TMP_FILE)) { CWLog("Error while removing cup tmp file."); } } else if (wumState.state == WUM_STATE_READY) { if (!remove(CUP_TMP_FILE)) { CWLog("Error while removing cup tmp file."); } } wumState.state = WUM_STATE_WAIT; } CWLog("Saved WUM Vendor Payload..."); return CW_TRUE; } CWBool CWWTPSaveUCIValues(CWVendorUciValues * uciPayload, CWProtocolResultCode * resultCode) { if (uciPayload == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; struct sockaddr_in serv_addr; int sendSock, slen = sizeof(serv_addr), responseSize, responseCode; unsigned int ArgsSize, response = 0, ArgsSizeNet; char *bufferMessage; if ((sendSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { CWLog("[CWSaveUCIValues]: Error on creation of socket."); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(UCI_SERVER_PORT); if (inet_aton("127.0.0.1", &serv_addr.sin_addr) == 0) { CWLog("[CWSaveUCIValues]: Error on aton function."); close(sendSock); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (uciPayload->commandArgs == NULL) ArgsSize = 0; else ArgsSize = strlen(uciPayload->commandArgs); if ((bufferMessage = malloc(ArgsSize + sizeof(unsigned char) + sizeof(unsigned int))) != NULL) { memcpy(bufferMessage, &(uciPayload->command), sizeof(unsigned char)); /* First Field */ ArgsSizeNet = htonl(ArgsSize); memcpy(bufferMessage + sizeof(unsigned char), &ArgsSizeNet, sizeof(unsigned int)); /* Second Field */ if (uciPayload->commandArgs != NULL) memcpy(bufferMessage + (sizeof(unsigned char) + sizeof(unsigned int)), uciPayload->commandArgs, ArgsSize); /* Third Field */ /*Send conf request to uci daemon */ if (sendto(sendSock, bufferMessage, sizeof(unsigned char), 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWSaveUCIValues]: Error on sendto function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (recvfrom (sendSock, &response, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, (socklen_t *) & slen) < 0) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (!ntohl(response)) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (sendto (sendSock, bufferMessage + sizeof(unsigned char), sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWSaveUCIValues]: Error on sendto function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (recvfrom (sendSock, &response, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, (socklen_t *) & slen) < 0) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (!ntohl(response)) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (ArgsSize > 0) { if (sendto (sendSock, bufferMessage + sizeof(unsigned char) + sizeof(unsigned int), ArgsSize, 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWSaveUCIValues]: Error on sendto function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (recvfrom (sendSock, &response, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, (socklen_t *) & slen) < 0) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (!ntohl(response)) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } } } else { CWLog("[CWSaveUCIValues]: Error on malloc function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } /*Receive result code from uci daemon */ if (recvfrom (sendSock, &responseCode, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, (socklen_t *) & slen) < 0) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } response = htonl(1); if (sendto(sendSock, &response, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWSaveUCIValues]: Error on sendto function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } responseCode = ntohl(responseCode); if (responseCode != 0) /*If we have an error */ *resultCode = CW_PROTOCOL_FAILURE; else { /*OK, that's a go... receive response string (if we have it) */ /*Receive response length from uci daemon */ if (recvfrom (sendSock, &responseSize, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, (socklen_t *) & slen) < 0) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (sendto(sendSock, &response, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWSaveUCIValues]: Error on sendto function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } responseSize = ntohl(responseSize); if (responseSize > 0) { CW_FREE_OBJECT(bufferMessage); /*Fill buffer for response */ if ((bufferMessage = malloc(responseSize * sizeof(unsigned char))) != NULL) { /*Receive from uci daemon the response string */ if (recvfrom (sendSock, bufferMessage, sizeof(unsigned char) * responseSize, 0, (struct sockaddr *)&serv_addr, (socklen_t *) & slen) < 0) { CWLog("[CWSaveUCIValues]: Error on recvfrom function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } if (sendto (sendSock, &response, sizeof(unsigned int), 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWSaveUCIValues]: Error on sendto function."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } /*Copy the buffer in the uci payload structure */ CW_CREATE_STRING_ERR(uciPayload->response, responseSize, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); memcpy(uciPayload->response, bufferMessage, responseSize); uciPayload->response[responseSize] = '\0'; } else { CWLog("[CWSaveUCIValues]: Error on malloc function."); close(sendSock); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } } else { /*If response is empty, set it to NULL (needed after, when the response is built) */ uciPayload->response = NULL; } } CWLog("Saved UCI Vendor Payload..."); close(sendSock); CW_FREE_OBJECT(bufferMessage); return CW_TRUE; } ================================================ FILE: CWWTP.h ================================================ /******************************************************************************************* * Copyright (c) 2005-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_CWWTP_HEADER__ #define __CAPWAP_CWWTP_HEADER__ /*_______________________________________________________*/ /* *******************___INCLUDE___******************* */ #include "CWCommon.h" #include "WTPProtocol.h" #include "WTPBinding.h" /*______________________________________________________*/ /* *******************___DEFINE___******************* */ #define WTP_LOG_FILE_NAME "/var/log/wtp.log.txt" /*_____________________________________________________*/ /* *******************___TYPES___******************* */ typedef struct { char *address; CWBool received; int seqNum; } CWACDescriptor; /*_____________________________________________________________*/ /* *******************___WTP VARIABLES___******************* */ extern char *gInterfaceName; extern char *gEthInterfaceName; extern char *gRadioInterfaceName_0; extern char *gBaseMACInterfaceName; extern char gBoardReversionNo; extern char **gCWACAddresses; extern int gCWACCount; extern int gHostapd_port; extern char *gHostapd_unix_path; extern unsigned char gRADIO_MAC[6]; extern pthread_mutex_t gRADIO_MAC_mutex; extern char *gWTPLocation; extern char *gWTPName; extern unsigned char gWTPSessionID[16]; extern int gIPv4StatusDuplicate; extern int gIPv6StatusDuplicate; extern char *gWTPForceACAddress; extern CWAuthSecurity gWTPForceSecurity; extern CWSocket gWTPSocket; extern CWSocket gWTPDataSocket; extern int gWTPPathMTU; extern unsigned char gWTPMACMode; extern unsigned char gWTPTunnelMode; extern CWACDescriptor *gCWACList; extern CWACInfoValues *gACInfoPtr; extern CWStateTransition gWTPNextState; extern int gEchoInterval; extern int gWTPStatisticsTimer; extern WTPRebootStatisticsInfo gWTPRebootStatistics; extern CWWTPRadiosInfo gRadiosInfo; extern CWSecurityContext gWTPSecurityContext; extern CWSecuritySession gWTPSession; extern CWPendingRequestMessage gPendingRequestMsgs[MAX_PENDING_REQUEST_MSGS]; extern CWSafeList gPacketReceiveList; extern CWSafeList gFrameList; extern CWThreadCondition gInterfaceWait; extern CWThreadMutex gInterfaceMutex; /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ /* in WTP.c */ CWBool CWWTPLoadConfiguration(); CWBool CWWTPInitConfiguration(); void CWWTPResetRadioStatistics(WTPRadioStatisticsInfo * radioStatistics); CWBool CWReceiveMessage(CWProtocolMessage * msgPtr); CWBool CWWTPSendAcknowledgedPacket(int seqNum, CWList msgElemlist, CWBool(assembleFunc) (CWProtocolMessage **, int *, int, int, CWList), CWBool(parseFunc) (unsigned char *, int, int, void *), CWBool(saveFunc) (void *), void *valuesPtr); void CWWTPDestroy(); /* in WTPRunState.c */ CWBool CWAssembleWTPDataTansferRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CWBool CWAssembleWTPEventRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CW_THREAD_RETURN_TYPE CWWTPReceiveDtlsPacket(void *arg); CW_THREAD_RETURN_TYPE CWWTPReceiveDataPacket(void *arg); CWBool CWWTPCheckForBindingFrame(); /* in WTPProtocol_User.c */ CWBool CWWTPGetACNameWithIndex(CWACNamesWithIndex * ACsInfo); int getInterfaceMacAddr(char *interface, unsigned char *macAddr); int initWTPSessionID(unsigned char *sessionID); int CWWTPGetStatisticsTimer(); void CWWTPGetIPv6Address(struct sockaddr_in6 *myAddr); CWBool CWGetWTPRadiosAdminState(CWRadiosAdminInfo * valPtr); CWBool CWGetDecryptErrorReport(int radioID, CWDecryptErrorReportInfo * valPtr); /* in WTPRetransmission.c */ int CWSendPendingRequestMessage(CWPendingRequestMessage * pendingRequestMsgs, CWProtocolMessage * messages, int fragmentsNum); int CWFindPendingRequestMsgsBox(CWPendingRequestMessage * pendingRequestMsgs, const int length, const int msgType, const int seqNum); void CWResetPendingMsgBox(CWPendingRequestMessage * pendingRequestMsgs); CWBool CWUpdatePendingMsgBox(CWPendingRequestMessage * pendingRequestMsgs, unsigned char msgType, int seqNum, int timer_sec, CWTimerArg timer_arg, void (*timer_hdl) (CWTimerArg), int retransmission, CWProtocolMessage * msgElems, int fragmentsNum); #ifdef SOFTMAC //in WTPmacDriverInteraction.c int set_wme_cwmin(int acclass, int value); int set_wme_cwmax(int acclass, int value); int set_wme_aifsn(int acclass, int value); int set_txq(int code, int cwmin, int cwmax, int aifs, int burst_time); #else #ifndef BCM //in WTPDriverInteraction.c int set_cwmin(int sock, struct iwreq wrq, int acclass, int sta, int value); int get_cwmin(int sock, struct iwreq *wrq, int acclass, int sta); int set_cwmax(int sock, struct iwreq wrq, int acclass, int sta, int value); int get_cwmax(int sock, struct iwreq *wrq, int acclass, int sta); int set_aifs(int sock, struct iwreq wrq, int acclass, int sta, int value); int get_aifs(int sock, struct iwreq *wrq, int acclass, int sta); #else //in WTPBcmDriverInteraction.c int set_wme_cwmin(int acclass, int value); int set_wme_cwmax(int acclass, int value); int set_wme_aifsn(int acclass, int value); #endif #endif /* in WTPDiscoveryState.c */ CWStateTransition CWWTPEnterDiscovery(); void CWWTPPickACInterface(); CWStateTransition CWWTPEnterSulking(); CWStateTransition CWWTPEnterJoin(); CWStateTransition CWWTPEnterConfigure(); CWStateTransition CWWTPEnterDataCheck(); CWStateTransition CWWTPEnterRun(); CWBool CWStartHeartbeatTimer(); CWBool CWStopHeartbeatTimer(); CWBool CWStartNeighborDeadTimer(); CWBool CWStopNeighborDeadTimer(); CWBool CWResetTimers(); void CWWTPHeartBeatTimerExpiredHandler(void *arg); void CWWTPRetransmitTimerExpiredHandler(CWTimerArg arg); extern CWBool WTPExitOnUpdateCommit; #endif ================================================ FILE: Doxyfile ================================================ # Doxyfile 1.4.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = Capwap PROJECT_NUMBER = OUTPUT_DIRECTORY = /usr/local/src2/capwap/doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = /usr/local/src2/capwap/ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = /usr/local/src2/capwap FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM \ *.PY RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = YES STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = YES DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = YES TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = YES GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO ================================================ FILE: INSTALL.rst ================================================ ============================================= HOW TO BUILD AND RUN CAPWAP FOR LINUX SYSTEMS ============================================= NOTE: To run WTP you must have a wireless card that has Linux driver based on the Generic IEEE 802.11 Networking Stack (mac80211). HOW TO BUILD AC AND WTP ======================= Requirements ------------ * automake 1.9 or newer * autoconf * libtool * openssl Build ----- Run: autoreconf -f -i -s CFLAGS="-I/usr/include/openssl -DLOCALUDP" ./configure make make install Use the CFLAGS setting "-DLOCALUDP" to use local UNIX sockets for hostapd to AC/WTP communication. The openssl include path needs to be adjusted to your local openssl installation directory. HOW TO RUN WTP ============== * build hostapd with capwap support, see hostapd_wrapper/README.rst for instructions * make sure that your PCMCIA wireless card is working * create a wireless interfaces on the WiFi card in "ap" mode, /usr/sbin/iw phy phy0 interface add wlan0 type managed * adjust settings.wtp.txt and config.wtp * run WTP in superuser mode * run hostapd (see also hostapd_wrapper/README.rst) HOW TO RUN AC ============= * build hostapd with capwap support, see hostapd_wrapper/README.rst for instructions * adjust settings.ac.txt and config.ac * run AC in superuser mode * run hostapd (see also hostapd_wrapper/README.rst) ================================================ FILE: Makefile.am ================================================ ACLOCAL_AMFLAGS=-I m4 AM_CPPFLAGS = -I$(srcdir)/include -D_REENTRANT AM_CPPFLAGS += -DOPENSSL_NO_KRB5 # Capwap Debugging AM_CPPFLAGS += -DWRITE_STD_OUTPUT AM_CPPFLAGS += -DSOFTMAC AM_CPPFLAGS += -Wall bin_PROGRAMS = AC WTP WUA noinst_LTLIBRARIES = libcapwap.la libcapwap_la_SOURCES = \ CWLog.c \ CWCommon.c \ CWConfigFile.c \ CWErrorHandling.c \ CWList.c \ CWSafeList.c \ CWNetwork.c \ CWProtocol.c \ CWRandom.c \ CWStevens.c \ CWThread.c \ CWBinding.c \ CWVendorPayloadsAC.c \ CWVendorPayloadsWTP.c \ timerlib.c if USE_SSL libcapwap_la_SOURCES += \ CWSecurity.c \ CWOpenSSLBio.c endif libcapwap_la_CFLAGS = ${OPENSSL_INCLUDES} libcapwap_la_LIBADD = ${OPENSSL_LDFLAGS} ${OPENSSL_LIBS} AC_SOURCES = \ AC.c \ ACConfigFile.c \ ACMainLoop.c \ ACDiscoveryState.c \ ACJoinState.c \ ACConfigureState.c \ ACDataCheckState.c \ ACRunState.c \ ACProtocol_User.c \ ACRetransmission.c \ ACMultiHomedSocket.c \ ACProtocol.c \ ACBinding.c \ ACInterface.c \ ACSettingsFile.c \ tap.c \ ACipcHostapd.c AC_LDADD = libcapwap.la WTP_SOURCES = \ WTP.c \ WTPipcHostapd.c \ WTPmacFrameReceive.c \ WTPFreqStatsReceive.c \ WTPStatsReceive.c \ WTPConfigFile.c \ WTPProtocol.c \ WTPProtocol_User.c \ WTPDiscoveryState.c \ WTPJoinState.c \ WTPConfigureState.c \ WTPDataCheckState.c \ WTPRunState.c \ WTPRunStateCheck.c \ WTPRetransmission.c \ WTPSulkingState.c \ WTPBinding.c \ WTPmacDriverInteraction.c \ WTPSettingsFile.c WTP_LDADD = libcapwap.la WUA_SOURCES = WUA.c ================================================ FILE: Makefile.bcm ================================================ # ******************************************************************************************* # * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * # * Universita' Campus BioMedico - Italy * # * * # * 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., 59 Temple Place - Suite 330, Boston, * # * MA 02111-1307, USA. * # * * # * --------------------------------------------------------------------------------------- * # * Project: Capwap * # * * # * Author : Ludovico Rossi (ludo@bluepixysw.com) * # * Del Moro Andrea (andrea_delmoro@libero.it) * # * Giovannini Federica (giovannini.federica@gmail.com) * # * Massimo Vellucci (m.vellucci@unicampus.it) * # * Mauro Bisson (mauro.bis@gmail.com) * # ******************************************************************************************* KAMIKAZEDIR=/home/daniele/Scrivania/kamikaze-SDK CC = $(KAMIKAZEDIR)/staging_dir_mipsel/bin/mipsel-linux-gcc LDFLAGS = $(KAMIKAZEDIR)/staging_dir_mipsel/usr/lib/libssl.a $(KAMIKAZEDIR)/staging_dir_mipsel/usr/lib/libcrypto.a $(KAMIKAZEDIR)/staging_dir_mipsel/lib/libpthread.a $(KAMIKAZEDIR)/staging_dir_mipsel/lib/libdl.a $(KAMIKAZEDIR)/staging_dir_mipsel/usr/lib/libpcap.a -D_REENTRANT CFLAGS = -Wall -g -O0 -D_REENTRANT -DBCM -I $(KAMIKAZEDIR)/staging_dir_mipsel/usr/include #-DCW_NO_DTLS # Memory leak #LDFLAGS += ../dmalloc-5.5.0/libdmallocth.a #CFLAGS += -DDMALLOC # Capwap Debugging CFLAGS += -DCW_DEBUGGING RM = /bin/rm -f # list of generated object files for WTP. WTP_OBJS = WTP.o WTPBcmFrameReceive.o WTPConfigFile.o WTPProtocol.o WTPProtocol_User.o WTPDiscoveryState.o WTPJoinState.o WTPConfigureState.o WTPDataCheckState.o WTPRunState.o WTPRunStateCheck.o WTPRetransmission.o WTPSulkingState.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWSafeList.o CWList.o CWLog.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o WTPBinding.o WTPBcmDriverInteraction.o WTPSettingsFile.o timerlib.o WTP_SRCS = $(WTP_OBJS:.o=.c) WTP_DEPS := $(WTP_OBJS:.o=.d) # program executables. WTP_NAME = WTP .PHONY: deps clean clean_libs libs # top-level rule, to compile everything. all: $(WTP_NAME) $(WTP_NAME): $(WTP_OBJS) $(CC) -DWRITE_STD_OUTPUT $(WTP_OBJS) $(CC_FLAGS) $(LDFLAGS) -o $(WTP_NAME) clean: $(RM) $(WTP_NAME) $(WTP_OBJS) $(WTP_DEPS) clean_deps: $(WTP_DEPS) deps: $(WTP_SRC) $(CC) -MD -E -DWRITE_STD_OUTPUT $(WTP_SRCS) $(CFLAGS) >/dev/null -include $(WTP_DEPS) ================================================ FILE: Makefile.glibc ================================================ # ******************************************************************************************* # * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * # * Universita' Campus BioMedico - Italy * # * * # * 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., 59 Temple Place - Suite 330, Boston, * # * MA 02111-1307, USA. * # * * # * --------------------------------------------------------------------------------------- * # * Project: Capwap * # * * # * Author : Ludovico Rossi (ludo@bluepixysw.com) * # * Del Moro Andrea (andrea_delmoro@libero.it) * # * Giovannini Federica (giovannini.federica@gmail.com) * # * Massimo Vellucci (m.vellucci@unicampus.it) * # ******************************************************************************************* CC = gcc #LDFLAGS = -lssl -lcrypto -lpthread -ldl -D_REENTRANT #LDFLAGS = /usr/lib/libefence.a ./static/libssl.a ./static/libcrypto.a -lpthread -ldl -D_REENTRANT LDFLAGS = ./static/libssl.a ./static/libcrypto.a -lpthread -ldl -D_REENTRANT CFLAGS = -Wall -g -O0 -D_REENTRANT -I/usr/local/ssl/include/ #-DCW_NO_DTLS OPENSSL_INCLUDE = #-I/usr/local/ssl/include/ #Openssl include files # Memory leak #LDFLAGS += ../dmalloc-5.5.0/libdmallocth.a #CFLAGS += -DDMALLOC # Capwap Debugging CFLAGS += -DCW_DEBUGGING RM = /bin/rm -f # list of generated object files for AC. AC_OBJS = AC.o ACConfigFile.o ACMainLoop.o ACDiscoveryState.o ACJoinState.o ACConfigureState.o ACDataCheckState.o ACRunState.o ACProtocol_User.o ACRetransmission.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWList.o CWLog.o ACMultiHomedSocket.o ACProtocol.o CWSafeList.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o CWVendorPayloadsAC.o ACBinding.o ACInterface.o ACSettingsFile.o timerlib.o # list of generated object files for WTP. WTP_OBJS = WTP.o WTPFrameReceive.o WTPFreqStatsReceive.o WTPStatsReceive.o WTPConfigFile.o WTPProtocol.o WTPProtocol_User.o WTPDiscoveryState.o WTPJoinState.o WTPConfigureState.o WTPDataCheckState.o WTPRunState.o WTPRunStateCheck.o WTPRetransmission.o WTPSulkingState.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWSafeList.o CWList.o CWLog.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o CWVendorPayloadsWTP.o WTPBinding.o WTPDriverInteraction.o WTPSettingsFile.o timerlib.o AC_SRCS = $(AC_OBJS:.o=.c) WTP_SRCS = $(WTP_OBJS:.o=.c) AC_DEPS := $(AC_OBJS:.o=.d) WTP_DEPS := $(WTP_OBJS:.o=.d) # program executables. AC_NAME = AC WTP_NAME = WTP .PHONY: deps clean clean_libs libs # top-level rule, to compile everything. all: $(AC_NAME) $(WTP_NAME) $(AC_NAME): $(AC_OBJS) $(CC) $(AC_OBJS) $(CC_FLAGS) $(OPENSSL_INCLUDE) $(LDFLAGS) -o $(AC_NAME) $(WTP_NAME): $(WTP_OBJS) $(CC) -DWRITE_STD_OUTPUT $(WTP_OBJS) $(CC_FLAGS) $(LDFLAGS) -o $(WTP_NAME) clean: $(RM) $(AC_NAME) $(WTP_NAME) $(AC_OBJS) $(WTP_OBJS) $(AC_DEPS) $(WTP_DEPS) clean_deps: $(AC_DEPS) $(WTP_DEPS) deps: $(AC_SRC) $(WTP_SRC) $(CC) -MD -E $(AC_SRCS) $(CFLAGS) >/dev/null $(CC) -MD -E -DWRITE_STD_OUTPUT $(WTP_SRCS) $(CFLAGS) >/dev/null -include $(AC_DEPS) -include $(WTP_DEPS) ================================================ FILE: Makefile.uclibc ================================================ # ******************************************************************************************* # * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * # * Universita' Campus BioMedico - Italy * # * * # * 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., 59 Temple Place - Suite 330, Boston, * # * MA 02111-1307, USA. * # * * # * --------------------------------------------------------------------------------------- * # * Project: Capwap * # * * # * Author : Ludovico Rossi (ludo@bluepixysw.com) * # * Del Moro Andrea (andrea_delmoro@libero.it) * # * Giovannini Federica (giovannini.federica@gmail.com) * # * Massimo Vellucci (m.vellucci@unicampus.it) * # ******************************************************************************************* CC = gcc-openwrt #LDFLAGS = -lssl -lcrypto -lpthread -ldl -D_REENTRANT #LDFLAGS = /usr/lib/libefence.a ./static/libssl.a ./static/libcrypto.a -lpthread -ldl -D_REENTRANT LDFLAGS = ./static/uclibc/libssl.a ./static/uclibc/libcrypto.a -lpthread -ldl -D_REENTRANT CFLAGS = -Wall -g -O0 -D_REENTRANT -I./include/ #-DCW_NO_DTLS OPENSSL_INCLUDE = #-I/usr/local/ssl/include/ #Openssl include files # Memory leak #LDFLAGS += ../dmalloc-5.5.0/libdmallocth.a #CFLAGS += -DDMALLOC # Capwap Debugging CFLAGS += -DCW_DEBUGGING CFLAGS += -DOPENSSL_NO_KRB5 RM = /bin/rm -f # list of generated object files for AC. AC_OBJS = AC.o ACConfigFile.o ACMainLoop.o ACDiscoveryState.o ACJoinState.o ACConfigureState.o ACDataCheckState.o ACRunState.o ACProtocol_User.o ACRetransmission.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWList.o CWLog.o ACMultiHomedSocket.o ACProtocol.o CWSafeList.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o CWVendorPayloadsAC.o ACBinding.o ACInterface.o ACSettingsFile.o timerlib.o # list of generated object files for WTP. WTP_OBJS = WTP.o WTPFrameReceive.o WTPFreqStatsReceive.o WTPStatsReceive.o WTPConfigFile.o WTPProtocol.o WTPProtocol_User.o WTPDiscoveryState.o WTPJoinState.o WTPConfigureState.o WTPDataCheckState.o WTPRunState.o WTPRunStateCheck.o WTPRetransmission.o WTPSulkingState.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWSafeList.o CWList.o CWLog.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o CWVendorPayloadsWTP.o WTPBinding.o WTPDriverInteraction.o WTPSettingsFile.o timerlib.o WUA_OBJS = WUA.o AC_SRCS = $(AC_OBJS:.o=.c) WTP_SRCS = $(WTP_OBJS:.o=.c) WUA_SRCS = $(WUA:OBJS:.o=.c) AC_DEPS := $(AC_OBJS:.o=.d) WTP_DEPS := $(WTP_OBJS:.o=.d) WUA_DEPS := $(WUA_OBJS:.o=.d) # program executables. AC_NAME = AC WTP_NAME = WTP WUA_NAME = WUA .PHONY: deps clean clean_libs libs # top-level rule, to compile everything. all: $(AC_NAME) $(WTP_NAME) $(AC_NAME): $(AC_OBJS) $(CC) $(AC_OBJS) $(CC_FLAGS) $(OPENSSL_INCLUDE) $(LDFLAGS) -o $(AC_NAME) $(WTP_NAME): $(WTP_OBJS) $(CC) -DWRITE_STD_OUTPUT $(WTP_OBJS) $(CC_FLAGS) $(LDFLAGS) -o $(WTP_NAME) $(WUA_NAME): $(WUA_OBJS) $(CC) $(WUA_OBJS) $(CC_FLAGS) $(LDFLAGS) -o $(WUA_NAME) clean: $(RM) $(AC_NAME) $(WTP_NAME) $(WUA_NAME) $(AC_OBJS) $(WTP_OBJS) $(WUA_OBJS) $(AC_DEPS) $(WTP_DEPS) clean_deps: $(AC_DEPS) $(WTP_DEPS) deps: $(AC_SRC) $(WTP_SRC) $(CC) -MD -E $(AC_SRCS) $(CFLAGS) >/dev/null $(CC) -MD -E -DWRITE_STD_OUTPUT $(WTP_SRCS) $(CFLAGS) >/dev/null -include $(AC_DEPS) -include $(WTP_DEPS) ================================================ FILE: MakefileMac ================================================ # ******************************************************************************************* # * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * # * Universita' Campus BioMedico - Italy * # * * # * 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., 59 Temple Place - Suite 330, Boston, * # * MA 02111-1307, USA. * # * * # * --------------------------------------------------------------------------------------- * # * Project: Capwap * # * * # * Author : Ludovico Rossi (ludo@bluepixysw.com) * # * Del Moro Andrea (andrea_delmoro@libero.it) * # * Giovannini Federica (giovannini.federica@gmail.com) * # * Massimo Vellucci (m.vellucci@unicampus.it) * # ******************************************************************************************* CC = gcc #LDFLAGS = -lssl -lcrypto -lpthread -ldl -D_REENTRANT #LDFLAGS = /usr/lib/libefence.a ./static/libssl.a ./static/libcrypto.a -lpthread -ldl -D_REENTRANT LDFLAGS = /opt/local/lib/libssl.a /opt/local/lib/libcrypto.a /opt/local/lib/libz.a -lpthread -ldl -D_REENTRANT CFLAGS = -Wall -g -O0 -D_REENTRANT -I/opt/local/include/ #-DCW_NO_DTLS OPENSSL_INCLUDE = #-I/opt/local/include/ #Openssl include files # Memory leak #LDFLAGS += ../dmalloc-5.5.0/libdmallocth.a #CFLAGS += -DDMALLOC # Capwap Debugging CFLAGS += -DCW_DEBUGGING -DMACOSX RM = /bin/rm -f # list of generated object files for AC. AC_OBJS = AC.o ACConfigFile.o ACMainLoop.o ACDiscoveryState.o ACJoinState.o ACConfigureState.o ACDataCheckState.o ACRunState.o ACProtocol_User.o ACRetransmission.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWList.o CWLog.o ACMultiHomedSocket.o ACProtocol.o CWSafeList.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o ACBinding.o ACInterface.o ACSettingsFile.o timerlib.o # list of generated object files for WTP. WTP_OBJS = WTP.o WTPFrameReceive.o WTPFreqStatsReceive.o WTPStatsReceive.o WTPConfigFile.o WTPProtocol.o WTPProtocol_User.o WTPDiscoveryState.o WTPJoinState.o WTPConfigureState.o WTPDataCheckState.o WTPRunState.o WTPRunStateCheck.o WTPRetransmission.o WTPSulkingState.o CWCommon.o CWConfigFile.o CWErrorHandling.o CWSafeList.o CWList.o CWLog.o CWNetwork.o CWProtocol.o CWRandom.o CWSecurity.o CWOpenSSLBio.o CWStevens.o CWThread.o CWBinding.o WTPBinding.o WTPDriverInteraction.o WTPSettingsFile.o timerlib.o AC_SRCS = $(AC_OBJS:.o=.c) WTP_SRCS = $(WTP_OBJS:.o=.c) AC_DEPS := $(AC_OBJS:.o=.d) WTP_DEPS := $(WTP_OBJS:.o=.d) # program executables. AC_NAME = AC WTP_NAME = WTP .PHONY: deps clean clean_libs libs # top-level rule, to compile everything. all: $(AC_NAME) $(WTP_NAME) $(AC_NAME): $(AC_OBJS) $(CC) $(AC_OBJS) $(CC_FLAGS) $(OPENSSL_INCLUDE) $(LDFLAGS) -o $(AC_NAME) $(WTP_NAME): $(WTP_OBJS) $(CC) -DWRITE_STD_OUTPUT $(WTP_OBJS) $(CC_FLAGS) $(LDFLAGS) -o $(WTP_NAME) clean: $(RM) $(AC_NAME) $(WTP_NAME) $(AC_OBJS) $(WTP_OBJS) $(AC_DEPS) $(WTP_DEPS) clean_deps: $(AC_DEPS) $(WTP_DEPS) deps: $(AC_SRC) $(WTP_SRC) $(CC) -MD -E $(AC_SRCS) $(CFLAGS) >/dev/null $(CC) -MD -E -DWRITE_STD_OUTPUT $(WTP_SRCS) $(CFLAGS) >/dev/null -include $(AC_DEPS) -include $(WTP_DEPS) ================================================ FILE: README.md ================================================ ================================================ FILE: WTP.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #ifdef SOFTMAC CW_THREAD_RETURN_TYPE CWWTPThread_read_data_from_hostapd(void *arg); #endif CW_THREAD_RETURN_TYPE CWWTPReceiveFrame(void *arg); CW_THREAD_RETURN_TYPE CWWTPReceiveStats(void *arg); CW_THREAD_RETURN_TYPE CWWTPReceiveFreqStats(void *arg); CW_THREAD_RETURN_TYPE gogo(void *arg); int gEnabledLog; int gMaxLogFileSize; char gLogFileName[] = WTP_LOG_FILE_NAME; /* addresses of ACs for Discovery */ char **gCWACAddresses; int gCWACCount = 0; int gIPv4StatusDuplicate = 0; int gIPv6StatusDuplicate = 0; char *gWTPLocation = NULL; char *gWTPName = NULL; unsigned char gWTPSessionID[16]; /* if not NULL, jump Discovery and use this address for Joining */ char *gWTPForceACAddress = NULL; CWAuthSecurity gWTPForceSecurity; /* UDP network socket */ CWSocket gWTPSocket; CWSocket gWTPDataSocket; /* DTLS session vars */ CWSecurityContext gWTPSecurityContext; CWSecuritySession gWTPSession; /* list used to pass frames from wireless interface to main thread */ CWSafeList gFrameList; /* list used to pass CAPWAP packets from AC to main thread */ CWSafeList gPacketReceiveList; /* used to synchronize access to the lists */ CWThreadCondition gInterfaceWait; CWThreadMutex gInterfaceMutex; /* infos about the ACs to discover */ CWACDescriptor *gCWACList = NULL; /* infos on the better AC we discovered so far */ CWACInfoValues *gACInfoPtr = NULL; /* WTP statistics timer */ int gWTPStatisticsTimer = CW_STATISTIC_TIMER_DEFAULT; WTPRebootStatisticsInfo gWTPRebootStatistics; CWWTPRadiosInfo gRadiosInfo; /* path MTU of the current session */ int gWTPPathMTU = 0; unsigned char gWTPMACMode = CW_SPLIT_MAC; unsigned char gWTPTunnelMode = CW_TUNNEL_MODE_802_DOT_11_TUNNEL; int gWTPRetransmissionCount; CWStateTransition gWTPNextState; CWPendingRequestMessage gPendingRequestMsgs[MAX_PENDING_REQUEST_MSGS]; CWBool WTPExitOnUpdateCommit = CW_FALSE; #define CW_SINGLE_THREAD /* * Receive a message, that can be fragmented. This is useful not only for the Join State */ CWBool CWReceiveMessage(CWProtocolMessage * msgPtr) { CWList fragments = NULL; int readBytes; unsigned char buf[CW_BUFFER_SIZE]; CWBool dataFlag = CW_FALSE; CW_REPEAT_FOREVER { CW_ZERO_MEMORY(buf, CW_BUFFER_SIZE); #ifdef CW_NO_DTLS char *pkt_buffer = NULL; CWLockSafeList(gPacketReceiveList); while (CWGetCountElementFromSafeList(gPacketReceiveList) == 0) CWWaitElementFromSafeList(gPacketReceiveList); pkt_buffer = (char *)CWRemoveHeadElementFromSafeListwithDataFlag(gPacketReceiveList, &readBytes, &dataFlag); CWUnlockSafeList(gPacketReceiveList); CW_COPY_MEMORY(buf, pkt_buffer, readBytes); CW_FREE_OBJECT(pkt_buffer); #else if (!CWSecurityReceive(gWTPSession, buf, CW_BUFFER_SIZE, &readBytes)) { return CW_FALSE; } #endif if (!CWProtocolParseFragment(buf, readBytes, &fragments, msgPtr, &dataFlag, NULL)) { if (CWErrorGetLastErrorCode() == CW_ERROR_NEED_RESOURCE) { // we need at least one more fragment continue; } else { // error CWErrorCode error; error = CWErrorGetLastErrorCode(); switch (error) { case CW_ERROR_SUCCESS:{ CWDebugLog("ERROR: Success"); break; } case CW_ERROR_OUT_OF_MEMORY:{ CWDebugLog("ERROR: Out of Memory"); break; } case CW_ERROR_WRONG_ARG:{ CWDebugLog("ERROR: Wrong Argument"); break; } case CW_ERROR_INTERRUPTED:{ CWDebugLog("ERROR: Interrupted"); break; } case CW_ERROR_NEED_RESOURCE:{ CWDebugLog("ERROR: Need Resource"); break; } case CW_ERROR_COMUNICATING:{ CWDebugLog("ERROR: Comunicating"); break; } case CW_ERROR_CREATING:{ CWDebugLog("ERROR: Creating"); break; } case CW_ERROR_GENERAL:{ CWDebugLog("ERROR: General"); break; } case CW_ERROR_OPERATION_ABORTED:{ CWDebugLog("ERROR: Operation Aborted"); break; } case CW_ERROR_SENDING:{ CWDebugLog("ERROR: Sending"); break; } case CW_ERROR_RECEIVING:{ CWDebugLog("ERROR: Receiving"); break; } case CW_ERROR_INVALID_FORMAT:{ CWDebugLog("ERROR: Invalid Format"); break; } case CW_ERROR_TIME_EXPIRED:{ CWDebugLog("ERROR: Time Expired"); break; } case CW_ERROR_NONE:{ CWDebugLog("ERROR: None"); break; } } CWDebugLog("~~~~~~"); return CW_FALSE; } } else break; // the message is fully reassembled } return CW_TRUE; } CWBool CWWTPSendAcknowledgedPacket(int seqNum, CWList msgElemlist, CWBool(assembleFunc) (CWProtocolMessage **, int *, int, int, CWList), CWBool(parseFunc) (unsigned char *, int, int, void *), CWBool(saveFunc) (void *), void *valuesPtr) { CWProtocolMessage *messages = NULL; CWProtocolMessage msg; int fragmentsNum = 0, i; struct timespec timewait; int gTimeToSleep = gCWRetransmitTimer; int gMaxTimeToSleep = CW_ECHO_INTERVAL_DEFAULT / 2; msg.msg = NULL; if (!(assembleFunc(&messages, &fragmentsNum, gWTPPathMTU, seqNum, msgElemlist))) { goto cw_failure; } gWTPRetransmissionCount = 0; while (gWTPRetransmissionCount < gCWMaxRetransmit) { CWDebugLog("Transmission Num:%d", gWTPRetransmissionCount); for (i = 0; i < fragmentsNum; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected(gWTPSocket, messages[i].msg, messages[i].offset)) #else if (!CWSecuritySend(gWTPSession, messages[i].msg, messages[i].offset)) #endif { CWDebugLog("Failure sending Request"); goto cw_failure; } } timewait.tv_sec = time(0) + gTimeToSleep; timewait.tv_nsec = 0; CW_REPEAT_FOREVER { CWThreadMutexLock(&gInterfaceMutex); if (CWGetCountElementFromSafeList(gPacketReceiveList) > 0) CWErrorRaise(CW_ERROR_SUCCESS, NULL); else { if (CWErr(CWWaitThreadConditionTimeout(&gInterfaceWait, &gInterfaceMutex, &timewait))) CWErrorRaise(CW_ERROR_SUCCESS, NULL); } CWThreadMutexUnlock(&gInterfaceMutex); switch (CWErrorGetLastErrorCode()) { case CW_ERROR_TIME_EXPIRED:{ gWTPRetransmissionCount++; goto cw_continue_external_loop; break; } case CW_ERROR_SUCCESS:{ /* there's something to read */ if (!(CWReceiveMessage(&msg))) { CW_FREE_PROTOCOL_MESSAGE(msg); CWDebugLog("Failure Receiving Response"); goto cw_failure; } if (!(parseFunc(msg.msg, msg.offset, seqNum, valuesPtr))) { if (CWErrorGetLastErrorCode() != CW_ERROR_INVALID_FORMAT) { CW_FREE_PROTOCOL_MESSAGE(msg); CWDebugLog("Failure Parsing Response"); goto cw_failure; } else { CWErrorHandleLast(); { gWTPRetransmissionCount++; goto cw_continue_external_loop; } break; } } if ((saveFunc(valuesPtr))) { goto cw_success; } else { if (CWErrorGetLastErrorCode() != CW_ERROR_INVALID_FORMAT) { CW_FREE_PROTOCOL_MESSAGE(msg); CWDebugLog("Failure Saving Response"); goto cw_failure; } } break; } case CW_ERROR_INTERRUPTED:{ gWTPRetransmissionCount++; goto cw_continue_external_loop; break; } default:{ CWErrorHandleLast(); CWDebugLog("Failure"); goto cw_failure; break; } } } cw_continue_external_loop: CWDebugLog("Retransmission time is over"); gTimeToSleep <<= 1; if (gTimeToSleep > gMaxTimeToSleep) gTimeToSleep = gMaxTimeToSleep; } /* too many retransmissions */ return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "Peer Dead"); cw_success: for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); CW_FREE_PROTOCOL_MESSAGE(msg); return CW_TRUE; cw_failure: if (messages != NULL) { for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); } CWDebugLog("Failure"); return CW_FALSE; } void usage(void) { } int main(int argc, char * const argv[]) { int run_daemon = 1; int c; #ifdef CW_DEBUGGING const struct rlimit rlim = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY }; /* unlimited size for cores */ setrlimit(RLIMIT_CORE, &rlim); #endif while (-1 != (c = getopt(argc, argv, "hf"))) { switch(c) { case 'h': usage(); exit(1); break; case 'f': run_daemon = 0; break; default: usage(); exit(1); break; } } /* Daemon Mode */ if (run_daemon) if (daemon(1, 0) != 0) { fprintf(stderr, "daemon failed: %s\n", strerror(errno)); exit(1); } CWLogInitFile(WTP_LOG_FILE_NAME); fprintf(stderr, "log init done\n"); #ifndef CW_SINGLE_THREAD CWDebugLog("Use Threads"); #else CWDebugLog("Don't Use Threads"); #endif fprintf(stderr, "log init done\n"); CWErrorHandlingInitLib(); if (!CWParseSettingsFile()) { CWLog("Can't start WTP"); exit(1); } /* Capwap receive packets list */ if (!CWErr(CWCreateSafeList(&gPacketReceiveList))) { CWLog("Can't start WTP"); exit(1); } /* Capwap receive frame list */ if (!CWErr(CWCreateSafeList(&gFrameList))) { CWLog("Can't start WTP"); exit(1); } CWCreateThreadMutex(&gInterfaceMutex); CWSetMutexSafeList(gPacketReceiveList, &gInterfaceMutex); CWSetMutexSafeList(gFrameList, &gInterfaceMutex); CWCreateThreadCondition(&gInterfaceWait); CWSetConditionSafeList(gPacketReceiveList, &gInterfaceWait); CWSetConditionSafeList(gFrameList, &gInterfaceWait); CWLog("Starting WTP..."); CWRandomInitLib(); CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); if (timer_init() == 0) { CWLog("Can't init timer module"); exit(1); } #ifdef CW_NO_DTLS if (!CWErr(CWWTPLoadConfiguration())) { #else if (!CWErr(CWSecurityInitLib()) || !CWErr(CWWTPLoadConfiguration())) { #endif CWLog("Can't start WTP"); exit(1); } CWDebugLog("Init WTP Radio Info"); if (!CWWTPInitConfiguration()) { CWLog("Error Init Configuration"); exit(1); } #ifdef SOFTMAC CWThread thread_ipc_with_wtp_hostapd; if (!CWErr(CWCreateThread(&thread_ipc_with_wtp_hostapd, CWWTPThread_read_data_from_hostapd, NULL))) { CWLog("Error starting Thread that receive command and 802.11 frame from hostapd (WTP side)"); exit(1); } #endif CWThread thread_receiveFrame; if (!CWErr(CWCreateThread(&thread_receiveFrame, CWWTPReceiveFrame, NULL))) { CWLog("Error starting Thread that receive binding frame"); exit(1); } CWThread thread_receiveStats; if (!CWErr(CWCreateThread(&thread_receiveStats, CWWTPReceiveStats, NULL))) { CWLog("Error starting Thread that receive stats on monitoring interface"); exit(1); } /**************************************** * 2009 Update: * * Spawn Frequency Stats * * Receiver Thread * ****************************************/ CWThread thread_receiveFreqStats; if (!CWErr(CWCreateThread(&thread_receiveFreqStats, CWWTPReceiveFreqStats, NULL))) { CWLog("Error starting Thread that receive frequency stats on monitoring interface"); exit(1); } /* if AC address is given jump Discovery and use this address for Joining */ if (gWTPForceACAddress != NULL) gWTPNextState = CW_ENTER_JOIN; /* Setting hostapd default MAC char for checking in join state */ gRADIO_MAC[0] = 0xAA; /* start CAPWAP state machine */ CW_REPEAT_FOREVER { CWDebugLog("nextState is %d", gWTPNextState); switch (gWTPNextState) { case CW_ENTER_DISCOVERY: gWTPNextState = CWWTPEnterDiscovery(); break; case CW_ENTER_SULKING: gWTPNextState = CWWTPEnterSulking(); break; case CW_ENTER_JOIN: gWTPNextState = CWWTPEnterJoin(); break; case CW_ENTER_CONFIGURE: gWTPNextState = CWWTPEnterConfigure(); break; case CW_ENTER_DATA_CHECK: gWTPNextState = CWWTPEnterDataCheck(); break; case CW_ENTER_RUN: gWTPNextState = CWWTPEnterRun(); break; case CW_ENTER_RESET: /* * CWStopHeartbeatTimer(); * CWStopNeighborDeadTimer(); * CWNetworkCloseSocket(gWTPSocket); * CWSecurityDestroySession(gWTPSession); * CWSecurityDestroyContext(gWTPSecurityContext); * gWTPSecurityContext = NULL; * gWTPSession = NULL; */ if (gWTPForceACAddress != NULL) gWTPNextState = CW_ENTER_JOIN; else gWTPNextState = CW_ENTER_DISCOVERY; break; case CW_QUIT: CWWTPDestroy(); CWLogCloseFile(); return 0; } } } unsigned int CWGetSeqNum() { static unsigned int seqNum = 0; if (seqNum == CW_MAX_SEQ_NUM) seqNum = 0; else seqNum++; return seqNum; } int CWGetFragmentID() { static int fragID = 0; return fragID++; } /* * Parses config file and inits WTP configuration. */ CWBool CWWTPLoadConfiguration() { int i; CWLog("WTP Loads Configuration"); /* get saved preferences */ if (!CWErr(CWParseConfigFile())) { CWLog("Can't Read Config File"); exit(1); } if (gCWACCount == 0) return CWErrorRaise(CW_ERROR_NEED_RESOURCE, "No AC Configured"); CW_CREATE_ARRAY_ERR(gCWACList, gCWACCount, CWACDescriptor, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < gCWACCount; i++) { CWDebugLog("Init Configuration for AC at %s", gCWACAddresses[i]); CW_CREATE_STRING_FROM_STRING_ERR(gCWACList[i].address, gCWACAddresses[i], return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } CW_FREE_OBJECTS_ARRAY(gCWACAddresses, gCWACCount); return CW_TRUE; } void CWWTPDestroy() { int i; CWLog("Destroy WTP"); for (i = 0; i < gCWACCount; i++) { CW_FREE_OBJECT(gCWACList[i].address); } timer_destroy(); CW_FREE_OBJECT(gCWACList); CW_FREE_OBJECT(gRadiosInfo.radiosInfo); } CWBool CWWTPInitConfiguration() { CWDebugLog("CWWTPInitConfiguration"); int i; //Generate 128-bit Session ID, initWTPSessionID(&gWTPSessionID[0]); CWWTPResetRebootStatistics(&gWTPRebootStatistics); gRadiosInfo.radioCount = CWWTPGetMaxRadios(); CW_CREATE_ARRAY_ERR(gRadiosInfo.radiosInfo, gRadiosInfo.radioCount, CWWTPRadioInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); gRadiosInfo.radiosInfo[0].radioID = 0; /* gRadiosInfo.radiosInfo[0].numEntries = 0; */ gRadiosInfo.radiosInfo[0].decryptErrorMACAddressList = NULL; gRadiosInfo.radiosInfo[0].reportInterval = CW_REPORT_INTERVAL_DEFAULT; gRadiosInfo.radiosInfo[0].adminState = ENABLED; gRadiosInfo.radiosInfo[0].adminCause = AD_NORMAL; gRadiosInfo.radiosInfo[0].operationalState = ENABLED; gRadiosInfo.radiosInfo[0].operationalCause = OP_NORMAL; gRadiosInfo.radiosInfo[0].TxQueueLevel = 0; gRadiosInfo.radiosInfo[0].wirelessLinkFramesPerSec = 0; CWWTPResetRadioStatistics(&(gRadiosInfo.radiosInfo[0].statistics)); if (!CWWTPInitBinding(0)) { return CW_FALSE; } for (i = 1; i < gRadiosInfo.radioCount; i++) { gRadiosInfo.radiosInfo[i].radioID = i; /* gRadiosInfo.radiosInfo[i].numEntries = 0; */ gRadiosInfo.radiosInfo[i].decryptErrorMACAddressList = NULL; gRadiosInfo.radiosInfo[i].reportInterval = CW_REPORT_INTERVAL_DEFAULT; /* Default value for CAPWA� */ gRadiosInfo.radiosInfo[i].adminState = ENABLED; gRadiosInfo.radiosInfo[i].adminCause = AD_NORMAL; gRadiosInfo.radiosInfo[i].operationalState = DISABLED; gRadiosInfo.radiosInfo[i].operationalCause = OP_NORMAL; gRadiosInfo.radiosInfo[i].TxQueueLevel = 0; gRadiosInfo.radiosInfo[i].wirelessLinkFramesPerSec = 0; CWWTPResetRadioStatistics(&(gRadiosInfo.radiosInfo[i].statistics)); if (!CWWTPInitBinding(i)) { return CW_FALSE; } } return CW_TRUE; } ================================================ FILE: WTPBcmDriverInteraction.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #include "WTPBcmDriverInteraction.h" static char interface[16] = "wl0"; static char wlbuf[WLC_IOCTL_MAXLEN]; #define BUFSIZE 8192 /*prototipi da includere in CWWTP.h*/ int set_rts_threshold(int value); int get_rts_threshold(int *value); int set_frag_threshold(int value); int get_frag_threshold(int *value); int set_maxassoc(int value); int get_maxassoc(int *value); /*--------------------------- RTS/CTS Threshold ---------------------------*/ int set_rts_threshold(int value) { char *iov_type; iov_type = malloc(20 * sizeof(char)); strcpy(iov_type, "rtsthresh"); if (wl_iovar_setint(interface, iov_type, value) < 0) { perror("Ioctl error"); return (0); } printf("\nRTS/CTS threshold impostato a: %d\n", value); return 1; } int get_rts_threshold(int *value) { char *iov_type; iov_type = malloc(20 * sizeof(char)); strcpy(iov_type, "rtsthresh"); if (wl_iovar_getint(interface, iov_type, value) < 0) { perror("Ioctl error"); return (0); } printf("\nRTS/CTS threshold: %d\n", *value); return 1; } /*--------------------------- Fragmentation Threshold ---------------------------*/ int set_frag_threshold(int value) { char *iov_type; iov_type = malloc(20 * sizeof(char)); strcpy(iov_type, "fragthresh"); if (wl_iovar_setint(interface, iov_type, value) < 0) { perror("Ioctl error"); return (0); } printf("\nFragmentation threshold impostato a: %d\n", value); return 1; } int get_frag_threshold(int *value) { char *iov_type; iov_type = malloc(20 * sizeof(char)); strcpy(iov_type, "fragthresh"); if (wl_iovar_getint(interface, iov_type, value) < 0) { perror("Ioctl error"); return (0); } printf("\nFragmentation threshold: %d\n", *value); return 1; } /*--------------------------- Max. number of associated clients ---------------------------*/ int set_maxassoc(int value) { char *iov_type; iov_type = malloc(20 * sizeof(char)); strcpy(iov_type, "maxassoc"); if (wl_iovar_setint(interface, iov_type, value) < 0) { perror("Ioctl error"); return (0); } printf("\nMax. number of associated clients impostato a: %d\n", value); return 1; } int get_maxassoc(int *value) { char *iov_type; iov_type = malloc(20 * sizeof(char)); strcpy(iov_type, "maxassoc"); if (wl_iovar_getint(interface, iov_type, value) < 0) { perror("Ioctl error"); return (0); } printf("\nMax. number of associated clients: %d\n", *value); return 1; } /*---------- WME Extensions: cwmin,cwmax,aifsn for BE,BK,VI,VO queues ---------------------*/ /*the Broadcom's driver doesn't support GET command for wme.*/ /*set CWMIN*/ int set_wme_cwmin(int class, int value) { edcf_acparam_t params[AC_COUNT]; char *buf = wlbuf; char *type; type = malloc(20 * sizeof(char)); strcpy(type, "wme_ac_ap"); memset(params, 0, sizeof(params)); wl_iovar_get(interface, type, params, sizeof(params)); strcpy(buf, type); buf += strlen(buf) + 1; params[class].ECW = (params[class].ECW & ~(0xf)) | (value & 0xf); memcpy(buf, ¶ms[class], sizeof(edcf_acparam_t)); if (wl_ioctl(interface, WLC_SET_VAR, wlbuf, BUFSIZE) < 0) { perror("Ioctl error"); return (0); } printf("\nCWMIN impostato a: %d\n", value); return 1; } /*set CWMAX*/ int set_wme_cwmax(int class, int value) { edcf_acparam_t params[AC_COUNT]; char *buf = wlbuf; char *type; type = malloc(20 * sizeof(char)); strcpy(type, "wme_ac_ap"); memset(params, 0, sizeof(params)); wl_iovar_get(interface, type, params, sizeof(params)); strcpy(buf, type); buf += strlen(buf) + 1; params[class].ECW = (params[class].ECW & ~(0xf << 4)) | ((value & 0xf) << 4); memcpy(buf, ¶ms[class], sizeof(edcf_acparam_t)); if (wl_ioctl(interface, WLC_SET_VAR, wlbuf, BUFSIZE) < 0) { perror("Ioctl error"); return (0); } printf("\nCWMAX impostato a: %d\n", value); return 1; } /*set AIFSN*/ int set_wme_aifsn(int class, int value) { edcf_acparam_t params[AC_COUNT]; char *buf = wlbuf; char *type; type = malloc(20 * sizeof(char)); strcpy(type, "wme_ac_ap"); memset(params, 0, sizeof(params)); wl_iovar_get(interface, type, params, sizeof(params)); strcpy(buf, type); buf += strlen(buf) + 1; params[class].ACI = (params[class].ACI & ~(0xf)) | (value & 0xf); memcpy(buf, ¶ms[class], sizeof(edcf_acparam_t)); if (wl_ioctl(interface, WLC_SET_VAR, wlbuf, BUFSIZE) < 0) { perror("Ioctl error"); return (0); } printf("\nAIFSN impostato a: %d\n", value); return 1; } /*@@@@@@@@ ioctl driver interaction's functions @@@@@@@@@@@@@*/ int wl_ioctl(char *name, int cmd, void *buf, int len) { struct ifreq ifr; wl_ioctl_t ioc; int ret = 0; int s; /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return errno; } /* do it */ ioc.cmd = cmd; ioc.buf = buf; ioc.len = len; strncpy(ifr.ifr_name, name, IFNAMSIZ); ifr.ifr_data = (caddr_t) & ioc; if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0) { perror("ioctl error"); close(s); return -1; } /* cleanup */ close(s); return ret; } static int wl_iovar_getbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) { int err; uint namelen; uint iolen; namelen = strlen(iovar) + 1; /* length of iovar name plus null */ iolen = namelen + paramlen; /* check for overflow */ if (iolen > buflen) return (BCME_BUFTOOSHORT); memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ memcpy((int8 *) bufptr + namelen, param, paramlen); err = wl_ioctl(ifname, WLC_GET_VAR, bufptr, buflen); return (err); } static int wl_iovar_setbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen) { uint namelen; uint iolen; namelen = strlen(iovar) + 1; /* length of iovar name plus null */ iolen = namelen + paramlen; /* check for overflow */ if (iolen > buflen) return (BCME_BUFTOOSHORT); memcpy(bufptr, iovar, namelen); /* copy iovar name including null */ memcpy((int8 *) bufptr + namelen, param, paramlen); return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen); } int wl_iovar_set(char *ifname, char *iovar, void *param, int paramlen) { char smbuf[WLC_IOCTL_SMLEN]; return wl_iovar_setbuf(ifname, iovar, param, paramlen, smbuf, sizeof(smbuf)); } int wl_iovar_get(char *ifname, char *iovar, void *bufptr, int buflen) { char smbuf[WLC_IOCTL_SMLEN]; int ret; /* use the return buffer if it is bigger than what we have on the stack */ if (buflen > sizeof(smbuf)) { ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, bufptr, buflen); } else { ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, smbuf, sizeof(smbuf)); if (ret == 0) memcpy(bufptr, smbuf, buflen); } return ret; } ================================================ FILE: WTPBcmDriverInteraction.h ================================================ #define __CAPWAP_WTPBroadcomDriverInteraction_HEADER__ /* check this magic number */ #define WLC_IOCTL_MAGIC 0x14e46c77 /* bump this number if you change the ioctl interface */ #define WLC_IOCTL_VERSION 1 #define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ #define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ /* common ioctl definitions */ #define WLC_GET_MAGIC 0 #define WLC_GET_VERSION 1 #define WLC_UP 2 #define WLC_DOWN 3 #define WLC_DUMP 6 #define WLC_GET_MSGLEVEL 7 #define WLC_SET_MSGLEVEL 8 #define WLC_GET_PROMISC 9 #define WLC_SET_PROMISC 10 #define WLC_GET_RATE 12 /* #define WLC_SET_RATE 13 *//* no longer supported */ #define WLC_GET_INSTANCE 14 /* #define WLC_GET_FRAG 15 *//* no longer supported */ /* #define WLC_SET_FRAG 16 *//* no longer supported */ /* #define WLC_GET_RTS 17 *//* no longer supported */ /* #define WLC_SET_RTS 18 *//* no longer supported */ #define WLC_GET_INFRA 19 #define WLC_SET_INFRA 20 #define WLC_GET_AUTH 21 #define WLC_SET_AUTH 22 #define WLC_GET_BSSID 23 #define WLC_SET_BSSID 24 #define WLC_GET_SSID 25 #define WLC_SET_SSID 26 #define WLC_RESTART 27 #define WLC_GET_CHANNEL 29 #define WLC_SET_CHANNEL 30 #define WLC_GET_SRL 31 #define WLC_SET_SRL 32 #define WLC_GET_LRL 33 #define WLC_SET_LRL 34 #define WLC_GET_PLCPHDR 35 #define WLC_SET_PLCPHDR 36 #define WLC_GET_RADIO 37 #define WLC_SET_RADIO 38 #define WLC_GET_PHYTYPE 39 /* #define WLC_GET_WEP 42 *//* no longer supported */ /* #define WLC_SET_WEP 43 *//* no longer supported */ #define WLC_GET_KEY 44 #define WLC_SET_KEY 45 #define WLC_GET_REGULATORY 46 #define WLC_SET_REGULATORY 47 #define WLC_GET_PASSIVE 48 #define WLC_SET_PASSIVE 49 #define WLC_SCAN 50 #define WLC_SCAN_RESULTS 51 #define WLC_DISASSOC 52 #define WLC_REASSOC 53 #define WLC_GET_ROAM_TRIGGER 54 #define WLC_SET_ROAM_TRIGGER 55 #define WLC_GET_TXANT 61 #define WLC_SET_TXANT 62 #define WLC_GET_ANTDIV 63 #define WLC_SET_ANTDIV 64 /* #define WLC_GET_TXPWR 65 *//* no longer supported */ /* #define WLC_SET_TXPWR 66 *//* no longer supported */ #define WLC_GET_CLOSED 67 #define WLC_SET_CLOSED 68 #define WLC_GET_MACLIST 69 #define WLC_SET_MACLIST 70 #define WLC_GET_RATESET 71 #define WLC_SET_RATESET 72 #define WLC_GET_LOCALE 73 #define WLC_LONGTRAIN 74 #define WLC_GET_BCNPRD 75 #define WLC_SET_BCNPRD 76 #define WLC_GET_DTIMPRD 77 #define WLC_SET_DTIMPRD 78 #define WLC_GET_SROM 79 #define WLC_SET_SROM 80 #define WLC_GET_WEP_RESTRICT 81 #define WLC_SET_WEP_RESTRICT 82 #define WLC_GET_COUNTRY 83 #define WLC_SET_COUNTRY 84 #define WLC_GET_PM 85 #define WLC_SET_PM 86 #define WLC_GET_WAKE 87 #define WLC_SET_WAKE 88 #define WLC_GET_D11CNTS 89 #define WLC_GET_FORCELINK 90 /* ndis only */ #define WLC_SET_FORCELINK 91 /* ndis only */ #define WLC_FREQ_ACCURACY 92 #define WLC_CARRIER_SUPPRESS 93 #define WLC_GET_PHYREG 94 #define WLC_SET_PHYREG 95 #define WLC_GET_RADIOREG 96 #define WLC_SET_RADIOREG 97 #define WLC_GET_REVINFO 98 #define WLC_GET_UCANTDIV 99 #define WLC_SET_UCANTDIV 100 #define WLC_R_REG 101 #define WLC_W_REG 102 #define WLC_DIAG_LOOPBACK 103 #define WLC_RESET_D11CNTS 104 #define WLC_GET_MACMODE 105 #define WLC_SET_MACMODE 106 #define WLC_GET_MONITOR 107 #define WLC_SET_MONITOR 108 #define WLC_GET_GMODE 109 #define WLC_SET_GMODE 110 #define WLC_GET_LEGACY_ERP 111 #define WLC_SET_LEGACY_ERP 112 #define WLC_GET_RX_ANT 113 #define WLC_GET_CURR_RATESET 114 /* current rateset */ #define WLC_GET_SCANSUPPRESS 115 #define WLC_SET_SCANSUPPRESS 116 #define WLC_GET_AP 117 #define WLC_SET_AP 118 #define WLC_GET_EAP_RESTRICT 119 #define WLC_SET_EAP_RESTRICT 120 #define WLC_SCB_AUTHORIZE 121 #define WLC_SCB_DEAUTHORIZE 122 #define WLC_GET_WDSLIST 123 #define WLC_SET_WDSLIST 124 #define WLC_GET_ATIM 125 #define WLC_SET_ATIM 126 #define WLC_GET_RSSI 127 #define WLC_GET_PHYANTDIV 128 #define WLC_SET_PHYANTDIV 129 #define WLC_AP_RX_ONLY 130 #define WLC_GET_TX_PATH_PWR 131 #define WLC_SET_TX_PATH_PWR 132 #define WLC_GET_WSEC 133 #define WLC_SET_WSEC 134 #define WLC_GET_PHY_NOISE 135 #define WLC_GET_BSS_INFO 136 #define WLC_GET_PKTCNTS 137 #define WLC_GET_LAZYWDS 138 #define WLC_SET_LAZYWDS 139 #define WLC_GET_BANDLIST 140 #define WLC_GET_BAND 141 #define WLC_SET_BAND 142 #define WLC_SCB_DEAUTHENTICATE 143 #define WLC_GET_SHORTSLOT 144 #define WLC_GET_SHORTSLOT_OVERRIDE 145 #define WLC_SET_SHORTSLOT_OVERRIDE 146 #define WLC_GET_SHORTSLOT_RESTRICT 147 #define WLC_SET_SHORTSLOT_RESTRICT 148 #define WLC_GET_GMODE_PROTECTION 149 #define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 #define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 #define WLC_UPGRADE 152 /* #define WLC_GET_MRATE 153 *//* no longer supported */ /* #define WLC_SET_MRATE 154 *//* no longer supported */ #define WLC_GET_ASSOCLIST 159 #define WLC_GET_CLK 160 #define WLC_SET_CLK 161 #define WLC_GET_UP 162 #define WLC_OUT 163 #define WLC_GET_WPA_AUTH 164 #define WLC_SET_WPA_AUTH 165 #define WLC_GET_PROTECTION_CONTROL 178 #define WLC_SET_PROTECTION_CONTROL 179 #define WLC_GET_PHYLIST 180 #define WLC_GET_KEY_SEQ 183 /* #define WLC_GET_GMODE_PROTECTION_CTS 198 *//* no longer supported */ /* #define WLC_SET_GMODE_PROTECTION_CTS 199 *//* no longer supported */ #define WLC_GET_PIOMODE 203 #define WLC_SET_PIOMODE 204 #define WLC_SET_LED 209 #define WLC_GET_LED 210 #define WLC_GET_CHANNEL_SEL 215 #define WLC_START_CHANNEL_SEL 216 #define WLC_GET_VALID_CHANNELS 217 #define WLC_GET_FAKEFRAG 218 #define WLC_SET_FAKEFRAG 219 #define WLC_GET_WET 230 #define WLC_SET_WET 231 #define WLC_GET_KEY_PRIMARY 235 #define WLC_SET_KEY_PRIMARY 236 #define WLC_GET_RADAR 242 #define WLC_SET_RADAR 243 #define WLC_SET_SPECT_MANAGMENT 244 #define WLC_GET_SPECT_MANAGMENT 245 #define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ #define WLC_SET_CS_SCAN_TIMER 248 #define WLC_GET_CS_SCAN_TIMER 249 #define WLC_SEND_PWR_CONSTRAINT 254 #define WLC_CURRENT_PWR 256 #define WLC_GET_CHANNELS_IN_COUNTRY 260 #define WLC_GET_COUNTRY_LIST 261 #define WLC_GET_VAR 262 /* get value of named variable */ #define WLC_SET_VAR 263 /* set named variable to value */ #define WLC_NVRAM_GET 264 /* deprecated */ #define WLC_NVRAM_SET 265 #define WLC_SET_WSEC_PMK 268 #define WLC_GET_AUTH_MODE 269 #define WLC_SET_AUTH_MODE 270 #define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ #define WLC_NVOTPW 274 #define WLC_OTPW 275 #define WLC_SET_LOCALE 278 #define WLC_LAST 279 /* do not change - use get_var/set_var */ /* ** driver/apps-shared section ** */ #define BCME_STRLEN 64 /* Max string length for BCM errors */ #define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) /* * error codes could be added but the defined ones shouldn't be changed/deleted * these error codes are exposed to the user code * when ever a new error code is added to this list * please update errorstring table with the related error string and * update osl files with os specific errorcode map */ #define BCME_OK 0 /* Success */ #define BCME_ERROR -1 /* Error generic */ #define BCME_BADARG -2 /* Bad Argument */ #define BCME_BADOPTION -3 /* Bad option */ #define BCME_NOTUP -4 /* Not up */ #define BCME_NOTDOWN -5 /* Not down */ #define BCME_NOTAP -6 /* Not AP */ #define BCME_NOTSTA -7 /* Not STA */ #define BCME_BADKEYIDX -8 /* BAD Key Index */ #define BCME_RADIOOFF -9 /* Radio Off */ #define BCME_NOTBANDLOCKED -10 /* Not band locked */ #define BCME_NOCLK -11 /* No Clock */ #define BCME_BADRATESET -12 /* BAD Rate valueset */ #define BCME_BADBAND -13 /* BAD Band */ #define BCME_BUFTOOSHORT -14 /* Buffer too short */ #define BCME_BUFTOOLONG -15 /* Buffer too long */ #define BCME_BUSY -16 /* Busy */ #define BCME_NOTASSOCIATED -17 /* Not Associated */ #define BCME_BADSSIDLEN -18 /* Bad SSID len */ #define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ #define BCME_BADCHAN -20 /* Bad Channel */ #define BCME_BADADDR -21 /* Bad Address */ #define BCME_NORESOURCE -22 /* Not Enough Resources */ #define BCME_UNSUPPORTED -23 /* Unsupported */ #define BCME_BADLEN -24 /* Bad length */ #define BCME_NOTREADY -25 /* Not Ready */ #define BCME_EPERM -26 /* Not Permitted */ #define BCME_NOMEM -27 /* No Memory */ #define BCME_ASSOCIATED -28 /* Associated */ #define BCME_RANGE -29 /* Not In Range */ #define BCME_NOTFOUND -30 /* Not Found */ #define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ #define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ #define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ #define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ #define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ #define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ #define BCME_LAST BCME_DONGLE_DOWN /* These are collection of BCME Error strings */ #define BCMERRSTRINGTABLE { \ "OK", \ "Undefined error", \ "Bad Argument", \ "Bad Option", \ "Not up", \ "Not down", \ "Not AP", \ "Not STA", \ "Bad Key Index", \ "Radio Off", \ "Not band locked", \ "No clock", \ "Bad Rate valueset", \ "Bad Band", \ "Buffer too short", \ "Buffer too long", \ "Busy", \ "Not Associated", \ "Bad SSID len", \ "Out of Range Channel", \ "Bad Channel", \ "Bad Address", \ "Not Enough Resources", \ "Unsupported", \ "Bad length", \ "Not Ready", \ "Not Permitted", \ "No Memory", \ "Associated", \ "Not In Range", \ "Not Found", \ "WME Not Enabled", \ "TSPEC Not Found", \ "ACM Not Supported", \ "Not WME Association", \ "SDIO Bus Error", \ "Dongle Not Accessible" \ } /* Types definition*/ /* * Inferred Typedefs * */ /* Infer the compile environment based on preprocessor symbols and pramas. * Override type definitions as needed, and include configuration dependent * header files to define types. */ #ifdef __cplusplus #define TYPEDEF_BOOL #ifndef FALSE #define FALSE false #endif #ifndef TRUE #define TRUE true #endif #endif /* __cplusplus */ #if defined(_NEED_SIZE_T_) typedef long unsigned int size_t; #endif #define TYPEDEF_UINT #define TYPEDEF_USHORT #define TYPEDEF_ULONG /* Do not support the (u)int64 types with strict ansi for GNU C */ #if defined(__GNUC__) && defined(__STRICT_ANSI__) #define TYPEDEF_INT64 #define TYPEDEF_UINT64 #endif /* pick up ushort & uint from standard types.h */ #if defined(linux) && defined(__KERNEL__) #include /* sys/types.h and linux/types.h are oil and water */ #else #include #endif /* use the default typedefs in the next section of this file */ #define USE_TYPEDEF_DEFAULTS /* * Default Typedefs * */ #ifdef USE_TYPEDEF_DEFAULTS #undef USE_TYPEDEF_DEFAULTS #ifndef TYPEDEF_BOOL typedef /* @abstract@ */ unsigned char bool; #endif /* define uchar, ushort, uint, ulong */ #ifndef TYPEDEF_UCHAR typedef unsigned char uchar; #endif #ifndef TYPEDEF_USHORT typedef unsigned short ushort; #endif #ifndef TYPEDEF_UINT typedef unsigned int uint; #endif #ifndef TYPEDEF_ULONG typedef unsigned long ulong; #endif /* define [u]int8/16/32/64, uintptr */ #ifndef TYPEDEF_UINT8 typedef unsigned char uint8; #endif #ifndef TYPEDEF_UINT16 typedef unsigned short uint16; #endif #ifndef TYPEDEF_UINT32 typedef unsigned int uint32; #endif #ifndef TYPEDEF_UINT64 typedef unsigned long long uint64; #endif #ifndef TYPEDEF_UINTPTR typedef unsigned int uintptr; #endif #ifndef TYPEDEF_INT8 typedef signed char int8; #endif #ifndef TYPEDEF_INT16 typedef signed short int16; #endif #ifndef TYPEDEF_INT32 typedef signed int int32; #endif #ifndef TYPEDEF_INT64 typedef signed long long int64; #endif /* define float32/64, float_t */ #ifndef TYPEDEF_FLOAT32 typedef float float32; #endif #ifndef TYPEDEF_FLOAT64 typedef double float64; #endif /* * abstracted floating point type allows for compile time selection of * single or double precision arithmetic. Compiling with -DFLOAT32 * selects single precision; the default is double precision. */ #ifndef TYPEDEF_FLOAT_T #if defined(FLOAT32) typedef float32 float_t; #else /* default to double precision floating point */ typedef float64 float_t; #endif #endif /* TYPEDEF_FLOAT_T */ /* define macro values */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 /* TRUE */ #endif #ifndef NULL #define NULL 0 #endif #ifndef OFF #define OFF 0 #endif #ifndef ON #define ON 1 /* ON = 1 */ #endif #define AUTO (-1) /* Auto = -1 */ /* define PTRSZ, INLINE */ #ifndef PTRSZ #define PTRSZ sizeof(char*) #endif #ifndef INLINE #ifdef _MSC_VER #define INLINE __inline #elif __GNUC__ #define INLINE __inline__ #else #define INLINE #endif /* _MSC_VER */ #endif /* INLINE */ #undef TYPEDEF_BOOL #undef TYPEDEF_UCHAR #undef TYPEDEF_USHORT #undef TYPEDEF_UINT #undef TYPEDEF_ULONG #undef TYPEDEF_UINT8 #undef TYPEDEF_UINT16 #undef TYPEDEF_UINT32 #undef TYPEDEF_UINT64 #undef TYPEDEF_UINTPTR #undef TYPEDEF_INT8 #undef TYPEDEF_INT16 #undef TYPEDEF_INT32 #undef TYPEDEF_INT64 #undef TYPEDEF_FLOAT32 #undef TYPEDEF_FLOAT64 #undef TYPEDEF_FLOAT_T /* WME Access Category Indices (ACIs) */ #define AC_BE 0 /* Best Effort */ #define AC_BK 1 /* Background */ #define AC_VI 2 /* Video */ #define AC_VO 3 /* Voice */ #define AC_COUNT 4 /* number of ACs */ struct edcf_acparam { uint8 ACI; uint8 ECW; uint16 TXOP; /* stored in network order (ls octet first) */ } PACKED; typedef struct edcf_acparam edcf_acparam_t; /* Linux network driver ioctl encoding */ typedef struct wl_ioctl { uint cmd; /* common ioctl definition */ void *buf; /* pointer to user buffer */ uint len; /* length of user buffer */ bool set; /* get or set request (optional) */ uint used; /* bytes read or written (optional) */ uint needed; /* bytes needed (optional) */ } wl_ioctl_t; /* * Pass a wlioctl request to the specified interface. * @param name interface name * @param cmd WLC_GET_MAGIC <= cmd < WLC_LAST * @param buf buffer for passing in and/or receiving data * @param len length of buf * @return >= 0 if successful or < 0 otherwise */ extern int wl_ioctl(char *name, int cmd, void *buf, int len); extern int wl_iovar_set(char *ifname, char *iovar, void *param, int paramlen); extern int wl_iovar_get(char *ifname, char *iovar, void *bufptr, int buflen); /* * Set/Get named variable. * @param ifname interface name * @param iovar variable name * @param param input param value/buffer * @param paramlen input param value/buffer length * @param bufptr io buffer * @param buflen io buffer length * @param val val or val pointer for int routines * @return success == 0, failure != 0 */ /* * set named driver variable to int value * calling example: wl_iovar_setint(ifname, "arate", rate) */ static inline int wl_iovar_setint(char *ifname, char *iovar, int val) { return wl_iovar_set(ifname, iovar, &val, sizeof(val)); } /* * get named driver variable to int value and return error indication * calling example: wl_iovar_getint(ifname, "arate", &rate) */ static inline int wl_iovar_getint(char *ifname, char *iovar, int *val) { return wl_iovar_get(ifname, iovar, val, sizeof(int)); } #endif ================================================ FILE: WTPBcmFrameReceive.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "WTPBcmFrameReceive.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif int extractFrame(CWProtocolMessage ** frame, unsigned char *buffer, int len) //len: frame length { CW_CREATE_OBJECT_ERR(*frame, CWProtocolMessage, return 0; ); CWProtocolMessage *auxPtr = *frame; CW_CREATE_PROTOCOL_MESSAGE(*auxPtr, len, return 0; ); memcpy(auxPtr->msg, buffer, len); auxPtr->offset = len; return 1; } int get_mac(u_char * buf) { struct ifreq ifr; int s; /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return errno; } strncpy(ifr.ifr_name, WL_DEVICE, IFNAMSIZ); //ifr.ifr_data = (caddr_t) buf; if ((ioctl(s, SIOCGIFHWADDR, &ifr)) < 0) { perror(ifr.ifr_name); close(s); return 0; } /* cleanup */ close(s); memcpy(buf, &(ifr.ifr_hwaddr.sa_data), MAC_ADDR_LEN); return 1; } int macAddrCmp(unsigned char *addr1, unsigned char *addr2) { int i, ok = 1; /* CWDebugLog("Address 1:"); for (i=0; ilen < sizeof(prism_hdr) + sizeof(ieee802_11_hdr)) return; hPrism = (prism_hdr *) packet; hWifi = (ieee802_11_hdr *) (packet + (hPrism->msg_length)); buffer = (unsigned char *)(packet + (hPrism->msg_length)); packet_len = hPrism->msg_length; if (!macAddrCmp(hWifi->addr1, wl0_mac_address)) return; //Parse the prism DIDs i = (prism_did *) ((char *)hPrism + sizeof(prism_hdr)); while ((int)i < (int)hWifi) { if (i->did == pdn_rssi) RSSI = *(char *)(i + 1); if (i->did == pdn_sq) SNR = *(char *)(i + 1); if (i->did == pdn_datarate) data_rate = (((*(int *)(i + 1)) / 2) * 10); i = (prism_did *) ((int)(i + 1) + i->length); } //Establish the frame type wfType = ((hWifi->frame_control & 0xF0) >> 4) + ((hWifi->frame_control & 0xC) << 2); switch (wfType) { case mgt_assocRequest: src = hWifi->addr2; dst = hWifi->addr1; printf("\nAssociation request received from: "); print_mac(src, "\n"); fflush(stdout); //CWDebugLog("\nRSSI: %d",RSSI); //CWDebugLog("\nSNR: %d",SNR); //CWDebugLog("\nData Rate: %d Mbs\n",data_rate); CW_CREATE_OBJECT_ERR(bindingValuesPtr, CWBindingTransportHeaderValues, EXIT_THREAD); bindingValuesPtr->RSSI = RSSI; bindingValuesPtr->SNR = SNR; bindingValuesPtr->dataRate = data_rate; CW_CREATE_OBJECT_ERR(listElement, CWBindingDataListElement, EXIT_THREAD); if (!extractFrame(&frame, buffer, packet_len - sizeof(prism_hdr))) { CWDebugLog("THR FRAME: Error extracting a frame"); EXIT_THREAD} listElement->frame = frame; listElement->bindingValues = bindingValuesPtr; CWLockSafeList(gFrameList); CWAddElementToSafeListTail(gFrameList, listElement, sizeof(CWBindingDataListElement)); CWUnlockSafeList(gFrameList); break; case mgt_assocResponse: break; case mgt_reassocRequest: break; case mgt_reassocResponse: break; case mgt_probeRequest: break; case mgt_probeResponse: break; case mgt_beacon: break; case mgt_disassoc: break; case mgt_auth: break; case mgt_deauth: break; } } ================================================ FILE: WTPBcmFrameReceive.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_WTPFrameReceive_HEADER__ #define __CAPWAP_WTPFrameReceive_HEADER__ #include #include #include #include #include #include #include "CWWTP.h" #define EXIT_THREAD CWLog("ERROR Handling Frames: application will be closed!"); \ exit(1); #define WL_DEVICE "wl0" #define MAC_ADDR_LEN 6 /* check this magic number */ #define WLC_IOCTL_MAGIC 0x14e46c77 #define WLC_GET_MAGIC 0 #define WLC_GET_BSSID 23 #define WLC_SET_BSSID 24 #define WLC_GET_SSID 25 #define WLC_SET_SSID 26 #define WLC_GET_CHANNEL 29 #define WLC_SET_CHANNEL 30 #define WLC_GET_MONITOR 107 /* discovered by nbd */ #define WLC_SET_MONITOR 108 /* discovered by nbd */ #define WLC_GET_AP 117 #define WLC_SET_AP 118 #define WLC_GET_RSSI 127 #define WLC_GET_ASSOCLIST 159 #ifdef DEFINE_TYPES typedef unsigned short u_short; typedef unsigned char u_char; typedef unsigned int u_int; #endif typedef enum { mgt_assocRequest = 0, mgt_assocResponse = 1, mgt_reassocRequest = 2, mgt_reassocResponse = 3, mgt_probeRequest = 4, mgt_probeResponse = 5, mgt_beacon = 8, mgt_disassoc = 10, mgt_auth = 11, mgt_deauth = 12 } wifi_frametype; typedef struct ieee802_11_hdr { u_char frame_control; u_char flags; #define IEEE80211_TO_DS 0x01 #define IEEE80211_FROM_DS 0x02 #define IEEE80211_MORE_FRAG 0x04 #define IEEE80211_RETRY 0x08 #define IEEE80211_PWR_MGT 0x10 #define IEEE80211_MORE_DATA 0x20 #define IEEE80211_WEP_FLAG 0x40 #define IEEE80211_ORDER_FLAG 0x80 u_short duration; u_char addr1[6]; u_char addr2[6]; u_char addr3[6]; u_short frag_and_seq; } ieee802_11_hdr; typedef struct { u_char timestamp[8]; u_short bcn_interval; u_short caps; #define MGT_CAPS_AP 0x1 #define MGT_CAPS_IBSS 0x2 #define MGT_CAPS_WEP 0x10 } ieee_802_11_mgt_frame; typedef struct prism_hdr { u_int msg_code; u_int msg_length; char cap_device[16]; } prism_hdr; typedef struct prism_did { u_short did; u_short status1; u_short status2; u_short length; } prism_did; typedef enum prism_did_num { pdn_host_time = 0x1041, pdn_mac_time = 0x2041, pdn_rssi = 0x4041, pdn_sq = 0x5041, pdn_datarate = 0x8041, pdn_framelen = 0xa041 } prism_did_num; void print_mac(u_char * mac, char *extra); void fprint_mac(FILE * outf, u_char * mac, char *extra); int macAddrCmp(unsigned char *addr1, unsigned char *addr2); int get_mac(u_char * buf); void dealWithPacket(struct pcap_pkthdr *header, const u_char * packet, u_char * wl0_mac_address); #endif ================================================ FILE: WTPBinding.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include "wireless_copy.h" #include "CWWTP.h" #include #include #include #include #include #include #include #include #include #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif int CWTranslateQueueIndex(int j) { if (j == VOICE_QUEUE_INDEX) return 3; if (j == VIDEO_QUEUE_INDEX) return 2; if (j == BACKGROUND_QUEUE_INDEX) return 1; return 0; } #ifdef SOFTMAC CWBool CWWTPInitBinding(int radioIndex) { bindingValues *aux; int i; CW_CREATE_OBJECT_ERR(aux, bindingValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); gRadiosInfo.radiosInfo[radioIndex].bindingValuesPtr = (void *)aux; CW_CREATE_ARRAY_ERR(aux->qosValues, NUM_QOS_PROFILES, WTPQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < NUM_QOS_PROFILES; i++) { /* TODO: Get info from Hostapd UNIX DOMAIN SOCKET */ aux->qosValues[i].cwMin = 3; aux->qosValues[i].cwMax = 15; aux->qosValues[i].AIFS = 2; } return CW_TRUE; } #else #ifndef BCM CWBool CWWTPInitBinding(int radioIndex) { bindingValues *aux; int i, sock; struct iwreq wrq; /*** Inizializzazione socket ***/ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { CWLog("Error Creating Socket for ioctl"); return CW_FALSE; } /*** Inizializzazione struttura iwreq ***/ memset(&wrq, 0, sizeof(wrq)); strncpy(wrq.ifr_name, gInterfaceName, IFNAMSIZ); CWLog("wrq.ifr_name %s ", wrq.ifr_name); CW_CREATE_OBJECT_ERR(aux, bindingValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); gRadiosInfo.radiosInfo[radioIndex].bindingValuesPtr = (void *)aux; CW_CREATE_ARRAY_ERR(aux->qosValues, NUM_QOS_PROFILES, WTPQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < NUM_QOS_PROFILES; i++) { /* * Donato Capitella - TO_REMOVE_DEVELOP * Commented the following lines just to make the WTP work in a test machine. */ //if(!get_cwmin(sock, &wrq, CWTranslateQueueIndex(i), 0)){return CW_FALSE;} //aux->qosValues[i].cwMin = wrq.u.param.value; //if(!get_cwmax(sock, &wrq, CWTranslateQueueIndex(i), 0)){return CW_FALSE;} //aux->qosValues[i].cwMax = wrq.u.param.value; //if(!get_aifs(sock, &wrq, CWTranslateQueueIndex(i), 0)){return CW_FALSE;} //aux->qosValues[i].AIFS = wrq.u.param.value; /*## aux->qosValues[i].cwMin = 2; aux->qosValues[i].cwMax = 4; aux->qosValues[i].AIFS = 3; */ } return CW_TRUE; } #else CWBool CWWTPInitBinding(int radioIndex) { bindingValues *aux; int i; CW_CREATE_OBJECT_ERR(aux, bindingValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); gRadiosInfo.radiosInfo[radioIndex].bindingValuesPtr = (void *)aux; CW_CREATE_ARRAY_ERR(aux->qosValues, NUM_QOS_PROFILES, WTPQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < NUM_QOS_PROFILES; i++) { /*Daniele: i driver Broadcom non permettono get sulle WME: setto i parametri del Qos a valori costanti */ aux->qosValues[i].cwMin = 2; aux->qosValues[i].cwMax = 4; aux->qosValues[i].AIFS = 3; } return CW_TRUE; } #endif #endif #ifdef SOFTMAC CWBool CWBindingSetQosValues(int qosCount, RadioQosValues * radioQosValues, CWProtocolResultCode * resultCode) { if (qosCount <= 0) { return CW_TRUE; } if (radioQosValues == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; int i, k, j; for (i = 0; i < qosCount; i++) { for (k = 0; k < gRadiosInfo.radioCount; k++) { if (radioQosValues[i].radioID == gRadiosInfo.radiosInfo[k].radioID) { bindingValues *auxPtr = (bindingValues *) gRadiosInfo.radiosInfo[k].bindingValuesPtr; for (j = 0; j < NUM_QOS_PROFILES; j++) { CWLog("AIFS: %d %d", auxPtr->qosValues[j].AIFS, radioQosValues[i].qosValues[j].AIFS); int aifs = (int)radioQosValues[i].qosValues[j].AIFS; int burst_time = 0; if (j == 0) burst_time = 15; else if (j == 1) burst_time = 30; if (set_txq (j, radioQosValues[i].qosValues[j].cwMin, radioQosValues[i].qosValues[j].cwMax, aifs, burst_time)) { auxPtr->qosValues[j].cwMin = radioQosValues[i].qosValues[j].cwMin; auxPtr->qosValues[j].cwMax = radioQosValues[i].qosValues[j].cwMax; auxPtr->qosValues[j].AIFS = radioQosValues[i].qosValues[j].AIFS; } else { *resultCode = CW_PROTOCOL_FAILURE; } /* if(auxPtr->qosValues[j].cwMin!=radioQosValues[i].qosValues[j].cwMin) { if (set_wme_cwmin(CWTranslateQueueIndex(j), radioQosValues[i].qosValues[j].cwMin)) {auxPtr->qosValues[j].cwMin=radioQosValues[i].qosValues[j].cwMin;} else {*resultCode=CW_PROTOCOL_FAILURE;} } if(auxPtr->qosValues[j].cwMax!=radioQosValues[i].qosValues[j].cwMax) { if (set_wme_cwmax(CWTranslateQueueIndex(j), radioQosValues[i].qosValues[j].cwMax)) {auxPtr->qosValues[j].cwMax=radioQosValues[i].qosValues[j].cwMax;} else {*resultCode=CW_PROTOCOL_FAILURE;} } if(auxPtr->qosValues[j].AIFS!=radioQosValues[i].qosValues[j].AIFS) { if (set_wme_aifsn(CWTranslateQueueIndex(j), radioQosValues[i].qosValues[j].AIFS)) {auxPtr->qosValues[j].AIFS=radioQosValues[i].qosValues[j].AIFS;} else {*resultCode=CW_PROTOCOL_FAILURE;} } */ } break; } } } return CW_TRUE; } #else #ifndef BCM CWBool CWBindingSetQosValues(int qosCount, RadioQosValues * radioQosValues, CWProtocolResultCode * resultCode) { struct iwreq wrq; int sock; if (qosCount <= 0) { return CW_TRUE; } if (radioQosValues == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; /*** Inizializzazione socket ***/ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { CWLog("Error Creating Socket for ioctl"); return CWErrorRaise(CW_ERROR_GENERAL, NULL);; } /*** Inizializzazione struttura iwreq ***/ memset(&wrq, 0, sizeof(wrq)); strncpy(wrq.ifr_name, gInterfaceName, IFNAMSIZ); int i, k, j; for (i = 0; i < qosCount; i++) { for (k = 0; k < gRadiosInfo.radioCount; k++) { if (radioQosValues[i].radioID == gRadiosInfo.radiosInfo[k].radioID) { bindingValues *auxPtr = (bindingValues *) gRadiosInfo.radiosInfo[k].bindingValuesPtr; for (j = 0; j < NUM_QOS_PROFILES; j++) { if (auxPtr->qosValues[j].cwMin != radioQosValues[i].qosValues[j].cwMin) { if (set_cwmin (sock, wrq, CWTranslateQueueIndex(j), 0, radioQosValues[i].qosValues[j].cwMin)) { auxPtr->qosValues[j].cwMin = radioQosValues[i].qosValues[j].cwMin; } else { *resultCode = CW_PROTOCOL_FAILURE; } } if (auxPtr->qosValues[j].cwMax != radioQosValues[i].qosValues[j].cwMax) { if (set_cwmax (sock, wrq, CWTranslateQueueIndex(j), 0, radioQosValues[i].qosValues[j].cwMax)) { auxPtr->qosValues[j].cwMax = radioQosValues[i].qosValues[j].cwMax; } else { *resultCode = CW_PROTOCOL_FAILURE; } } if (auxPtr->qosValues[j].AIFS != radioQosValues[i].qosValues[j].AIFS) { if (set_aifs (sock, wrq, CWTranslateQueueIndex(j), 0, radioQosValues[i].qosValues[j].AIFS)) { auxPtr->qosValues[j].AIFS = radioQosValues[i].qosValues[j].AIFS; } else { *resultCode = CW_PROTOCOL_FAILURE; } } } break; } } } //WTPQosValues* aux=radioQosValues; close(sock); return CW_TRUE; } #else CWBool CWBindingSetQosValues(int qosCount, RadioQosValues * radioQosValues, CWProtocolResultCode * resultCode) { if (qosCount <= 0) { return CW_TRUE; } if (radioQosValues == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; int i, k, j; for (i = 0; i < qosCount; i++) { for (k = 0; k < gRadiosInfo.radioCount; k++) { if (radioQosValues[i].radioID == gRadiosInfo.radiosInfo[k].radioID) { bindingValues *auxPtr = (bindingValues *) gRadiosInfo.radiosInfo[k].bindingValuesPtr; for (j = 0; j < NUM_QOS_PROFILES; j++) { if (auxPtr->qosValues[j].cwMin != radioQosValues[i].qosValues[j].cwMin) { if (set_wme_cwmin (CWTranslateQueueIndex(j), radioQosValues[i].qosValues[j].cwMin)) { auxPtr->qosValues[j].cwMin = radioQosValues[i].qosValues[j].cwMin; } else { *resultCode = CW_PROTOCOL_FAILURE; } } if (auxPtr->qosValues[j].cwMax != radioQosValues[i].qosValues[j].cwMax) { if (set_wme_cwmax (CWTranslateQueueIndex(j), radioQosValues[i].qosValues[j].cwMax)) { auxPtr->qosValues[j].cwMax = radioQosValues[i].qosValues[j].cwMax; } else { *resultCode = CW_PROTOCOL_FAILURE; } } if (auxPtr->qosValues[j].AIFS != radioQosValues[i].qosValues[j].AIFS) { if (set_wme_aifsn (CWTranslateQueueIndex(j), radioQosValues[i].qosValues[j].AIFS)) { auxPtr->qosValues[j].AIFS = radioQosValues[i].qosValues[j].AIFS; } else { *resultCode = CW_PROTOCOL_FAILURE; } } } break; } } } return CW_TRUE; } #endif #endif /************************************************************** * Update 2009: OFDM Message Element Management * **************************************************************/ CWBool CWManageOFDMValues(CWBindingConfigurationUpdateRequestValuesOFDM * ofdmValues, CWProtocolResultCode * resultCode) { if (ofdmValues == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; OFDMControlValues *radioValues = ofdmValues->radioOFDMValues; //unsigned char radioID = ofdmValues->radioID; struct sockaddr_in serv_addr; int sendSock, slen = sizeof(serv_addr); if ((sendSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { CWLog("[FreqAnalyzer]: Error on creation of socket."); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(FREQ_SERVER_PORT); if (inet_aton(FREQ_SERVER_ADDR, &serv_addr.sin_addr) == 0) { CWLog("[CWManageOFDMValue]: Error on aton function."); close(sendSock); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } /******************************************************************** * Update 2009: OFDM Management * * * * Send a OFDMControlValues to wtpFreqManager. * * In this function there is the control switch for the different * * type of commands. * ********************************************************************/ if (sendto(sendSock, radioValues, sizeof(OFDMControlValues), 0, (struct sockaddr *)&serv_addr, slen) < 0) { CWLog("[CWManageOFDMValue]: Error on sendto function."); close(sendSock); return CWErrorRaise(CW_ERROR_GENERAL, NULL); } close(sendSock); return CW_TRUE; } CWBool CWParseWTPOFDM(CWProtocolMessage * msgPtr, int len, unsigned char *radioID, OFDMControlValues * valPtr) { CWParseMessageElementStart(); *radioID = CWProtocolRetrieve8(msgPtr); valPtr->currentChan = CWProtocolRetrieve32(msgPtr); valPtr->BandSupport = (unsigned char)CWProtocolRetrieve8(msgPtr); valPtr->TIThreshold = (unsigned int)CWProtocolRetrieve32(msgPtr); CWParseMessageElementEnd(); } CWBool CWParseWTPQoS(CWProtocolMessage * msgPtr, int len, unsigned char *radioID, unsigned char *tagPackets, WTPQosValues * valPtr) { int i; CWParseMessageElementStart(); *radioID = CWProtocolRetrieve8(msgPtr); *tagPackets = CWProtocolRetrieve8(msgPtr); for (i = 0; i < NUM_QOS_PROFILES; i++) { valPtr[i].queueDepth = (unsigned char)CWProtocolRetrieve8(msgPtr); valPtr[i].cwMin = CWProtocolRetrieve16(msgPtr); valPtr[i].cwMax = CWProtocolRetrieve16(msgPtr); valPtr[i].AIFS = (unsigned char)CWProtocolRetrieve8(msgPtr); valPtr[i].dot1PTag = (unsigned char)CWProtocolRetrieve8(msgPtr); valPtr[i].DSCPTag = (unsigned char)CWProtocolRetrieve8(msgPtr); } CWParseMessageElementEnd(); } CWBool CWBindingSaveConfigurationUpdateRequest(void *bindingValuesPtr, CWProtocolResultCode * resultCode, int *updateRequestType) { if (bindingValuesPtr == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; switch (*updateRequestType) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS:{ CWBindingConfigurationUpdateRequestValues *bindingPtr = (CWBindingConfigurationUpdateRequestValues *) bindingValuesPtr; if (bindingPtr->qosCount > 0) { if (!CWBindingSetQosValues (bindingPtr->qosCount, bindingPtr->radioQosValues, resultCode)) { CW_FREE_OBJECT(bindingPtr->radioQosValues); CW_FREE_OBJECT(bindingPtr); return CW_FALSE; } CW_FREE_OBJECT(bindingPtr->radioQosValues); CW_FREE_OBJECT(bindingPtr); } return CW_TRUE; break; } case BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL:{ CWBindingConfigurationUpdateRequestValuesOFDM *bindingPtr = (CWBindingConfigurationUpdateRequestValuesOFDM *) bindingValuesPtr; if (!CWManageOFDMValues(bindingPtr, resultCode)) { CW_FREE_OBJECT(bindingPtr->radioOFDMValues); CW_FREE_OBJECT(bindingPtr); return CW_FALSE; } return CW_TRUE; break; } } return CW_TRUE; } CWBool CWBindingParseConfigurationUpdateRequest(unsigned char *msg, int len, void **valuesPtr) { int i; CWProtocolMessage completeMsg; unsigned short int GlobalElemType = 0; // = CWProtocolRetrieve32(&completeMsg); int qosCount = 0; if (msg == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing Binding Configuration Update Request..."); completeMsg.msg = msg; completeMsg.offset = 0; CWBindingConfigurationUpdateRequestValues *auxBindingPtr; CWBindingConfigurationUpdateRequestValuesOFDM *ofdmBindingPtr; CW_CREATE_OBJECT_ERR(auxBindingPtr, CWBindingConfigurationUpdateRequestValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_OBJECT_ERR(ofdmBindingPtr, CWBindingConfigurationUpdateRequestValuesOFDM, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // parse message elements while (completeMsg.offset < len) { unsigned short int elemType = 0; // = CWProtocolRetrieve32(&completeMsg); unsigned short int elemLen = 0; // = CWProtocolRetrieve16(&completeMsg); CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); GlobalElemType = elemType; //CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); switch (elemType) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS: qosCount++; //(auxBindingPtr->qosCount)++; // just count completeMsg.offset += elemLen; break; case BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL: completeMsg.offset += elemLen; break; default: if (CWBindingCheckType(elemType)) { CW_FREE_OBJECT(valuesPtr); CW_FREE_OBJECT(auxBindingPtr); CW_FREE_OBJECT(ofdmBindingPtr); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } else { completeMsg.offset += elemLen; break; } } } if (completeMsg.offset != len){ CW_FREE_OBJECT(auxBindingPtr); CW_FREE_OBJECT(ofdmBindingPtr); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); } switch (GlobalElemType) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS:{ CW_FREE_OBJECT(ofdmBindingPtr); *valuesPtr = (void *)auxBindingPtr; auxBindingPtr->qosCount = qosCount; auxBindingPtr->radioQosValues = NULL; CW_CREATE_ARRAY_ERR(auxBindingPtr->radioQosValues, auxBindingPtr->qosCount, RadioQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); break; } case BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL: CW_FREE_OBJECT(auxBindingPtr); *valuesPtr = (void *)ofdmBindingPtr; CW_CREATE_OBJECT_ERR(ofdmBindingPtr->radioOFDMValues, OFDMControlValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT,"Message elemet type unrecognized"); } i = 0; completeMsg.offset = 0; while (completeMsg.offset < len) { unsigned short int type = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(&completeMsg, &type, &elemLen); switch (type) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS:{ unsigned char tagPackets; if (! (CWParseWTPQoS (&completeMsg, elemLen, &(auxBindingPtr->radioQosValues[i].radioID), &tagPackets, auxBindingPtr->radioQosValues[i].qosValues))) { CW_FREE_OBJECT(auxBindingPtr->radioQosValues); CW_FREE_OBJECT(valuesPtr); return CW_FALSE; // will be handled by the caller } i++; break; } case BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL:{ /* 2009: New case */ if (! (CWParseWTPOFDM (&completeMsg, elemLen, &(ofdmBindingPtr->radioID), ofdmBindingPtr->radioOFDMValues))) { CW_FREE_OBJECT(ofdmBindingPtr->radioOFDMValues); CW_FREE_OBJECT(valuesPtr); return CW_FALSE; // will be handled by the caller } break; } default: completeMsg.offset += elemLen; break; } } CWLog("Binding Configure Update Request Parsed"); return CW_TRUE; } CWBool CWBindingSaveConfigureResponse(void *bindingValuesPtr, CWProtocolResultCode * resultCode) { if (bindingValuesPtr == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; CWBindingConfigurationRequestValues *bindingPtr = (CWBindingConfigurationRequestValues *) bindingValuesPtr; if (bindingPtr->qosCount > 0) { if (!CWBindingSetQosValues(bindingPtr->qosCount, bindingPtr->radioQosValues, resultCode)) { CW_FREE_OBJECT(bindingPtr->radioQosValues); return CW_FALSE; } CW_FREE_OBJECT(bindingPtr->radioQosValues); } return CW_TRUE; } CWBool CWBindingParseConfigureResponse(unsigned char *msg, int len, void **valuesPtr) { int i; CWProtocolMessage completeMsg; if (msg == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing Binding Configuration Request..."); completeMsg.msg = msg; completeMsg.offset = 0; CWBindingConfigurationRequestValues *auxBindingPtr; CW_CREATE_OBJECT_ERR(auxBindingPtr, CWBindingConfigurationRequestValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *valuesPtr = (void *)auxBindingPtr; auxBindingPtr->qosCount = 0; auxBindingPtr->radioQosValues = NULL; // parse message elements while (completeMsg.offset < len) { unsigned short int elemType = 0; // = CWProtocolRetrieve32(&completeMsg); unsigned short int elemLen = 0; // = CWProtocolRetrieve16(&completeMsg); CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); CWDebugLog("Parsing Message Element: %d, elemLen: %d", elemType, elemLen); switch (elemType) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS: (auxBindingPtr->qosCount)++; // just count completeMsg.offset += elemLen; break; default: if (CWBindingCheckType(elemType)) { CW_FREE_OBJECT(valuesPtr); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } else { completeMsg.offset += elemLen; break; } } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); // actually read each radio info CW_CREATE_ARRAY_ERR(auxBindingPtr->radioQosValues, auxBindingPtr->qosCount, RadioQosValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); i = 0; completeMsg.offset = 0; while (completeMsg.offset < len) { unsigned short int type = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(&completeMsg, &type, &elemLen); switch (type) { case BINDING_MSG_ELEMENT_TYPE_WTP_QOS:{ unsigned char tagPackets; if (! (CWParseWTPQoS (&completeMsg, elemLen, &(auxBindingPtr->radioQosValues[i].radioID), &tagPackets, auxBindingPtr->radioQosValues[i].qosValues))) { CW_FREE_OBJECT(auxBindingPtr->radioQosValues); CW_FREE_OBJECT(valuesPtr); return CW_FALSE; // will be handled by the caller } i++; break; } default: completeMsg.offset += elemLen; break; } } CWLog("Binding Configuration Request Parsed"); return CW_TRUE; } ================================================ FILE: WTPBinding.h ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #ifndef __CAPWAP_WTPBinding_HEADER__ #define __CAPWAP_WTPBinding_HEADER__ typedef struct { unsigned char radioID; WTPQosValues qosValues[NUM_QOS_PROFILES]; } RadioQosValues; typedef struct { int qosCount; RadioQosValues *radioQosValues; } CWBindingConfigurationRequestValues; typedef struct { int qosCount; RadioQosValues *radioQosValues; } CWBindingConfigurationUpdateRequestValues; /**************************************************** * 2009 Updates: * * New Structure for mananagement of * * OFDM Message Element * ****************************************************/ typedef struct { unsigned char radioID; OFDMControlValues *radioOFDMValues; } CWBindingConfigurationUpdateRequestValuesOFDM; /**************************************************** * 2009 Updates: * * Definition of port number and type * * of commands of Frequency Server * * Manager (WTP side). * ****************************************************/ #define FREQ_SERVER_ADDR "127.0.0.1" #define FREQ_SERVER_PORT 1236 CWBool CWWTPInitBinding(int radioIndex); CWBool CWBindingSaveConfigureResponse(void *bindingValuesPtr, CWProtocolResultCode * resultCode); CWBool CWBindingSetQosValues(int qosCount, RadioQosValues * radioQosValues, CWProtocolResultCode * resultCode); CWBool CWBindingParseConfigurationUpdateRequest(unsigned char *msg, int len, void **valuesPtr); CWBool CWBindingParseConfigureResponse(unsigned char *msg, int len, void **valuesPtr); /**************************************************** * 2009 Updates: (SaveConfiguration) * * Prototype Modification (int * added)* ****************************************************/ CWBool CWBindingSaveConfigurationUpdateRequest(void *bindingValuesPtr, CWProtocolResultCode * resultCode, int *updateRequestType); #endif ================================================ FILE: WTPConfigFile.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif const char *CW_CONFIG_FILE = "config.wtp"; CWBool CWConfigFileInitLib() { gConfigValuesCount = 9; CW_CREATE_ARRAY_ERR(gConfigValues, gConfigValuesCount, CWConfigValue, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); gConfigValues[0].type = CW_STRING_ARRAY; gConfigValues[0].code = ""; gConfigValues[0].endCode = ""; gConfigValues[0].value.str_array_value = NULL; gConfigValues[0].count = 0; gConfigValues[1].type = CW_INTEGER; gConfigValues[1].code = ""; gConfigValues[1].value.int_value = 0; gConfigValues[2].type = CW_STRING; gConfigValues[2].code = ""; gConfigValues[2].value.str_value = NULL; gConfigValues[3].type = CW_STRING; gConfigValues[3].code = ""; gConfigValues[3].value.str_value = NULL; gConfigValues[4].type = CW_STRING; gConfigValues[4].code = ""; gConfigValues[4].value.str_value = NULL; gConfigValues[5].type = CW_STRING; gConfigValues[5].code = ""; gConfigValues[5].value.str_value = NULL; gConfigValues[6].type = CW_STRING; gConfigValues[6].code = ""; gConfigValues[6].value.str_value = NULL; gConfigValues[7].type = CW_INTEGER; gConfigValues[7].code = ""; gConfigValues[7].value.int_value = 0; gConfigValues[8].type = CW_INTEGER; gConfigValues[8].code = ""; gConfigValues[8].value.int_value = DEFAULT_LOG_SIZE; return CW_TRUE; } CWBool CWConfigFileDestroyLib() { int i; // save the preferences we read CW_CREATE_ARRAY_ERR(gCWACAddresses, gConfigValues[0].count, char *, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < gConfigValues[0].count; i++) { CW_CREATE_STRING_FROM_STRING_ERR(gCWACAddresses[i], (gConfigValues[0].value.str_array_value)[i], return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } gCWACCount = gConfigValues[0].count; #ifdef CW_DEBUGGING CW_PRINT_STRING_ARRAY(gCWACAddresses, gCWACCount); #endif gCWForceMTU = gConfigValues[1].value.int_value; if (gConfigValues[2].value.str_value != NULL && !strcmp(gConfigValues[2].value.str_value, "IPv6")) { gNetworkPreferredFamily = CW_IPv6; } else { // default gNetworkPreferredFamily = CW_IPv4; } if (gConfigValues[3].value.str_value != NULL) { CW_CREATE_STRING_FROM_STRING_ERR(gWTPName, (gConfigValues[3].value.str_value), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } if (gConfigValues[4].value.str_value != NULL) { CW_CREATE_STRING_FROM_STRING_ERR(gWTPLocation, (gConfigValues[4].value.str_value), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } if (gConfigValues[5].value.str_value != NULL) { CW_CREATE_STRING_FROM_STRING_ERR(gWTPForceACAddress, (gConfigValues[5].value.str_value), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } if (gConfigValues[6].value.str_value != NULL && !strcmp(gConfigValues[6].value.str_value, "PRESHARED")) { gWTPForceSecurity = CW_PRESHARED; } else { // default gWTPForceSecurity = CW_X509_CERTIFICATE; } for (i = 0; i < gConfigValuesCount; i++) { if (gConfigValues[i].type == CW_STRING) { CW_FREE_OBJECT(gConfigValues[i].value.str_value); } else if (gConfigValues[i].type == CW_STRING_ARRAY) { CW_FREE_OBJECTS_ARRAY((gConfigValues[i].value.str_array_value), gConfigValues[i].count); } } gEnabledLog = gConfigValues[7].value.int_value; gMaxLogFileSize = gConfigValues[8].value.int_value; CW_FREE_OBJECT(gConfigValues); return CW_TRUE; } ================================================ FILE: WTPConfigureState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /* void CWWTPResponseTimerExpired(void *arg, CWTimerID id); */ CWBool CWAssembleConfigureRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CWBool CWParseConfigureResponseMessage(unsigned char *msg, int len, int seqNum, CWProtocolConfigureResponseValues * valuesPtr); CWBool CWSaveConfigureResponseMessage(CWProtocolConfigureResponseValues * configureResponse); /*_________________________________________________________*/ /* *******************___FUNCTIONS___******************* */ /* * Manage Configure State. */ CWStateTransition CWWTPEnterConfigure() { int seqNum; CWProtocolConfigureResponseValues values; CWLog("\n"); CWLog("######### Configure State #########"); /* send Configure Request */ seqNum = CWGetSeqNum(); if (!CWErr(CWWTPSendAcknowledgedPacket(seqNum, NULL, CWAssembleConfigureRequest, (void *)CWParseConfigureResponseMessage, (void *)CWSaveConfigureResponseMessage, &values))) { CWNetworkCloseSocket(gWTPSocket); #ifndef CW_NO_DTLS CWSecurityDestroySession(gWTPSession); CWSecurityDestroyContext(gWTPSecurityContext); gWTPSecurityContext = NULL; gWTPSession = NULL; #endif return CW_QUIT; } return CW_ENTER_DATA_CHECK; } /* void CWWTPResponseTimerExpired(void *arg, CWTimerID id) { CWLog("WTP Response Configure Timer Expired"); CWNetworkCloseSocket(gWTPSocket); } */ /* * Send Configure Request on the active session. */ CWBool CWAssembleConfigureRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemCount = 8; const int msgElemBindingCount = 0; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWDebugLog("Assembling Configure Request..."); /* Assemble Message Elements */ if ((!(CWAssembleMsgElemACName(&(msgElems[++k])))) || (!(CWAssembleMsgElemACNameWithIndex(&(msgElems[++k])))) || (!(CWAssembleMsgElemRadioAdminState(&(msgElems[++k])))) || (!(CWAssembleMsgElemStatisticsTimer(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPRebootStatistics(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPRadioInformation(&(msgElems[++k])))) || (!(CWAssembleMsgElemSupportedRates(&(msgElems[++k])))) || (!(CWAssembleMsgElemMultiDomainCapability(&(msgElems[++k]))))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CONFIGURE_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWDebugLog("Configure Request Assembled"); return CW_TRUE; } CWBool CWParseConfigureResponseMessage(unsigned char *msg, int len, int seqNum, CWProtocolConfigureResponseValues * valuesPtr) { CWControlHeaderValues controlVal; CWProtocolMessage completeMsg; CWBool bindingMsgElemFound = CW_FALSE; int offsetTillMessages; int i = 0; int j = 0; if (msg == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parsing Configure Response..."); completeMsg.msg = msg; completeMsg.offset = 0; valuesPtr->echoRequestTimer = 0; valuesPtr->radioOperationalInfoCount = 0; valuesPtr->radiosDecryptErrorPeriod.radiosCount = 0; valuesPtr->bindingValues = NULL; valuesPtr->ACIPv4ListInfo.ACIPv4ListCount = 0; valuesPtr->ACIPv4ListInfo.ACIPv4List = NULL; valuesPtr->ACIPv6ListInfo.ACIPv6ListCount = 0; valuesPtr->ACIPv6ListInfo.ACIPv6List = NULL; /* error will be handled by the caller */ if (!(CWParseControlHeader(&completeMsg, &controlVal))) return CW_FALSE; /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_CONFIGURE_RESPONSE) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Configure Response as Expected"); if (controlVal.seqNum != seqNum) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Different Sequence Number"); /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &type, &len); /* CWDebugLog("Parsing Message Element: %u, len: %u", type, len); */ if (CWBindingCheckType(type)) { bindingMsgElemFound = CW_TRUE; completeMsg.offset += len; continue; } switch (type) { case CW_MSG_ELEMENT_AC_IPV4_LIST_CW_TYPE: if (!(CWParseACIPv4List(&completeMsg, len, &(valuesPtr->ACIPv4ListInfo)))) return CW_FALSE; break; case CW_MSG_ELEMENT_AC_IPV6_LIST_CW_TYPE: if (!(CWParseACIPv6List(&completeMsg, len, &(valuesPtr->ACIPv6ListInfo)))) return CW_FALSE; break; case CW_MSG_ELEMENT_CW_TIMERS_CW_TYPE: if (!(CWParseCWTimers(&completeMsg, len, valuesPtr))) return CW_FALSE; break; case CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE: /* * just count how many radios we have, so we * can allocate the array */ valuesPtr->radioOperationalInfoCount++; completeMsg.offset += len; break; case CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_PERIOD_CW_TYPE: valuesPtr->radiosDecryptErrorPeriod.radiosCount++; completeMsg.offset += len; break; case CW_MSG_ELEMENT_IDLE_TIMEOUT_CW_TYPE: if (!(CWParseIdleTimeout(&completeMsg, len, valuesPtr))) return CW_FALSE; break; case CW_MSG_ELEMENT_WTP_FALLBACK_CW_TYPE: if (!(CWParseWTPFallback(&completeMsg, len, valuesPtr))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CW_CREATE_ARRAY_ERR((*valuesPtr).radioOperationalInfo, (*valuesPtr).radioOperationalInfoCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_ARRAY_ERR((*valuesPtr).radiosDecryptErrorPeriod.radios, (*valuesPtr).radiosDecryptErrorPeriod.radiosCount, WTPDecryptErrorReportValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); completeMsg.offset = offsetTillMessages; while (completeMsg.offset - offsetTillMessages < controlVal.msgElemsLen) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &type, &len); switch (type) { case CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE: /* will be handled by the caller */ if (!(CWParseWTPRadioOperationalState(&completeMsg, len, &(valuesPtr->radioOperationalInfo[i])))) return CW_FALSE; i++; break; case CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_PERIOD_CW_TYPE: if (!(CWParseDecryptErrorReportPeriod(&completeMsg, len, &(valuesPtr->radiosDecryptErrorPeriod.radios[j])))) return CW_FALSE; j++; break; default: completeMsg.offset += len; break; } } if (bindingMsgElemFound) { if (!CWBindingParseConfigureResponse(msg + offsetTillMessages, len - offsetTillMessages, &(valuesPtr->bindingValues))) { return CW_FALSE; } } CWDebugLog("Configure Response Parsed"); return CW_TRUE; } CWBool CWSaveConfigureResponseMessage(CWProtocolConfigureResponseValues * configureResponse) { if (configureResponse == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (gACInfoPtr == NULL) return CWErrorRaise(CW_ERROR_NEED_RESOURCE, NULL); CWDebugLog("Saving Configure Response..."); CWDebugLog("###A"); CWDebugLog("###Count:%d", (configureResponse->ACIPv4ListInfo).ACIPv4ListCount); if ((gACInfoPtr->ACIPv4ListInfo).ACIPv4List == NULL) { CWDebugLog("###NULL"); } if ((configureResponse->ACIPv4ListInfo).ACIPv4ListCount > 0) { //CW_FREE_OBJECT((gACInfoPtr->ACIPv4ListInfo).ACIPv4List); (gACInfoPtr->ACIPv4ListInfo).ACIPv4ListCount = (configureResponse->ACIPv4ListInfo).ACIPv4ListCount; (gACInfoPtr->ACIPv4ListInfo).ACIPv4List = (configureResponse->ACIPv4ListInfo).ACIPv4List; } CWDebugLog("###B"); if ((configureResponse->ACIPv6ListInfo).ACIPv6ListCount > 0) { //CW_FREE_OBJECT((gACInfoPtr->ACIPv6ListInfo).ACIPv6List); (gACInfoPtr->ACIPv6ListInfo).ACIPv6ListCount = (configureResponse->ACIPv6ListInfo).ACIPv6ListCount; (gACInfoPtr->ACIPv6ListInfo).ACIPv6List = (configureResponse->ACIPv6ListInfo).ACIPv6List; } if (configureResponse->bindingValues != NULL) { CWProtocolResultCode resultCode; if (!CWBindingSaveConfigureResponse(configureResponse->bindingValues, &resultCode)) { CW_FREE_OBJECT(configureResponse->bindingValues); return CW_FALSE; } } if (configureResponse->echoRequestTimer > 0) { gEchoInterval = configureResponse->echoRequestTimer; } /* ""need to be added"" int discoveryTimer; int radioOperationalInfoCount; CWRadioOperationalInfoValues *radioOperationalInfo; WTPDecryptErrorReport radiosDecryptErrorPeriod; int idleTimeout; int fallback; */ /* * It is not clear to me what the original developers intended to * accomplish. One thing's for sure: radioOperationalInfo, radiosDecryptErrorPeriod.radios, * and bidingValues get allocated and are never freed, * so we do it here... * * BUGs ML02-ML04-ML05 * 16/10/2009 - Donato Capitella */ //CW_FREE_OBJECT(configureResponse->radioOperationalInfo); //CW_FREE_OBJECT(configureResponse->radiosDecryptErrorPeriod.radios); //CW_FREE_OBJECT(configureResponse->bindingValues); CWDebugLog("Configure Response Saved"); return CW_TRUE; } ================================================ FILE: WTPDataCheckState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWAssembleChangeStateEventRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CWBool CWParseChangeStateEventResponseMessage(unsigned char *msg, int len, int seqNum, void *values); CWBool CWSaveChangeStateEventResponseMessage(void *changeStateEventResp); CWStateTransition CWWTPEnterDataCheck() { int seqNum; CWLog("\n"); CWLog("######### Data Check State #########"); CWLog("\n"); CWLog("#________ Change State Event (Data Check) ________#"); /* Send Change State Event Request */ seqNum = CWGetSeqNum(); if (!CWErr(CWStartHeartbeatTimer())) { return CW_ENTER_RESET; } if (!CWErr(CWWTPSendAcknowledgedPacket(seqNum, NULL, CWAssembleChangeStateEventRequest, CWParseChangeStateEventResponseMessage, CWSaveChangeStateEventResponseMessage, NULL))) { return CW_ENTER_RESET; } if (!CWErr(CWStopHeartbeatTimer())) { return CW_ENTER_RESET; } return CW_ENTER_RUN; } CWBool CWAssembleChangeStateEventRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemCount = 2; int msgElemBindingCount = 0; int resultCode = CW_PROTOCOL_SUCCESS; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWLog("Assembling Change State Event Request..."); /* Assemble Message Elements */ if (!(CWAssembleMsgElemRadioOperationalState(-1, &(msgElems[++k]))) || !(CWAssembleMsgElemResultCode(&(msgElems[++k]), resultCode))) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Change State Event Request Assembled"); return CW_TRUE; } CWBool CWParseChangeStateEventResponseMessage(unsigned char *msg, int len, int seqNum, void *values) { CWControlHeaderValues controlVal; CWProtocolMessage completeMsg; if (msg == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing Change State Event Response..."); completeMsg.msg = msg; completeMsg.offset = 0; /* error will be handled by the caller */ if (!(CWParseControlHeader(&completeMsg, &controlVal))) return CW_FALSE; if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_RESPONSE) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Change State Event Response as Expected"); if (controlVal.seqNum != seqNum) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Different Sequence Number"); /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; if (controlVal.msgElemsLen != 0) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Change State Event Response must carry no message elements"); CWLog("Change State Event Response Parsed"); return CW_TRUE; } CWBool CWSaveChangeStateEventResponseMessage(void *changeStateEventResp) { CWDebugLog("Saving Change State Event Response..."); CWDebugLog("Change State Event Response Saved"); return CW_TRUE; } ================================================ FILE: WTPDiscoveryState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /*________________________________________________________________*/ /* *******************___CAPWAP VARIABLES___******************* */ int gCWMaxDiscoveries = 10; /*_________________________________________________________*/ /* *******************___VARIABLES___******************* */ int gCWDiscoveryCount; #ifdef CW_DEBUGGING int gCWDiscoveryInterval = 3; //5; int gCWMaxDiscoveryInterval = 4; //20; #else int gCWDiscoveryInterval = 5; int gCWMaxDiscoveryInterval = 20; #endif /*_____________________________________________________*/ /* *******************___MACRO___******************* */ #define CWWTPFoundAnAC() (gACInfoPtr != NULL /*&& gACInfoPtr->preferredAddress.ss_family != AF_UNSPEC*/) /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ CWBool CWReceiveDiscoveryResponse(); void CWWTPEvaluateAC(CWACInfoValues * ACInfoPtr); CWBool CWReadResponses(); CWBool CWAssembleDiscoveryRequest(CWProtocolMessage ** messagesPtr, int seqNum); CWBool CWParseDiscoveryResponseMessage(unsigned char *msg, int len, int *seqNumPtr, CWACInfoValues * ACInfoPtr); /*_________________________________________________________*/ /* *******************___FUNCTIONS___******************* */ /* * Manage Discovery State */ CWStateTransition CWWTPEnterDiscovery() { int i; CWLog("\n"); CWLog("######### Discovery State #########"); /* reset Discovery state */ gCWDiscoveryCount = 0; CWNetworkCloseSocket(gWTPSocket); if (!CWErr(CWNetworkInitSocketClient(&gWTPSocket, NULL))) { return CW_QUIT; } /* * note: gCWACList can be freed and reallocated (reading from config file) * at each transition to the discovery state to save memory space */ for (i = 0; i < gCWACCount; i++) gCWACList[i].received = CW_FALSE; /* wait a random time */ sleep(CWRandomIntInRange(gCWDiscoveryInterval, gCWMaxDiscoveryInterval)); CW_REPEAT_FOREVER { CWBool sentSomething = CW_FALSE; /* we get no responses for a very long time */ if (gCWDiscoveryCount == gCWMaxDiscoveries) return CW_ENTER_SULKING; /* send Requests to one or more ACs */ for (i = 0; i < gCWACCount; i++) { /* if this AC hasn't responded to us... */ if (!(gCWACList[i].received)) { /* ...send a Discovery Request */ CWProtocolMessage *msgPtr = NULL; /* get sequence number (and increase it) */ gCWACList[i].seqNum = CWGetSeqNum(); if (!CWErr(CWAssembleDiscoveryRequest(&msgPtr, gCWACList[i].seqNum))) { exit(1); } CW_CREATE_OBJECT_ERR(gACInfoPtr, CWACInfoValues, return CW_QUIT; ); CWNetworkGetAddressForHost(gCWACList[i].address, &(gACInfoPtr->preferredAddress)); CWUseSockNtop(&(gACInfoPtr->preferredAddress), CWDebugLog(str); ); //j = CWErr(CWNetworkSendUnsafeUnconnected(gWTPSocket, // &(gACInfoPtr->preferredAddress), // (*msgPtr).msg, (*msgPtr).offset)); /* * log eventual error and continue * CWUseSockNtop(&(gACInfoPtr->preferredAddress), * CWLog("WTP sends Discovery Request to: %s", str);); */ CW_FREE_PROTOCOL_MESSAGE(*msgPtr); CW_FREE_OBJECT(msgPtr); CW_FREE_OBJECT(gACInfoPtr); /* * we sent at least one Request in this loop * (even if we got an error sending it) */ sentSomething = CW_TRUE; } } /* All AC sent the response (so we didn't send any request) */ if (!sentSomething && CWWTPFoundAnAC()) break; gCWDiscoveryCount++; /* wait for Responses */ if (CWErr(CWReadResponses()) && CWWTPFoundAnAC()) { /* we read at least one valid Discovery Response */ break; } CWLog("WTP Discovery-To-Discovery (%d)", gCWDiscoveryCount); } CWLog("WTP Picks an AC"); /* crit error: we should have received at least one Discovery Response */ if (!CWWTPFoundAnAC()) { CWLog("No Discovery response Received"); return CW_ENTER_DISCOVERY; } /* if the AC is multi homed, we select our favorite AC's interface */ CWWTPPickACInterface(); CWUseSockNtop(&(gACInfoPtr->preferredAddress), CWLog("Preferred AC: \"%s\", at address: %s", gACInfoPtr->name, str); ); return CW_ENTER_JOIN; } /* * Wait DiscoveryInterval time while receiving Discovery Responses. */ CWBool CWReadResponses() { CWBool result = CW_FALSE; struct timeval timeout, before, after, delta, newTimeout; timeout.tv_sec = newTimeout.tv_sec = gCWDiscoveryInterval; timeout.tv_usec = newTimeout.tv_usec = 0; gettimeofday(&before, NULL); CW_REPEAT_FOREVER { /* check if something is available to read until newTimeout */ if (CWNetworkTimedPollRead(gWTPSocket, &newTimeout)) { /* success * if there was no error, raise a "success error", so we can easily handle * all the cases in the switch */ CWErrorRaise(CW_ERROR_SUCCESS, NULL); } switch (CWErrorGetLastErrorCode()) { case CW_ERROR_TIME_EXPIRED: goto cw_time_over; break; case CW_ERROR_SUCCESS: result = CWReceiveDiscoveryResponse(); case CW_ERROR_INTERRUPTED: /* * something to read OR interrupted by the system * wait for the remaining time (NetworkPoll will be recalled with the remaining time) */ gettimeofday(&after, NULL); CWTimevalSubtract(&delta, &after, &before); if (CWTimevalSubtract(&newTimeout, &timeout, &delta) == 1) { /* negative delta: time is over */ goto cw_time_over; } break; default: CWErrorHandleLast(); goto cw_error; break; } } cw_time_over: /* time is over */ CWDebugLog("Timer expired during receive"); cw_error: return result; } /* * Gets a datagram from network that should be a Discovery Response. */ CWBool CWReceiveDiscoveryResponse() { unsigned char buf[CW_BUFFER_SIZE]; int i; CWNetworkLev4Address addr; CWACInfoValues *ACInfoPtr; int seqNum; int readBytes; /* receive the datagram */ if (!CWErr(CWNetworkReceiveUnsafe(gWTPSocket, buf, CW_BUFFER_SIZE - 1, 0, &addr, &readBytes))) { return CW_FALSE; } CW_CREATE_OBJECT_ERR(ACInfoPtr, CWACInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* check if it is a valid Discovery Response */ if (!CWErr(CWParseDiscoveryResponseMessage(buf, readBytes, &seqNum, ACInfoPtr))) { CW_FREE_OBJECT(ACInfoPtr); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Received something different from a\ Discovery Response while in Discovery State"); } CW_COPY_NET_ADDR_PTR(&(ACInfoPtr->incomingAddress), &(addr)); /* see if this AC is better than the one we have stored */ CWWTPEvaluateAC(ACInfoPtr); CWLog("WTP Receives Discovery Response"); /* check if the sequence number we got is correct */ for (i = 0; i < gCWACCount; i++) { if (gCWACList[i].seqNum == seqNum) { CWUseSockNtop(&addr, CWLog("Discovery Response from:%s", str); ); /* we received response from this address */ gCWACList[i].received = CW_TRUE; return CW_TRUE; } } return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Sequence Number of Response doesn't macth Request"); } void CWWTPEvaluateAC(CWACInfoValues * ACInfoPtr) { if (ACInfoPtr == NULL) return; if (gACInfoPtr == NULL) { /* * this is the first AC we evaluate: so * it's the best AC we examined so far */ gACInfoPtr = ACInfoPtr; } else { CW_FREE_OBJECT(ACInfoPtr); } /* * ... note: we can add our favourite algorithm to pick the best AC. * We can also consider to remember all the Discovery Responses we * received and not just the best. */ } /* * Pick one interface of the AC (easy if there is just one interface). The * current algorithm just pick the Ac with less WTP communicating with it. If * the addresses returned by the AC in the Discovery Response don't include the * address of the sender of the Discovery Response, we ignore the address in * the Response and use the one of the sender (maybe the AC sees garbage * address, i.e. it is behind a NAT). */ void CWWTPPickACInterface() { int i, min; CWBool foundIncoming = CW_FALSE; if (gACInfoPtr == NULL) return; gACInfoPtr->preferredAddress.ss_family = AF_UNSPEC; if (gNetworkPreferredFamily == CW_IPv6) { goto cw_pick_IPv6; } cw_pick_IPv4: if (gACInfoPtr->IPv4Addresses == NULL || gACInfoPtr->IPv4AddressesCount <= 0) return; min = gACInfoPtr->IPv4Addresses[0].WTPCount; CW_COPY_NET_ADDR_PTR(&(gACInfoPtr->preferredAddress), &(gACInfoPtr->IPv4Addresses[0].addr)); for (i = 1; i < gACInfoPtr->IPv4AddressesCount; i++) { if (!sock_cmp_addr((struct sockaddr *)&(gACInfoPtr->IPv4Addresses[i]), (struct sockaddr *)&(gACInfoPtr->incomingAddress), sizeof(struct sockaddr_in))) foundIncoming = CW_TRUE; if (gACInfoPtr->IPv4Addresses[i].WTPCount < min) { min = gACInfoPtr->IPv4Addresses[i].WTPCount; CW_COPY_NET_ADDR_PTR(&(gACInfoPtr->preferredAddress), &(gACInfoPtr->IPv4Addresses[i].addr)); } } if (!foundIncoming) { /* * If the addresses returned by the AC in the Discovery * Response don't include the address of the sender of the * Discovery Response, we ignore the address in the Response * and use the one of the sender (maybe the AC sees garbage * address, i.e. it is behind a NAT). */ CW_COPY_NET_ADDR_PTR(&(gACInfoPtr->preferredAddress), &(gACInfoPtr->incomingAddress)); } return; cw_pick_IPv6: /* CWDebugLog("Pick IPv6"); */ if (gACInfoPtr->IPv6Addresses == NULL || gACInfoPtr->IPv6AddressesCount <= 0) goto cw_pick_IPv4; min = gACInfoPtr->IPv6Addresses[0].WTPCount; CW_COPY_NET_ADDR_PTR(&(gACInfoPtr->preferredAddress), &(gACInfoPtr->IPv6Addresses[0].addr)); for (i = 1; i < gACInfoPtr->IPv6AddressesCount; i++) { /* * if(!sock_cmp_addr(&(gACInfoPtr->IPv6Addresses[i]), * &(gACInfoPtr->incomingAddress), * sizeof(struct sockaddr_in6))) * * foundIncoming = CW_TRUE; */ if (gACInfoPtr->IPv6Addresses[i].WTPCount < min) { min = gACInfoPtr->IPv6Addresses[i].WTPCount; CW_COPY_NET_ADDR_PTR(&(gACInfoPtr->preferredAddress), &(gACInfoPtr->IPv6Addresses[i].addr)); } } /* if(!foundIncoming) { CW_COPY_NET_ADDR_PTR(&(gACInfoPtr->preferredAddress), &(gACInfoPtr->incomingAddress)); } */ return; } CWBool CWAssembleDiscoveryRequest(CWProtocolMessage ** messagesPtr, int seqNum) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 6; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; int k = -1; int fragmentsNum; if (messagesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /* Assemble Message Elements */ if ((!(CWAssembleMsgElemDiscoveryType(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPBoardData(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPDescriptor(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPFrameTunnelMode(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPMACType(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPRadioInformation(&(msgElems[++k])))) ) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } return CWAssembleMessage(messagesPtr, &fragmentsNum, 0, seqNum, CW_MSG_TYPE_VALUE_DISCOVERY_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount); } /* * Parse Discovery Response and return informations in *ACInfoPtr. */ CWBool CWParseDiscoveryResponseMessage(unsigned char *msg, int len, int *seqNumPtr, CWACInfoValues * ACInfoPtr) { CWControlHeaderValues controlVal; CWProtocolTransportHeaderValues transportVal; int offsetTillMessages, i, j; char tmp_ABGNTypes; CWProtocolMessage completeMsg; if (msg == NULL || seqNumPtr == NULL || ACInfoPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parse Discovery Response"); completeMsg.msg = msg; completeMsg.offset = 0; CWBool dataFlag = CW_FALSE; /* will be handled by the caller */ if (!(CWParseTransportHeader(&completeMsg, &transportVal, &dataFlag, NULL))) return CW_FALSE; /* will be handled by the caller */ if (!(CWParseControlHeader(&completeMsg, &controlVal))) return CW_FALSE; /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_DISCOVERY_RESPONSE) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Discovery Response as Expected"); *seqNumPtr = controlVal.seqNum; /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; ACInfoPtr->IPv4AddressesCount = 0; ACInfoPtr->IPv6AddressesCount = 0; /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &type, &len); CWDebugLog("Parsing Message Element: %u, len: %u", type, len); switch (type) { case CW_MSG_ELEMENT_AC_DESCRIPTOR_CW_TYPE: /* will be handled by the caller */ if (!(CWParseACDescriptor(&completeMsg, len, ACInfoPtr))) return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE: /* will be handled by the caller */ if (!(CWParseWTPRadioInformation_FromAC(&completeMsg, len, &tmp_ABGNTypes))) return CW_FALSE; break; case CW_MSG_ELEMENT_AC_NAME_CW_TYPE: /* will be handled by the caller */ if (!(CWParseACName(&completeMsg, len, &(ACInfoPtr->name)))) return CW_FALSE; break; case CW_MSG_ELEMENT_CW_CONTROL_IPV4_ADDRESS_CW_TYPE: /* * just count how many interfacess we have, * so we can allocate the array */ ACInfoPtr->IPv4AddressesCount++; completeMsg.offset += len; break; case CW_MSG_ELEMENT_CW_CONTROL_IPV6_ADDRESS_CW_TYPE: /* * just count how many interfacess we have, * so we can allocate the array */ ACInfoPtr->IPv6AddressesCount++; completeMsg.offset += len; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } /* CWDebugLog("bytes: %d/%d", * (completeMsg.offset-offsetTillMessages), * controlVal.msgElemsLen); */ } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); /* actually read each interface info */ CW_CREATE_ARRAY_ERR(ACInfoPtr->IPv4Addresses, ACInfoPtr->IPv4AddressesCount, CWProtocolIPv4NetworkInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (ACInfoPtr->IPv6AddressesCount > 0) { CW_CREATE_ARRAY_ERR(ACInfoPtr->IPv6Addresses, ACInfoPtr->IPv6AddressesCount, CWProtocolIPv6NetworkInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } i = 0, j = 0; completeMsg.offset = offsetTillMessages; while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &type, &len); switch (type) { case CW_MSG_ELEMENT_CW_CONTROL_IPV4_ADDRESS_CW_TYPE: /* will be handled by the caller */ if (!(CWParseCWControlIPv4Addresses(&completeMsg, len, &(ACInfoPtr->IPv4Addresses[i])))) return CW_FALSE; i++; break; case CW_MSG_ELEMENT_CW_CONTROL_IPV6_ADDRESS_CW_TYPE: /* will be handled by the caller */ if (!(CWParseCWControlIPv6Addresses(&completeMsg, len, &(ACInfoPtr->IPv6Addresses[j])))) return CW_FALSE; j++; break; default: completeMsg.offset += len; break; } } return CW_TRUE; } ================================================ FILE: WTPDriverInteraction.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define SIOCIWFIRSTPRIV 0x8BE0 #define IEEE80211_IOCTL_SETWMMPARAMS (SIOCIWFIRSTPRIV+4) #define IEEE80211_IOCTL_GETWMMPARAMS (SIOCIWFIRSTPRIV+5) #define IEEE80211_WMMPARAMS_CWMIN 1 #define IEEE80211_WMMPARAMS_CWMAX 2 #define IEEE80211_WMMPARAMS_AIFS 3 /**************************** mac80211 ****************************/ /**************************** iwconfig ****************************/ /*--------------------------- Frequency ---------------------------*/ int set_freq(int sock, struct iwreq wrq, int value) { wrq.u.freq.m = value; //in Ghz/10 wrq.u.freq.e = 1; if (ioctl(sock, SIOCSIWFREQ, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nFrequenza impostata a: %d\n", wrq.u.freq.m); return 1; } int get_freq(int sock, struct iwreq *wrq) { if (ioctl(sock, SIOCGIWFREQ, wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nFrequenza: %d\n", wrq->u.freq.m); return 1; } /*--------------------------- Bit rate ---------------------------*/ int set_bitrate(int sock, struct iwreq wrq, int value) { wrq.u.bitrate.value = value; wrq.u.bitrate.fixed = 1; if (ioctl(sock, SIOCSIWRATE, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nBit rate impostato a: %d\n", wrq.u.bitrate.value); return 1; } int get_bitrate(int sock, struct iwreq *wrq) { if (ioctl(sock, SIOCGIWRATE, wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nBit rate: %d\n", wrq->u.bitrate.value); return 1; } /*--------------------------- RTS/CTS Threshold ---------------------------*/ int set_rts_cts(int sock, struct iwreq wrq, int value) { if (value != 0) { wrq.u.rts.value = value; } else { wrq.u.rts.disabled = 1; } if (ioctl(sock, SIOCSIWRTS, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nRTS/CTS threshold impostato a: %d\n", wrq.u.rts.value); return 1; } int get_rts_cts(int sock, struct iwreq *wrq) { if (ioctl(sock, SIOCGIWRTS, wrq) < 0) { perror("Ioctl error"); return (0); } if (wrq->u.rts.disabled != 1) { printf("\nRTS/CTS threshold: %d\n", wrq->u.rts.value); } else { printf("\nRTS/CTS threshold off\n"); } return 1; } /*--------------------------- Fragmentation Threshold ---------------------------*/ int set_frag(int sock, struct iwreq wrq, int value) { if (value != 0) { wrq.u.frag.value = value; } else { wrq.u.frag.disabled = 1; } if (ioctl(sock, SIOCSIWFRAG, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nFragmentation threshold impostato a: %d\n", wrq.u.frag.value); return 1; } int get_frag(int sock, struct iwreq *wrq) { if (ioctl(sock, SIOCGIWFRAG, wrq) < 0) { perror("Ioctl error"); return (0); } if (wrq->u.frag.disabled != 1) { printf("\nFragmentation threshold: %d\n", wrq->u.frag.value); } else { printf("\nFragmentation threshold off\n"); } return 1; } /*--------------------------- Transmit Power ---------------------------*/ int set_txpower(int sock, struct iwreq wrq, int value) { wrq.u.txpower.value = value; wrq.u.txpower.fixed = 1; if (ioctl(sock, SIOCSIWTXPOW, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nTransmit power impostato a: %d\n", wrq.u.txpower.value); return 1; } int get_txpower(int sock, struct iwreq *wrq) { if (ioctl(sock, SIOCGIWTXPOW, wrq) < 0) { perror("Ioctl error"); return (0); } if (wrq->u.txpower.disabled != 1) { printf("\nTransmit power: %d\n", wrq->u.txpower.value); } else { printf("\nTransmit power off\n"); } return 1; } /**************************** iwpriv ****************************/ /*--------------------------- CWMIN ---------------------------*/ int set_cwmin(int sock, struct iwreq wrq, int acclass, int sta, int value) { int buffer[3]; wrq.u.mode = IEEE80211_WMMPARAMS_CWMIN; buffer[0] = acclass; buffer[1] = sta; buffer[2] = value; memcpy(wrq.u.name + sizeof(int), buffer, sizeof(buffer)); if (ioctl(sock, IEEE80211_IOCTL_SETWMMPARAMS, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nCWMIN impostato a: %d\n", value); return 1; } int get_cwmin(int sock, struct iwreq *wrq, int acclass, int sta) { int buffer[2]; wrq->u.mode = IEEE80211_WMMPARAMS_CWMIN; buffer[0] = acclass; buffer[1] = sta; memcpy(wrq->u.name + sizeof(int), buffer, sizeof(buffer)); if (ioctl(sock, IEEE80211_IOCTL_GETWMMPARAMS, wrq) < 0) { perror("Ioctl error"); return (0); } // printf("\nCWMIN: %d\n", wrq->u.param.value); return 1; } /*--------------------------- CWMAX ---------------------------*/ int set_cwmax(int sock, struct iwreq wrq, int acclass, int sta, int value) { int buffer[3]; wrq.u.mode = IEEE80211_WMMPARAMS_CWMAX; buffer[0] = acclass; buffer[1] = sta; buffer[2] = value; memcpy(wrq.u.name + sizeof(int), buffer, sizeof(buffer)); if (ioctl(sock, IEEE80211_IOCTL_SETWMMPARAMS, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nCWMAX impostato a: %d\n", value); return 1; } int get_cwmax(int sock, struct iwreq *wrq, int acclass, int sta) { int buffer[2]; wrq->u.mode = IEEE80211_WMMPARAMS_CWMAX; buffer[0] = acclass; buffer[1] = sta; memcpy(wrq->u.name + sizeof(int), buffer, sizeof(buffer)); if (ioctl(sock, IEEE80211_IOCTL_GETWMMPARAMS, wrq) < 0) { perror("Ioctl error"); return (0); } //printf("\nCWMAX: %d\n", wrq->u.param.value); return 1; } /*--------------------------- AIFS ---------------------------*/ int set_aifs(int sock, struct iwreq wrq, int acclass, int sta, int value) { int buffer[3]; wrq.u.mode = IEEE80211_WMMPARAMS_AIFS; buffer[0] = acclass; buffer[1] = sta; buffer[2] = value; memcpy(wrq.u.name + sizeof(int), buffer, sizeof(buffer)); if (ioctl(sock, IEEE80211_IOCTL_SETWMMPARAMS, &wrq) < 0) { perror("Ioctl error"); return (0); } printf("\nAIFS impostato a: %d\n", value); return 1; } int get_aifs(int sock, struct iwreq *wrq, int acclass, int sta) { int buffer[2]; wrq->u.mode = IEEE80211_WMMPARAMS_AIFS; buffer[0] = acclass; buffer[1] = sta; memcpy(wrq->u.name + sizeof(int), buffer, sizeof(buffer)); if (ioctl(sock, IEEE80211_IOCTL_GETWMMPARAMS, wrq) < 0) { perror("Ioctl error"); return (0); } //printf("\nAIFS: %d\n", wrq->u.param.value); return 1; } ================================================ FILE: WTPFrameReceive.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "WTPFrameReceive.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define EXIT_FRAME_THREAD(sock) CWLog("ERROR Handling Frames: application will be closed!"); \ close(sock); \ exit(1); int getMacAddr(int sock, char *interface, unsigned char *macAddr) { struct ifreq ethreq; int i; memset(ðreq, 0, sizeof(ethreq)); strncpy(ethreq.ifr_name, interface, IFNAMSIZ); if (ioctl(sock, SIOCGIFHWADDR, ðreq) == -1) { return 0; } for (i = 0; i < MAC_ADDR_LEN; i++) { macAddr[i] = (unsigned char)ethreq.ifr_hwaddr.sa_data[i]; } CWDebugLog("\n"); return 1; } int extractFrameInfo(char *buffer, char *RSSI, char *SNR, int *dataRate) { int signal, noise; *RSSI = buffer[RSSI_BYTE] - ATHEROS_CONV_VALUE; //RSSI in dBm signal = buffer[SIGNAL_BYTE] - ATHEROS_CONV_VALUE; noise = buffer[NOISE_BYTE]; *SNR = (char)signal - noise; //RSN in dB *dataRate = (buffer[DATARATE_BYTE] / 2) * 10; //Data rate in Mbps*10 return 1; } int extractFrame(CWProtocolMessage ** frame, unsigned char *buffer, int len) //len: frame length including prism header { CW_CREATE_OBJECT_ERR(*frame, CWProtocolMessage, return 0; ); CWProtocolMessage *auxPtr = *frame; CW_CREATE_PROTOCOL_MESSAGE(*auxPtr, len - PRISMH_LEN, return 0; ); memcpy(auxPtr->msg, buffer + PRISMH_LEN, len - PRISMH_LEN); auxPtr->offset = len - PRISMH_LEN; return 1; } int extract802_3_Frame(CWProtocolMessage ** frame, unsigned char *buffer, int len) { CW_CREATE_OBJECT_ERR(*frame, CWProtocolMessage, return 0; ); CWProtocolMessage *auxPtr = *frame; CW_CREATE_PROTOCOL_MESSAGE(*auxPtr, len, return 0; ); memcpy(auxPtr->msg, buffer, len); auxPtr->offset = len; return 1; } int extractAddr(unsigned char *destAddr, unsigned char *sourceAddr, char *frame) { memset(destAddr, 0, MAC_ADDR_LEN); memset(sourceAddr, 0, MAC_ADDR_LEN); memcpy(destAddr, frame + DEST_ADDR_START, MAC_ADDR_LEN); memcpy(sourceAddr, frame + SOURCE_ADDR_START, MAC_ADDR_LEN); return 1; } int macAddrCmp(unsigned char *addr1, unsigned char *addr2) { int i, ok = 1; /* CWDebugLog("Address 1:"); for (i=0; i PRISMH_LEN) { byte0 = *(buffer + PRISMH_LEN); version = byte0 & VERSION_MASK; type = byte0 & TYPE_MASK; subtype = byte0 & SUBTYPE_MASK; subtype >>= 4; /* if(version == (unsigned char) VERSION) {CWDebugLog("Version OK\n");} else {CWDebugLog("Wrong Version");} */ if (type == (unsigned char)MANAGEMENT_TYPE) { //Management Frame //CWDebugLog("Management Frame\n"); //CWDebugLog("Subtype: %d ", subtype); switch (subtype) { case ASSOCIATION_REQUEST_SUBTYPE:{ if (!extractFrame(&frame, buffer, n)) { CWDebugLog("THR FRAME: Error extracting a frame"); EXIT_FRAME_THREAD(gRawSock); } extractAddr(destAddr, sourceAddr, frame->msg); int k; for (k = 0; k < MAC_ADDR_LEN; k++) { printf("%02x", sourceAddr[k]); if (k != MAC_ADDR_LEN - 1) { printf(":"); } } printf("\n"); fflush(stdout); CW_CREATE_OBJECT_ERR(bindingValuesPtr, CWBindingTransportHeaderValues, EXIT_FRAME_THREAD(gRawSock); ); extractFrameInfo((char *)buffer, &(bindingValuesPtr->RSSI), &(bindingValuesPtr->SNR), &(bindingValuesPtr->dataRate)); CW_CREATE_OBJECT_ERR(listElement, CWBindingDataListElement, EXIT_FRAME_THREAD(gRawSock); ); listElement->frame = frame; listElement->bindingValues = bindingValuesPtr; // CWLockSafeList(gFrameList); CWAddElementToSafeListTail(gFrameList, listElement, sizeof(CWBindingDataListElement)); CWUnlockSafeList(gFrameList); break; } /* case ASSOCIATION_RESPONSE_SUBTYPE: {CWDebugLog("Association Response\n"); break;} case REASSOCIATION_REQUEST_SUBTYPE: {CWDebugLog("Reassociation Request\n"); break;} case REASSOCIATION_RESPONSE_SUBTYPE: {CWDebugLog("Reassociation Response\n"); break;} case PROBE_REQUEST_SUBTYPE: {CWDebugLog("Probe Request\n"); break;} case PROBE_RESPONSE_SUBTYPE: {CWDebugLog("Probe Response\n"); break;} case RESERVED6_SUBTYPE: {CWDebugLog("Reserved\n"); break;} case RESERVED7_SUBTYPE: {CWDebugLog("Reserved\n"); break;} case BEACON_SUBTYPE: {CWDebugLog("Beacon\n"); break;} case ATIM_SUBTYPE: {CWDebugLog("ATIM\n"); break;} case DISASSOCIATION_SUBTYPE: {CWDebugLog("Disassociation\n"); break;} case AUTHENTICATION_SUBTYPE: {CWDebugLog("Authentication\n"); break;} case DEAUTHENTICATION_SUBTYPE: {CWDebugLog("Deauthentication\n"); break;} */ default:{ /*CWDebugLog("Unrecognized Frame\n"); */ } } } if (type == (unsigned char)CONTROL_TYPE) { //Control Frame /* CWDebugLog("Control Frame\n"); //CWDebugLog("Subtype: %d ", subtype); switch (subtype) { case RESERVED0_SUBTYPE: {CWDebugLog("Reserved\n"); break;} case RESERVED9_SUBTYPE: {CWDebugLog("Reserved\n"); break;} case POWER_SAVE_SUBTYPE: {CWDebugLog("Power Save\n"); break;} case RTS_SUBTYPE: {CWDebugLog("RTS\n"); break;} case CTS_SUBTYPE: {CWDebugLog("CTS\n"); break;} case ACKNOLEDGEMENT_SUBTYPE: {CWDebugLog("Acknoledgement\n"); break;} case CF_END_SUBTYPE: {CWDebugLog("CF-End\n"); break;} case CF_END_CF_ACK_SUBTYPE: {CWDebugLog("CF-End + CF-Ack\n"); break;} default: {CWDebugLog("Unrecognized Frame\n");} } */ } if (type == (unsigned char)DATA_TYPE) { /* CWDebugLog("Data Frame\n"); //CWDebugLog("Subtype: %d ", subtype); switch (subtype) { case DATA_SUBTYPE: {CWDebugLog("Data\n"); break;} case DATA_CF_ACK_SUBTYPE: {CWDebugLog("Data + CF-Ack\n"); break;} case DATA_CF_POLL_SUBTYPE: {CWDebugLog("Data + CF-Poll\n"); break;} case DATA_CF_ACK_CF_POLL_SUBTYPE: {CWDebugLog("Data + CF-Ack + CF-Poll\n"); break;} case NO_DATA_SUBTYPE: {CWDebugLog("Null Function (no data)\n"); break;} case CF_ACK_SUBTYPE: {CWDebugLog("CF-Ack (no data)\n"); break;} case CF_POLL_SUBTYPE: {CWDebugLog("CF-Poll (no data)\n"); break;} case CF_ACK_CF_POLL_SUBTYPE: {CWDebugLog("CF-Ack + CF-Poll (no data)\n"); break;} case RESERVED8_SUBTYPE: {CWDebugLog("Reserved\n"); break;} case RESERVED15_SUBTYPE: {CWDebugLog("Reserved\n"); break;} default: {CWDebugLog("Unrecognized Frame\n");} } */ } } else CWDebugLog("Malformed Frame"); } else { //Assume it is 802.3 if (n <= (gCWForceMTU - 20)) { if (!extract802_3_Frame(&frame, buffer, n)) { CWDebugLog("THR FRAME: Error extracting a frame"); EXIT_FRAME_THREAD(gRawSock); } CWDebugLog("Send 802.3 data(len:%d) to AC", n); ; CW_CREATE_OBJECT_ERR(listElement, CWBindingDataListElement, EXIT_FRAME_THREAD(gRawSock); ); listElement->frame = frame; listElement->bindingValues = NULL; // CWLockSafeList(gFrameList); CWAddElementToSafeListTail(gFrameList, listElement, sizeof(CWBindingDataListElement)); CWUnlockSafeList(gFrameList); } else { CWDebugLog("size:%d of 802.3 data > MTU:%d", n, gCWForceMTU - 20); } } } close(gRawSock); return (NULL); } ================================================ FILE: WTPFrameReceive.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_WTPFrameReceive_HEADER__ #define __CAPWAP_WTPFrameReceive_HEADER__ #include #include #include #include #include #include #include "CWWTP.h" #ifndef B_ENDIAN #define CHECK_PRISM_HEADER (buffer[0]==MESSAGE_CODE_1) && \ (buffer[1]==MESSAGE_CODE_2) && \ (buffer[2]==MESSAGE_CODE_3) && \ (buffer[3]==MESSAGE_CODE_4) #else #define CHECK_PRISM_HEADER (buffer[3]==MESSAGE_CODE_1) && \ (buffer[2]==MESSAGE_CODE_2) && \ (buffer[1]==MESSAGE_CODE_3) && \ (buffer[0]==MESSAGE_CODE_4) #endif //#define PROMODE_ON //#define FILTER_ON #define PRISMH_LEN 144 #define RSSI_BYTE 68 #define SIGNAL_BYTE 92 #define NOISE_BYTE 104 #define DATARATE_BYTE 116 #define DEST_ADDR_START 4 #define SOURCE_ADDR_START 10 #define MESSAGE_CODE_1 68 #define MESSAGE_CODE_2 0 #define MESSAGE_CODE_3 0 #define MESSAGE_CODE_4 0 #define MAC_ADDR_LEN 6 #define ATHEROS_CONV_VALUE 95 #define ASSOCIATION_REQUEST_SUBTYPE 0 #define ASSOCIATION_RESPONSE_SUBTYPE 1 #define REASSOCIATION_REQUEST_SUBTYPE 2 #define REASSOCIATION_RESPONSE_SUBTYPE 3 #define PROBE_REQUEST_SUBTYPE 4 #define PROBE_RESPONSE_SUBTYPE 5 #define RESERVED6_SUBTYPE 6 #define RESERVED7_SUBTYPE 7 #define BEACON_SUBTYPE 8 #define ATIM_SUBTYPE 9 #define DISASSOCIATION_SUBTYPE 10 #define AUTHENTICATION_SUBTYPE 11 #define DEAUTHENTICATION_SUBTYPE 12 #define RESERVED0_SUBTYPE 0 #define RESERVED9_SUBTYPE 9 #define POWER_SAVE_SUBTYPE 10 #define RTS_SUBTYPE 11 #define CTS_SUBTYPE 12 #define ACKNOLEDGEMENT_SUBTYPE 13 #define CF_END_SUBTYPE 14 #define CF_END_CF_ACK_SUBTYPE 15 #define DATA_SUBTYPE 0 #define DATA_CF_ACK_SUBTYPE 1 #define DATA_CF_POLL_SUBTYPE 2 #define DATA_CF_ACK_CF_POLL_SUBTYPE 3 #define NO_DATA_SUBTYPE 4 #define CF_ACK_SUBTYPE 5 #define CF_POLL_SUBTYPE 6 #define CF_ACK_CF_POLL_SUBTYPE 7 #define RESERVED8_SUBTYPE 8 #define RESERVED15_SUBTYPE 15 #endif ================================================ FILE: WTPFreqStatsReceive.c ================================================ /******************************************************************************************* * Copyright (c) 2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Antonio Davoli (antonio.davoli@gmail.com) * * * *******************************************************************************************/ #include "WTPFreqStatsReceive.h" CW_THREAD_RETURN_TYPE CWWTPReceiveFreqStats(void *arg) { int recSock, rlen, k, fragmentsNum = 0; struct sockaddr_in servaddr, client_addr; socklen_t slen = sizeof(client_addr); char buffer[PACKET_SIZE]; CWProtocolMessage *completeMsgPtr = NULL; CWProtocolMessage *data = NULL; CWBindingTransportHeaderValues *bindingValuesPtr = NULL; CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); /* Create an Inet UDP socket for this thread (Receive freq/ack packets) */ if ((recSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { CWDebugLog("Thread Frequency Receive Stats: Error creating socket"); CWExitThread(); } /* Set up address structure for server socket */ servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); servaddr.sin_port = htons(SERVER_PORT); /* Binding Socket */ if (bind(recSock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0) { CWDebugLog("Thread Frequency Receive Stats: Binding Socket Error"); close(recSock); CWExitThread(); } CW_REPEAT_FOREVER /* Receive data Loop */ { memset(buffer, 0, PACKET_SIZE); fragmentsNum = 0; k = 0; rlen = 0; if ((rlen = recvfrom(recSock, buffer, PACKET_SIZE, 0, (struct sockaddr *)&client_addr, &slen)) > 0) { /* Creation of stats/ack message for AC */ CW_CREATE_OBJECT_ERR(data, CWProtocolMessage, return 0; ); CW_CREATE_PROTOCOL_MESSAGE(*data, rlen, return 0; ); memcpy(data->msg, buffer, rlen); data->offset = rlen; /************************************************************** * 2009 Update: * * * * Frequency Stats Message, like the QoS Data message are * * encapsuled on Capwap Data Message. * * For distinguish the two types of message we use the fields * * of binding dataRate and SNR. * * Frequency Stats Message: dataRate=-1 && SNR=1 * * QoS Stats Message : dataRate=-1 * * ---------------------------------------------------------- * * For others Info: see CWBinding.c * **************************************************************/ /* In this function is tied the name of the socket: recSock */ CW_CREATE_OBJECT_ERR(bindingValuesPtr, CWBindingTransportHeaderValues, EXIT_THREAD); bindingValuesPtr->dataRate = -1; bindingValuesPtr->SNR = 1; /* Capwap Message Assembling */ if (CWAssembleDataMessage(&completeMsgPtr, &fragmentsNum, gWTPPathMTU, data, bindingValuesPtr, CW_PACKET_PLAIN, 0) == CW_TRUE) { for (k = 0; k < fragmentsNum; k++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected (gWTPSocket, completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { #else if (!CWSecuritySend (gWTPSession, completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { #endif CWDebugLog("Failure sending Request"); } } } /* Free used Structures */ for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*data); CW_FREE_OBJECT(data); CW_FREE_OBJECT(bindingValuesPtr); } else { CWDebugLog("Thread Frequency Receive Stats: Error on recvfrom"); close(recSock); } } } ================================================ FILE: WTPFreqStatsReceive.h ================================================ /******************************************************************************************* * Copyright (c) 2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Antonio Davoli (antonio.davoli@gmail.com) * * * *******************************************************************************************/ #ifndef __CAPWAP_WTPFreqStatsReceive_HEADER__ #define __CAPWAP_WTPFreqStatsReceive_HEADER__ #include "CWWTP.h" #include #include #include #define SERVER_PORT 1237 #define PACKET_SIZE 65536 #define EXIT_THREAD CWLog("ERROR Handling Frequency Stats: application will be closed!"); \ close(recSock); \ exit(1); /* Structs for frequencies' informations */ typedef unsigned char uint8; #define MAX_FREQ_LENGTH 16 #define MAX_ESSID_LENGTH 32 #define MAX_MAC_ADDR_LENGTH 18 /* XX:XX:XX:XX:XX:XX */ typedef struct _quality { uint8 numerator; uint8 denominator; } quality; typedef struct _FreqQualityInfo { uint8 version; char ESSID[MAX_ESSID_LENGTH]; char Address[MAX_MAC_ADDR_LENGTH]; uint8 channel; uint8 assocStations; uint8 throughStations; quality qualityLevel; int signalLevel; int noiseLevel; } FreqQualityInfo; typedef struct _FREQ_MONITOR_DATA { int numberOfCells; FreqQualityInfo *qualityOfCells; } FREQ_MONITOR_DATA; #endif ================================================ FILE: WTPJoinState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif static CWBool gSuccessfulHandshake = CW_TRUE; int gCWWaitJoin = CW_JOIN_INTERVAL_DEFAULT; int gCWDiscoveryCount; /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ void CWWTPWaitJoinExpired(CWTimerArg arg); CWBool CWAssembleJoinRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CWBool CWParseJoinResponseMessage(unsigned char *msg, int len, int seqNum, CWProtocolJoinResponseValues * valuesPtr); CWBool CWSaveJoinResponseMessage(CWProtocolJoinResponseValues * joinResponse); /*_____________________________________________________*/ /* *******************___FUNCTIONS___******************* */ /* * Manage Join State. */ CWStateTransition CWWTPEnterJoin() { CWTimerID waitJoinTimer; int seqNum; CWProtocolJoinResponseValues values; CWStateTransition state = CW_ENTER_DISCOVERY; CWDebugLog("Checking if hostapd is connected..."); if (gRADIO_MAC[0] == 0xAA){ CWDebugLog("Waiting for hostapd to connect..."); while(gRADIO_MAC[0] == 0xAA) sleep(1); } else { CWDebugLog("Hostapd is connected..."); } CWDebugLog("\n"); CWDebugLog("######### Join State #########"); /* reset Join state */ CWNetworkCloseSocket(gWTPSocket); #ifndef CW_NO_DTLS CWSecurityDestroySession(gWTPSession); CWSecurityDestroyContext(gWTPSecurityContext); #endif gWTPSecurityContext = NULL; gWTPSession = NULL; /* Initialize gACInfoPtr */ gACInfoPtr = malloc(sizeof(CWACInfoValues)); gACInfoPtr->ACIPv4ListInfo.ACIPv4ListCount = 0; gACInfoPtr->ACIPv4ListInfo.ACIPv4List = NULL; gACInfoPtr->ACIPv6ListInfo.ACIPv6ListCount = 0; gACInfoPtr->ACIPv6ListInfo.ACIPv6List = NULL; CWDebugLog("State is %d", state); if (gWTPForceACAddress != NULL) { CW_CREATE_OBJECT_ERR(gACInfoPtr, CWACInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWNetworkGetAddressForHost(gWTPForceACAddress, &(gACInfoPtr->preferredAddress)); gACInfoPtr->security = gWTPForceSecurity; state = CW_ENTER_JOIN; CWDebugLog("State is %d", state); } if ((waitJoinTimer = timer_add(gCWWaitJoin, 0, CWWTPWaitJoinExpired, NULL)) == -1) { return state; } /* Init DTLS session */ if (!CWErr(CWNetworkInitSocketClient(&gWTPSocket, &(gACInfoPtr->preferredAddress)))) { timer_rem(waitJoinTimer, NULL); return state; } if (!CWErr(CWNetworkInitSocketClientDataChannel(&gWTPDataSocket, &(gACInfoPtr->preferredAddress)))) { return state; } CWLog("Initiate Data Channel"); CWDebugLog("gWTPSocket:%d, gWTPDataSocket:%d", gWTPSocket, gWTPDataSocket); #ifndef CW_NO_DTLS if (gACInfoPtr->security == CW_X509_CERTIFICATE) { if (!CWErr(CWSecurityInitContext(&gWTPSecurityContext, "root.pem", "client.pem", "prova", CW_TRUE, NULL))) { timer_rem(waitJoinTimer, NULL); CWNetworkCloseSocket(gWTPSocket); gWTPSecurityContext = NULL; return state; } } else { /* pre-shared keys */ if (!CWErr(CWSecurityInitContext(&gWTPSecurityContext, NULL, NULL, NULL, CW_TRUE, NULL))) { timer_rem(waitJoinTimer, NULL); CWNetworkCloseSocket(gWTPSocket); gWTPSecurityContext = NULL; return state; } } #endif CWThread thread_receiveFrame; if (!CWErr(CWCreateThread(&thread_receiveFrame, CWWTPReceiveDtlsPacket, (void *)gWTPSocket))) { CWLog("Error starting Thread that receive DTLS packet"); timer_rem(waitJoinTimer, NULL); CWNetworkCloseSocket(gWTPSocket); #ifndef CW_NO_DTLS CWSecurityDestroyContext(gWTPSecurityContext); gWTPSecurityContext = NULL; gWTPSession = NULL; #endif if (gWTPForceACAddress != NULL) return CW_ENTER_JOIN; else return state; } CWThread thread_receiveDataFrame; if (!CWErr(CWCreateThread(&thread_receiveDataFrame, CWWTPReceiveDataPacket, (void *)gWTPDataSocket))) { CWLog("Error starting Thread that receive data packet"); return state; } #ifndef CW_NO_DTLS if (!CWErr(CWSecurityInitSessionClient(gWTPSocket, &(gACInfoPtr->preferredAddress), gPacketReceiveList, gWTPSecurityContext, &gWTPSession, &gWTPPathMTU))) { /* error setting up DTLS session */ timer_rem(waitJoinTimer, NULL); CWNetworkCloseSocket(gWTPSocket); CWSecurityDestroyContext(gWTPSecurityContext); gWTPSecurityContext = NULL; gWTPSession = NULL; return state; } #endif if (gCWForceMTU > 0) { gWTPPathMTU = gCWForceMTU; } CWDebugLog("Path MTU for this Session: %d", gWTPPathMTU); CWDebugLog("Waiting for previous threads to be closed on AC"); //sleep(CW_NEIGHBORDEAD_INTERVAL_DEFAULT*2); /* send Join Request */ seqNum = CWGetSeqNum(); if (!CWErr(CWWTPSendAcknowledgedPacket(seqNum, NULL, CWAssembleJoinRequest, (void *)CWParseJoinResponseMessage, (void *)CWSaveJoinResponseMessage, &values))) { cw_join_err: timer_rem(waitJoinTimer, NULL); CWNetworkCloseSocket(gWTPSocket); #ifndef CW_NO_DTLS CWSecurityDestroySession(gWTPSession); CWSecurityDestroyContext(gWTPSecurityContext); gWTPSecurityContext = NULL; gWTPSession = NULL; #endif gWTPSecurityContext = NULL; gWTPSession = NULL; return state; } timer_rem(waitJoinTimer, NULL); if (!gSuccessfulHandshake) { /* timer expired */ goto cw_join_err; } CWLog("Join Completed"); return CW_ENTER_CONFIGURE; } void CWWTPWaitJoinExpired(CWTimerArg arg) { CWLog("WTP Wait Join Expired"); gSuccessfulHandshake = CW_FALSE; CWNetworkCloseSocket(gWTPSocket); } CWBool CWAssembleJoinRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 9; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWLog("Assembling Join Request Message Elements..."); /* Assemble Message Elements */ if ((!(CWAssembleMsgElemLocationData(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPBoardData(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPDescriptor(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPIPv4Address(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPName(&(msgElems[++k])))) || (!(CWAssembleMsgElemSessionID(&(msgElems[++k]), &gWTPSessionID[0]))) || (!(CWAssembleMsgElemWTPFrameTunnelMode(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPMACType(&(msgElems[++k])))) || (!(CWAssembleMsgElemWTPRadioInformation(&(msgElems[++k])))) ) { int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); /* error will be handled by the caller */ return CW_FALSE; } CWLog("Assembling and Sending Join Request Message ..."); return CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_JOIN_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount); } /* * Parse Join Response and return informations in *valuesPtr. */ CWBool CWParseJoinResponseMessage(unsigned char *msg, int len, int seqNum, CWProtocolJoinResponseValues * valuesPtr) { CWControlHeaderValues controlVal; CWProtocolMessage completeMsg; int offsetTillMessages; char tmp_ABGNTypes; if (msg == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Parsing Join Response..."); completeMsg.msg = msg; completeMsg.offset = 0; /* error will be handled by the caller */ if (!(CWParseControlHeader(&completeMsg, &controlVal))) return CW_FALSE; if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_JOIN_RESPONSE) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Join Response as Expected"); if (controlVal.seqNum != seqNum) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Different Sequence Number"); /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; offsetTillMessages = completeMsg.offset; /* Mauro */ valuesPtr->ACInfoPtr.IPv4AddressesCount = 0; valuesPtr->ACInfoPtr.IPv6AddressesCount = 0; /* parse message elements */ while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int type = 0; unsigned short int len = 0; CWParseFormatMsgElem(&completeMsg, &type, &len); CWDebugLog("Parsing Message Element: %u, len: %u", type, len); /* valuesPtr->ACInfoPtr.IPv4AddressesCount = 0; valuesPtr->ACInfoPtr.IPv6AddressesCount = 0; */ valuesPtr->ACIPv4ListInfo.ACIPv4ListCount = 0; valuesPtr->ACIPv4ListInfo.ACIPv4List = NULL; valuesPtr->ACIPv6ListInfo.ACIPv6ListCount = 0; valuesPtr->ACIPv6ListInfo.ACIPv6List = NULL; switch (type) { case CW_MSG_ELEMENT_AC_DESCRIPTOR_CW_TYPE: /* will be handled by the caller */ if (!(CWParseACDescriptor(&completeMsg, len, &(valuesPtr->ACInfoPtr)))) return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE: /* will be handled by the caller */ if (!CWParseWTPRadioInformation_FromAC(&completeMsg, len, &tmp_ABGNTypes)) return CW_FALSE; break; case CW_MSG_ELEMENT_AC_IPV4_LIST_CW_TYPE: if (!(CWParseACIPv4List(&completeMsg, len, &(valuesPtr->ACIPv4ListInfo)))) return CW_FALSE; break; case CW_MSG_ELEMENT_AC_IPV6_LIST_CW_TYPE: if (!(CWParseACIPv6List(&completeMsg, len, &(valuesPtr->ACIPv6ListInfo)))) return CW_FALSE; break; case CW_MSG_ELEMENT_RESULT_CODE_CW_TYPE: if (!(CWParseResultCode(&completeMsg, len, &(valuesPtr->code)))) return CW_FALSE; break; case CW_MSG_ELEMENT_AC_NAME_CW_TYPE: /* will be handled by the caller */ if (!(CWParseACName(&completeMsg, len, &(valuesPtr->ACInfoPtr.name)))) return CW_FALSE; break; case CW_MSG_ELEMENT_CW_CONTROL_IPV4_ADDRESS_CW_TYPE: /* * just count how many interfacess we * have, so we can allocate the array */ valuesPtr->ACInfoPtr.IPv4AddressesCount++; completeMsg.offset += len; break; case CW_MSG_ELEMENT_CW_CONTROL_IPV6_ADDRESS_CW_TYPE: /* * just count how many interfacess we * have, so we can allocate the array */ valuesPtr->ACInfoPtr.IPv6AddressesCount++; completeMsg.offset += len; break; /* case CW_MSG_ELEMENT_SESSION_ID_CW_TYPE: if(!(CWParseSessionID(&completeMsg, len, valuesPtr))) return CW_FALSE; break; */ default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } /* CWDebugLog("bytes: %d/%d", (completeMsg.offset-offsetTillMessages), controlVal.msgElemsLen); */ } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); /* actually read each interface info */ CW_CREATE_ARRAY_ERR(valuesPtr->ACInfoPtr.IPv4Addresses, valuesPtr->ACInfoPtr.IPv4AddressesCount, CWProtocolIPv4NetworkInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (valuesPtr->ACInfoPtr.IPv6AddressesCount > 0) { CW_CREATE_ARRAY_ERR(valuesPtr->ACInfoPtr.IPv6Addresses, valuesPtr->ACInfoPtr.IPv6AddressesCount, CWProtocolIPv6NetworkInterface, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } int i = 0; int j = 0; completeMsg.offset = offsetTillMessages; while ((completeMsg.offset - offsetTillMessages) < controlVal.msgElemsLen) { unsigned short int type = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int len = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &type, &len); switch (type) { case CW_MSG_ELEMENT_CW_CONTROL_IPV4_ADDRESS_CW_TYPE: /* will be handled by the caller */ if (!(CWParseCWControlIPv4Addresses(&completeMsg, len, &(valuesPtr->ACInfoPtr.IPv4Addresses[i])))) return CW_FALSE; i++; break; case CW_MSG_ELEMENT_CW_CONTROL_IPV6_ADDRESS_CW_TYPE: /* will be handled by the caller */ if (!(CWParseCWControlIPv6Addresses(&completeMsg, len, &(valuesPtr->ACInfoPtr.IPv6Addresses[j])))) return CW_FALSE; j++; break; default: completeMsg.offset += len; break; } } return CW_TRUE; } CWBool CWSaveJoinResponseMessage(CWProtocolJoinResponseValues * joinResponse) { if (joinResponse == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if ((joinResponse->code == CW_PROTOCOL_SUCCESS) || (joinResponse->code == CW_PROTOCOL_SUCCESS_NAT)) { if (gACInfoPtr == NULL) return CWErrorRaise(CW_ERROR_NEED_RESOURCE, NULL); gACInfoPtr->name = (joinResponse->ACInfoPtr).name; gACInfoPtr->stations = (joinResponse->ACInfoPtr).stations; gACInfoPtr->limit = (joinResponse->ACInfoPtr).limit; gACInfoPtr->activeWTPs = (joinResponse->ACInfoPtr).activeWTPs; gACInfoPtr->maxWTPs = (joinResponse->ACInfoPtr).maxWTPs; gACInfoPtr->security = (joinResponse->ACInfoPtr).security; gACInfoPtr->RMACField = (joinResponse->ACInfoPtr).RMACField; /* BUG-ML07 * Before overwriting the field vendorInfos we'd better * free it (it was allocated during the Discovery State by * the function CWParseACDescriptor()). * * 19/10/2009 - Donato Capitella */ // Applies only if Discovey has run if (gCWDiscoveryCount != 0) { int i; for (i = 0; i < gACInfoPtr->vendorInfos.vendorInfosCount; i++) { CW_FREE_OBJECT(gACInfoPtr->vendorInfos.vendorInfos[i].valuePtr); } CW_FREE_OBJECT(gACInfoPtr->vendorInfos.vendorInfos); gWTPForceACAddress = NULL; if (joinResponse->ACIPv4ListInfo.ACIPv4ListCount > 0) { gACInfoPtr->ACIPv4ListInfo.ACIPv4ListCount = joinResponse->ACIPv4ListInfo.ACIPv4ListCount; gACInfoPtr->ACIPv4ListInfo.ACIPv4List = joinResponse->ACIPv4ListInfo.ACIPv4List; } if (joinResponse->ACIPv6ListInfo.ACIPv6ListCount > 0) { gACInfoPtr->ACIPv6ListInfo.ACIPv6ListCount = joinResponse->ACIPv6ListInfo.ACIPv6ListCount; gACInfoPtr->ACIPv6ListInfo.ACIPv6List = joinResponse->ACIPv6ListInfo.ACIPv6List; } } gACInfoPtr->vendorInfos = (joinResponse->ACInfoPtr).vendorInfos; /* * This field name was allocated for storing the AC name; however, it * doesn't seem to be used and it is certainly lost when we exit * CWWTPEnterJoin() as joinResponse is actually a local variable of that * function. * * Thus, it seems good to free it now. * * BUG ML03 * 16/10/2009 - Donato Capitella */ CW_FREE_OBJECT(joinResponse->ACInfoPtr.name); /* BUG ML08 */ CW_FREE_OBJECT(joinResponse->ACInfoPtr.IPv4Addresses); CWDebugLog("Join Response Saved"); return CW_TRUE; } else { CWDebugLog("Join Response said \"Failure\""); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Join Response as Expected"); } } ================================================ FILE: WTPProtocol.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #include "WTPipcHostapd.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /*____________________________________________________________________________*/ /* *****************************___ASSEMBLE___***************************** */ CWBool CWAssembleMsgElemACName(CWProtocolMessage * msgPtr) { char *name; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); name = CWWTPGetACName(); CWDebugLog("AC Name: %s", name); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, strlen(name), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStoreStr(msgPtr, name); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_AC_NAME_CW_TYPE); } CWBool CWAssembleMsgElemACNameWithIndex(CWProtocolMessage * msgPtr) { const int ac_Index_length = 1; CWACNamesWithIndex ACsinfo; CWProtocolMessage *msgs; int len = 0; int i; int j; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!CWWTPGetACNameWithIndex(&ACsinfo)) { return CW_FALSE; } CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgs, ACsinfo.count, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // create message for (i = 0; i < ACsinfo.count; i++) { // create message CW_CREATE_PROTOCOL_MESSAGE(msgs[i], ac_Index_length + strlen(ACsinfo.ACNameIndex[i].ACName), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(&(msgs[i]), ACsinfo.ACNameIndex[i].index); // ID of the AC CWProtocolStoreStr(&(msgs[i]), ACsinfo.ACNameIndex[i].ACName); // name of the AC if (!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_AC_NAME_INDEX_CW_TYPE))) { for (j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]); } CW_FREE_OBJECT(ACsinfo.ACNameIndex); CW_FREE_OBJECT(msgs); return CW_FALSE; } // CWDebugLog("AC Name with index: %d - %s", ACsinfo.ACNameIndex[i].index, ACsinfo.ACNameIndex[i].ACName); len += msgs[i].offset; } CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < ACsinfo.count; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } CW_FREE_OBJECT(msgs); /* * They free ACNameIndex, which is an array of CWACNameWithIndexValues, * but nobody cares to free the actual strings that were allocated as fields * of the CWACNameWithIndexValues structures in the CWWTPGetACNameWithIndex() * function.. Here we take care of this. * * BUG ML06 * 16/10/2009 - Donato Capitella */ CW_FREE_OBJECT(ACsinfo.ACNameIndex[0].ACName); CW_FREE_OBJECT(ACsinfo.ACNameIndex[1].ACName); CW_FREE_OBJECT(ACsinfo.ACNameIndex); return CW_TRUE; } CWBool CWAssembleMsgElemDataTransferData(CWProtocolMessage * msgPtr, int data_type) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); char *debug_data = " #### DATA DEBUG INFO #### "; //to be changed... // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 2 + strlen(debug_data), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, data_type); CWProtocolStore8(msgPtr, strlen(debug_data)); CWProtocolStoreStr(msgPtr, debug_data); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_DATA_TRANSFER_DATA_CW_TYPE); } CWBool CWAssembleMsgElemDiscoveryType(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 1, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog("Discovery Type: %d", CWWTPGetDiscoveryType()); CWProtocolStore8(msgPtr, CWWTPGetDiscoveryType()); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_DISCOVERY_TYPE_CW_TYPE); } CWBool CWAssembleMsgElemLocationData(CWProtocolMessage * msgPtr) { CWDebugLog("CWAssembleMsgElemLocationData()"); char *location; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); location = CWWTPGetLocation(); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, strlen(location), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWDebugLog("Location Data: %s", location); CWProtocolStoreStr(msgPtr, location); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_LOCATION_DATA_CW_TYPE); } CWBool CWAssembleMsgElemStatisticsTimer(CWProtocolMessage * msgPtr) { const int statistics_timer_length = 2; CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, statistics_timer_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore16(msgPtr, CWWTPGetStatisticsTimer()); // CWDebugLog("Statistics Timer: %d", CWWTPGetStatisticsTimer()); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_STATISTICS_TIMER_CW_TYPE); } CWBool CWAssembleMsgElemWTPBoardData(CWProtocolMessage * msgPtr) { CWDebugLog("CWAssembleMsgElemWTPBoardData()"); const int VENDOR_ID_LENGTH = 4; //Vendor Identifier is 4 bytes long const int TLV_HEADER_LENGTH = 4; //Type and Length of a TLV field is 4 byte long CWWTPVendorInfos infos; int i, size = 0; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // get infos if (!CWWTPGetBoardData(&infos)) { return CW_FALSE; } //Calculate msg elem size size = VENDOR_ID_LENGTH; for (i = 0; i < infos.vendorInfosCount; i++) { size += (TLV_HEADER_LENGTH + ((infos.vendorInfos)[i]).length); } // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, size, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore32(msgPtr, ((infos.vendorInfos)[0].vendorIdentifier)); for (i = 0; i < infos.vendorInfosCount; i++) { CWProtocolStore16(msgPtr, ((infos.vendorInfos)[i].type)); CWProtocolStore16(msgPtr, ((infos.vendorInfos)[i].length)); if ((infos.vendorInfos)[i].length == 4) { *((infos.vendorInfos)[i].valuePtr) = htonl(*((infos.vendorInfos)[i].valuePtr)); } CWProtocolStoreRawBytes(msgPtr, (unsigned char *)((infos.vendorInfos)[i].valuePtr), (infos.vendorInfos)[i].length); // CWDebugLog("Board Data: %d - %d - %d - %d", (infos.vendorInfos)[i].vendorIdentifier, (infos.vendorInfos)[i].type, (infos.vendorInfos)[i].length, *((infos.vendorInfos)[i].valuePtr)); } CWWTPDestroyVendorInfos(&infos); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_BOARD_DATA_CW_TYPE); } CWBool CWAssembleMsgElemVendorSpecificPayload(CWProtocolMessage * msgPtr) { const int VENDOR_ID_LENGTH = 4; //Vendor Identifier is 4 bytes long const int ELEMENT_ID = 2; //Type and Length of a TLV field is 4 byte long const int DATA_LEN = 2; CWWTPVendorInfos infos; int size = 0; int element_id_zero = 0; int data_zero = 0; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // get infos if (!CWWTPGetBoardData(&infos)) { return CW_FALSE; } //Calculate msg elem size size = VENDOR_ID_LENGTH + ELEMENT_ID + DATA_LEN; // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, size, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore32(msgPtr, ((infos.vendorInfos)[0].vendorIdentifier)); CWProtocolStore16(msgPtr, element_id_zero); CWProtocolStore16(msgPtr, data_zero); CWWTPDestroyVendorInfos(&infos); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_BW_CW_TYPE); } CWBool CWAssembleMsgElemWTPDescriptor(CWProtocolMessage * msgPtr) { const int GENERIC_RADIO_INFO_LENGTH = 5; //First 4 bytes for Max Radios, Radios In Use and Num Encryption Capability const int VENDOR_ID_LENGTH = 4; //Vendor Identifier is 4 bytes long const int TLV_HEADER_LENGTH = 4; //Type and Length of a TLV field is 4 byte long CWWTPEncryptCaps encc; CWWTPVendorInfos infos; int i, size = 0; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // get infos if (!CWWTPGetVendorInfos(&infos)) { return CW_FALSE; } if (!CWWTPGetEncCapabilities(&encc)) { // encryption capabilities return CW_FALSE; } //Calculate msg elem size size = GENERIC_RADIO_INFO_LENGTH; for (i = 0; i < encc.encryptCapsCount; i++) { size += 3; } for (i = 0; i < infos.vendorInfosCount; i++) { size += (VENDOR_ID_LENGTH + TLV_HEADER_LENGTH + ((infos.vendorInfos)[i]).length); } // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, size, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, CWWTPGetMaxRadios()); // number of radios supported by the WTP CWProtocolStore8(msgPtr, CWWTPGetRadiosInUse()); // number of radios present in the WTP CWProtocolStore8(msgPtr, encc.encryptCapsCount); for (i = 0; i < encc.encryptCapsCount; i++) { CWProtocolStore8(msgPtr, (encc.encryptCaps)[i].WBID & 0x1f); CWProtocolStore16(msgPtr, (encc.encryptCaps)[i].encryptionCapabilities); } for (i = 0; i < infos.vendorInfosCount; i++) { CWProtocolStore32(msgPtr, ((infos.vendorInfos)[i].vendorIdentifier)); CWProtocolStore16(msgPtr, ((infos.vendorInfos)[i].type)); CWProtocolStore16(msgPtr, ((infos.vendorInfos)[i].length)); if ((infos.vendorInfos)[i].length == 4) { *((infos.vendorInfos)[i].valuePtr) = htonl(*((infos.vendorInfos)[i].valuePtr)); } CWProtocolStoreRawBytes(msgPtr, (unsigned char *)((infos.vendorInfos)[i].valuePtr), (infos.vendorInfos)[i].length); // CWDebugLog("WTP Descriptor Vendor ID: %d", (infos.vendorInfos)[i].vendorIdentifier); // CWDebugLog("WTP Descriptor Type: %d", (infos.vendorInfos)[i].type); // CWDebugLog("WTP Descriptor Length: %d", (infos.vendorInfos)[i].length); // CWDebugLog("WTP Descriptor Value: %d", *((infos.vendorInfos)[i].valuePtr)); //CWDebugLog("Vendor Info \"%d\" = %d - %d - %d", i, (infos.vendorInfos)[i].vendorIdentifier, (infos.vendorInfos)[i].type, (infos.vendorInfos)[i].length); } CWWTPDestroyVendorInfos(&infos); CWWTPDestroyEncCapabilities(&encc); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_DESCRIPTOR_CW_TYPE); } CWBool CWAssembleMsgElemWTPFrameTunnelMode(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 1, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog("Frame Tunnel Mode: %d", CWWTPGetFrameTunnelMode()); CWProtocolStore8(msgPtr, CWWTPGetFrameTunnelMode()); // frame encryption return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_FRAME_TUNNEL_MODE_CW_TYPE); } CWBool CWAssembleMsgElemWTPIPv4Address(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 4, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog("WTP IPv4 Address: %d", CWWTPGetIPv4Address()); CWProtocolStore32(msgPtr, CWWTPGetIPv4Address()); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_IPV4_ADDRESS_CW_TYPE); } CWBool CWAssembleMsgElemWTPMACType(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 1, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog("WTP MAC Type: %d", CWWTPGetMACType()); CWProtocolStore8(msgPtr, CWWTPGetMACType()); // mode of operation of the WTP (local, split, ...) return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_MAC_TYPE_CW_TYPE); } CWBool CWAssembleMsgElemWTPRadioInformation(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 5, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); unsigned char wtp_r_info; wtp_r_info = CWTP_get_WTP_Radio_Information(); int radioID = 0; CWProtocolStore8(msgPtr, radioID); CWProtocolStore8(msgPtr, 0); CWProtocolStore8(msgPtr, 0); CWProtocolStore8(msgPtr, 0); CWProtocolStore8(msgPtr, wtp_r_info); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IEEE80211_WTP_RADIO_INFORMATION_CW_TYPE); } CWBool CWAssembleMsgElemSupportedRates(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 9, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); unsigned char tmp_sup_rate[8]; CWWTP_get_WTP_Rates(tmp_sup_rate); int radioID = 0; CWProtocolStore8(msgPtr, radioID); CWProtocolStore8(msgPtr, tmp_sup_rate[0]); CWProtocolStore8(msgPtr, tmp_sup_rate[1]); CWProtocolStore8(msgPtr, tmp_sup_rate[2]); CWProtocolStore8(msgPtr, tmp_sup_rate[3]); CWProtocolStore8(msgPtr, tmp_sup_rate[4]); CWProtocolStore8(msgPtr, tmp_sup_rate[5]); CWProtocolStore8(msgPtr, tmp_sup_rate[6]); CWProtocolStore8(msgPtr, tmp_sup_rate[7]); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IEEE80211_SUPPORTED_RATES_CW_TYPE); } CWBool CWAssembleMsgElemMultiDomainCapability(CWProtocolMessage * msgPtr) { if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, 8, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); unsigned char tmp_mdc[6]; CWWTP_get_WTP_MDC(tmp_mdc); int radioID = 0; CWProtocolStore8(msgPtr, radioID); CWProtocolStore8(msgPtr, 0); CWProtocolStore8(msgPtr, tmp_mdc[0]); CWProtocolStore8(msgPtr, tmp_mdc[1]); CWProtocolStore8(msgPtr, tmp_mdc[2]); CWProtocolStore8(msgPtr, tmp_mdc[3]); CWProtocolStore8(msgPtr, tmp_mdc[4]); CWProtocolStore8(msgPtr, tmp_mdc[5]); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_IEEE80211_MULTI_DOMAIN_CAPABILITY_CW_TYPE); } CWBool CWAssembleMsgElemWTPName(CWProtocolMessage * msgPtr) { char *name; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); name = CWWTPGetName(); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, strlen(name), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog("WTPName: %s", name); CWProtocolStoreStr(msgPtr, name); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_NAME_CW_TYPE); } CWBool CWAssembleMsgElemWTPOperationalStatistics(CWProtocolMessage * msgPtr, int radio) { const int operational_statistics_length = 4; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (radio < 0 || radio >= gRadiosInfo.radioCount) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, operational_statistics_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, radio); CWProtocolStore8(msgPtr, gRadiosInfo.radiosInfo[radio].TxQueueLevel); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].wirelessLinkFramesPerSec); // CWDebugLog(""); // CWDebugLog("WTPOperationalStatistics of radio \"%d\": %d - %d", radio,gRadiosInfo.radiosInfo[radio].TxQueueLevel, gRadiosInfo.radiosInfo[radio].wirelessLinkFramesPerSec); CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_OPERAT_STATISTICS_CW_TYPE); return CW_TRUE; } CWBool CWAssembleMsgElemWTPRadioStatistics(CWProtocolMessage * msgPtr, int radio) { const int radio_statistics_length = 20; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (radio < 0 || radio > gRadiosInfo.radioCount) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, radio_statistics_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(msgPtr, radio); CWProtocolStore8(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.lastFailureType); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.resetCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.SWFailureCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.HWFailuireCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.otherFailureCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.unknownFailureCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.configUpdateCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.channelChangeCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.bandChangeCount); CWProtocolStore16(msgPtr, gRadiosInfo.radiosInfo[radio].statistics.currentNoiseFloor); // CWDebugLog(""); // CWDebugLog("WTPRadioStatistics of radio: \"%d\"", radio); // CWDebugLog("WTPRadioStatistics(1): %d - %d - %d", gRadiosInfo.radiosInfo[radio].statistics.lastFailureType, gRadiosInfo.radiosInfo[radio].statistics.resetCount, gRadiosInfo.radiosInfo[radio].statistics.SWFailureCount); // CWDebugLog("WTPRadioStatistics(2): %d - %d - %d", gRadiosInfo.radiosInfo[radio].statistics.HWFailuireCount, gRadiosInfo.radiosInfo[radio].statistics.otherFailureCount, gRadiosInfo.radiosInfo[radio].statistics.unknownFailureCount); // CWDebugLog("WTPRadioStatistics(3): %d - %d - %d - %d", gRadiosInfo.radiosInfo[radio].statistics.configUpdateCount, gRadiosInfo.radiosInfo[radio].statistics.channelChangeCount,gRadiosInfo.radiosInfo[radio].statistics.bandChangeCount,gRadiosInfo.radiosInfo[radio].statistics.currentNoiseFloor); //return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_RADIO_STATISTICS_CW_TYPE); CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_RADIO_STATISTICS_CW_TYPE); return CW_TRUE; } CWBool CWAssembleMsgElemWTPRebootStatistics(CWProtocolMessage * msgPtr) { const int reboot_statistics_length = 15; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, reboot_statistics_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore16(msgPtr, gWTPRebootStatistics.rebootCount); CWProtocolStore16(msgPtr, gWTPRebootStatistics.ACInitiatedCount); CWProtocolStore16(msgPtr, gWTPRebootStatistics.linkFailurerCount); CWProtocolStore16(msgPtr, gWTPRebootStatistics.SWFailureCount); CWProtocolStore16(msgPtr, gWTPRebootStatistics.HWFailuireCount); CWProtocolStore16(msgPtr, gWTPRebootStatistics.otherFailureCount); CWProtocolStore16(msgPtr, gWTPRebootStatistics.unknownFailureCount); CWProtocolStore8(msgPtr, gWTPRebootStatistics.lastFailureType); // CWDebugLog(""); // CWDebugLog("WTPRebootStat(1): %d - %d - %d", gWTPRebootStatistics.rebootCount, gWTPRebootStatistics.ACInitiatedCount, gWTPRebootStatistics.linkFailurerCount); // CWDebugLog("WTPRebootStat(2): %d - %d - %d", gWTPRebootStatistics.SWFailureCount, gWTPRebootStatistics.HWFailuireCount, gWTPRebootStatistics.otherFailureCount); // CWDebugLog("WTPRebootStat(3): %d - %d", gWTPRebootStatistics.unknownFailureCount, gWTPRebootStatistics.lastFailureType); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_WTP_REBOOT_STATISTICS_CW_TYPE); } //test version CWBool CWAssembleMsgElemDuplicateIPv4Address(CWProtocolMessage * msgPtr) { const int duplicate_ipv4_length = 11; unsigned char *macAddress; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, duplicate_ipv4_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog(""); // CWDebugLog("Duplicate IPv4 Address: %d", CWWTPGetIPv4Address()); CWProtocolStore32(msgPtr, CWWTPGetIPv4Address()); CWProtocolStore8(msgPtr, CWWTPGetIPv4StatusDuplicate()); CWProtocolStore8(msgPtr, 6); CW_CREATE_ARRAY_ERR(macAddress, 6, unsigned char, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); macAddress[0] = 103; macAddress[1] = 204; macAddress[2] = 204; macAddress[3] = 190; macAddress[4] = 180; macAddress[5] = 0; CWProtocolStoreRawBytes(msgPtr, macAddress, 6); CW_FREE_OBJECT(macAddress); //CWProtocolStore8(msgPtr, CWWTPGetIPv4StatusDuplicate()); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_DUPLICATE_IPV4_ADDRESS_CW_TYPE); } //test version CWBool CWAssembleMsgElemDuplicateIPv6Address(CWProtocolMessage * msgPtr) { const int duplicate_ipv6_length = 23; unsigned char *macAddress; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); // create message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, duplicate_ipv6_length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog(""); // CWDebugLog("Duplicate IPv6 Address"); struct sockaddr_in6 myAddr; CWWTPGetIPv6Address(&myAddr); CWProtocolStoreRawBytes(msgPtr, myAddr.sin6_addr.s6_addr, 16); CWProtocolStore8(msgPtr, CWWTPGetIPv6StatusDuplicate()); CWProtocolStore8(msgPtr, 6); CW_CREATE_ARRAY_ERR(macAddress, 6, unsigned char, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); macAddress[0] = 103; macAddress[1] = 204; macAddress[2] = 204; macAddress[3] = 190; macAddress[4] = 180; macAddress[5] = 0; CWProtocolStoreRawBytes(msgPtr, macAddress, 6); CW_FREE_OBJECT(macAddress); //CWProtocolStore8(msgPtr, CWWTPGetIPv6StatusDuplicate()); return CWAssembleMsgElem(msgPtr, CW_MSG_ELEMENT_DUPLICATE_IPV6_ADDRESS_CW_TYPE); } CWBool CWAssembleMsgElemRadioAdminState(CWProtocolMessage * msgPtr) { const int radio_Admin_State_Length = 2; CWRadiosAdminInfo infos; CWProtocolMessage *msgs; int len = 0; int i; int j; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!CWGetWTPRadiosAdminState(&infos)) { return CW_FALSE; } CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgs, (infos.radiosCount), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { // create message CW_CREATE_PROTOCOL_MESSAGE(msgs[i], radio_Admin_State_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(&(msgs[i]), infos.radios[i].ID); // ID of the radio CWProtocolStore8(&(msgs[i]), infos.radios[i].state); // state of the radio //CWProtocolStore8(&(msgs[i]), infos.radios[i].cause); if (!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_RADIO_ADMIN_STATE_CW_TYPE))) { for (j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]); } CW_FREE_OBJECT(infos.radios); CW_FREE_OBJECT(msgs); return CW_FALSE; } len += msgs[i].offset; // CWDebugLog("Radio Admin State: %d - %d - %d", infos.radios[i].ID, infos.radios[i].state, infos.radios[i].cause); } CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } CW_FREE_OBJECT(msgs); CW_FREE_OBJECT(infos.radios); return CW_TRUE; } //if radioID is negative return Radio Operational State for all radios CWBool CWAssembleMsgElemRadioOperationalState(int radioID, CWProtocolMessage * msgPtr) { const int radio_Operational_State_Length = 3; CWRadiosOperationalInfo infos; CWProtocolMessage *msgs; int len = 0; int i; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!(CWGetWTPRadiosOperationalState(radioID, &infos))) { return CW_FALSE; } CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgs, (infos.radiosCount), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { // create message CW_CREATE_PROTOCOL_MESSAGE(msgs[i], radio_Operational_State_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(&(msgs[i]), infos.radios[i].ID); // ID of the radio CWProtocolStore8(&(msgs[i]), infos.radios[i].state); // state of the radio CWProtocolStore8(&(msgs[i]), infos.radios[i].cause); if (!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_RADIO_OPERAT_STATE_CW_TYPE))) { int j; for (j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]); } CW_FREE_OBJECT(infos.radios); CW_FREE_OBJECT(msgs); return CW_FALSE; } len += msgs[i].offset; // CWDebugLog("Radio Operational State: %d - %d - %d", infos.radios[i].ID, infos.radios[i].state, infos.radios[i].cause); } CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } CW_FREE_OBJECT(msgs); CW_FREE_OBJECT(infos.radios); return CW_TRUE; } CWBool CWAssembleMsgElemDecryptErrorReport(CWProtocolMessage * msgPtr, int radioID) { int decrypy_Error_Report_Length = 0; CWDecryptErrorReportInfo infos; CWProtocolMessage *msgs; int len = 0; int i; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (!(CWGetDecryptErrorReport(radioID, &infos))) { return CW_FALSE; } CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgs, (infos.radiosCount), return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { // create message decrypy_Error_Report_Length = 2 + sizeof(CWMACAddress) * (infos.radios[i].numEntries); CW_CREATE_PROTOCOL_MESSAGE(msgs[i], decrypy_Error_Report_Length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CWProtocolStore8(&(msgs[i]), infos.radios[i].ID); // ID of the radio CWProtocolStore8(&(msgs[i]), infos.radios[i].numEntries); // state of the radio CWProtocolStore8(&(msgs[i]), (unsigned char)sizeof(CWMACAddress) * (infos.radios[i].numEntries)); CWProtocolStoreRawBytes(&(msgs[i]), (unsigned char *)*(infos.radios[i].decryptErrorMACAddressList), sizeof(CWMACAddress) * (infos.radios[i].numEntries)); /* CWDebugLog("###numEntries = %d", infos.radios[i].numEntries); CWDebugLog("j = %d", sizeof(CWMACAddress)*(infos.radios[i].numEntries)); int j; for (j=(sizeof(CWMACAddress)*(infos.radios[i].numEntries)); j>0; j--) CWDebugLog("##(%d/6) = %d", j, msgs[i].msg[(msgs[i].offset)-j]); */ if (!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_CW_TYPE))) { int j; for (j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]); } for (j = 0; j < infos.radiosCount; j++) { CW_FREE_OBJECT(infos.radios[j].decryptErrorMACAddressList); } CW_FREE_OBJECT(infos.radios); CW_FREE_OBJECT(msgs); return CW_FALSE; } len += msgs[i].offset; // CWDebugLog("Radio Decrypt Error Report of radio \"%d\" = %d", infos.radios[i].ID, infos.radios[i].numEntries); } CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < infos.radiosCount; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } for (i = 0; i < infos.radiosCount; i++) { CW_FREE_OBJECT(infos.radios[i].decryptErrorMACAddressList); } CW_FREE_OBJECT(msgs); CW_FREE_OBJECT(infos.radios); return CW_TRUE; } /* CWBool CWAssembleMsgElemWTPRadioInformation(CWProtocolMessage *msgPtr) { CWProtocolMessage *msgs; CWRadiosInformation infos; int len = 0; int i; if(msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWDebugLog("Assemble WTP Radio Info"); if(!CWWTPGetRadiosInformation(&infos)) { return CW_FALSE; } // create one message element for each radio CW_CREATE_ARRAY_ERR(msgs, (infos.radiosCount), CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); for(i = 0; i < infos.radiosCount; i++) { // create message CW_CREATE_PROTOCOL_MESSAGE(msgs[i], 5, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); CWProtocolStore8(&(msgs[i]), infos.radios[i].ID); // ID of the radio CWProtocolStore32(&(msgs[i]), infos.radios[i].type); // type of the radio CWDebugLog("WTPRadioInformation: %d - %d", infos.radios[i].ID, infos.radios[i].type); if(!(CWAssembleMsgElem(&(msgs[i]), CW_MSG_ELEMENT_WTP_RADIO_INFO_CW_TYPE))) { int j; for(j = i; j >= 0; j--) { CW_FREE_PROTOCOL_MESSAGE(msgs[j]);} CW_FREE_OBJECT(infos.radios); CW_FREE_OBJECT(msgs); return CW_FALSE; } len += msgs[i].offset; } // return all the messages as one big message CW_CREATE_PROTOCOL_MESSAGE(*msgPtr, len, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); for(i = 0; i < infos.radiosCount; i++) { CWProtocolStoreMessage(msgPtr, &(msgs[i])); CW_FREE_PROTOCOL_MESSAGE(msgs[i]); } CW_FREE_OBJECT(msgs); CW_FREE_OBJECT(infos.radios); return CW_TRUE; } */ /*_________________________________________________________________________*/ /* *****************************___PARSE___***************************** */ CWBool CWParseWTPRadioInformation_FromAC(CWProtocolMessage * msgPtr, int len, char *valPtr) { //CWParseMessageElementStart(); CWProtocolRetrieve8(msgPtr); CWProtocolRetrieve8(msgPtr); CWProtocolRetrieve8(msgPtr); CWProtocolRetrieve8(msgPtr); *valPtr = CWProtocolRetrieve8(msgPtr); return CW_TRUE; //CWParseMessageElementEnd(); } CWBool CWParseACDescriptor(CWProtocolMessage * msgPtr, int len, CWACInfoValues * valPtr) { int i = 0, theOffset = 0; CWParseMessageElementStart(); valPtr->stations = CWProtocolRetrieve16(msgPtr); // CWDebugLog("AC Descriptor Stations: %d", valPtr->stations); valPtr->limit = CWProtocolRetrieve16(msgPtr); // CWDebugLog("AC Descriptor Limit: %d", valPtr->limit); valPtr->activeWTPs = CWProtocolRetrieve16(msgPtr); // CWDebugLog("AC Descriptor Active WTPs: %d", valPtr->activeWTPs); valPtr->maxWTPs = CWProtocolRetrieve16(msgPtr); // CWDebugLog("AC Descriptor Max WTPs: %d", valPtr->maxWTPs); valPtr->security = CWProtocolRetrieve8(msgPtr); // CWDebugLog("AC Descriptor Security: %d", valPtr->security); valPtr->RMACField = CWProtocolRetrieve8(msgPtr); // CWDebugLog("AC Descriptor Radio MAC Field: %d", valPtr->security); // valPtr->WirelessField= CWProtocolRetrieve8(msgPtr); // CWDebugLog("AC Descriptor Wireless Field: %d", valPtr->security); CWProtocolRetrieve8(msgPtr); //Reserved valPtr->DTLSPolicy = CWProtocolRetrieve8(msgPtr); // DTLS Policy // CWDebugLog("DTLS Policy: %d", valPtr->DTLSPolicy); valPtr->vendorInfos.vendorInfosCount = 0; theOffset = msgPtr->offset; // see how many vendor ID we have in the message while ((msgPtr->offset - oldOffset) < len) { // oldOffset stores msgPtr->offset's value at the beginning of this function. // See the definition of the CWParseMessageElementStart() macro. int tmp; //CWDebugLog("differenza:%d, offset:%d, oldOffset:%d", (msgPtr->offset-oldOffset), (msgPtr->offset), oldOffset); //id = CWProtocolRetrieve32(msgPtr); // CWDebugLog("ID: %d", id); // ID //type = CWProtocolRetrieve16(msgPtr); // CWDebugLog("TYPE: %d",type); // type tmp = CWProtocolRetrieve16(msgPtr); msgPtr->offset += tmp; // len // CWDebugLog("offset %d", msgPtr->offset); valPtr->vendorInfos.vendorInfosCount++; } msgPtr->offset = theOffset; // actually read each vendor ID CW_CREATE_ARRAY_ERR(valPtr->vendorInfos.vendorInfos, valPtr->vendorInfos.vendorInfosCount, CWACVendorInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // CWDebugLog("len %d", len); // CWDebugLog("vendorInfosCount %d", valPtr->vendorInfos.vendorInfosCount); for (i = 0; i < valPtr->vendorInfos.vendorInfosCount; i++) { // CWDebugLog("vendorInfosCount %d vs %d", i, valPtr->vendorInfos.vendorInfosCount); (valPtr->vendorInfos.vendorInfos)[i].vendorIdentifier = CWProtocolRetrieve32(msgPtr); (valPtr->vendorInfos.vendorInfos)[i].type = CWProtocolRetrieve16(msgPtr); (valPtr->vendorInfos.vendorInfos)[i].length = CWProtocolRetrieve16(msgPtr); (valPtr->vendorInfos.vendorInfos)[i].valuePtr = (int *)(CWProtocolRetrieveRawBytes(msgPtr, (valPtr->vendorInfos.vendorInfos)[i].length)); if ((valPtr->vendorInfos.vendorInfos)[i].valuePtr == NULL) return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); if ((valPtr->vendorInfos.vendorInfos)[i].length == 4) { *((valPtr->vendorInfos.vendorInfos)[i].valuePtr) = ntohl(*((valPtr->vendorInfos.vendorInfos)[i].valuePtr)); } // CWDebugLog("AC Descriptor Vendor ID: %d", (valPtr->vendorInfos.vendorInfos)[i].vendorIdentifier); // CWDebugLog("AC Descriptor Type: %d", (valPtr->vendorInfos.vendorInfos)[i].type); // CWDebugLog("AC Descriptor Value: %d", *((valPtr->vendorInfos.vendorInfos)[i].valuePtr)); } // CWDebugLog("AC Descriptor Out"); CWParseMessageElementEnd(); } CWBool CWParseACIPv4List(CWProtocolMessage * msgPtr, int len, ACIPv4ListValues * valPtr) { int i; CWParseMessageElementStart(); if (len == 0 || ((len % 4) != 0)) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Malformed AC IPv4 List Messame Element"); valPtr->ACIPv4ListCount = (len / 4); CW_CREATE_ARRAY_ERR(valPtr->ACIPv4List, valPtr->ACIPv4ListCount, int, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < valPtr->ACIPv4ListCount; i++) { struct sockaddr_in addr; (valPtr->ACIPv4List)[i] = CWProtocolRetrieve32(msgPtr); CWDebugLog("AC IPv4 List (%d): %d", i+1, (valPtr->ACIPv4List)[i]); addr.sin_addr.s_addr = (valPtr->ACIPv4List)[i]; addr.sin_family = AF_INET; addr.sin_port = 1024; CWUseSockNtop(&addr, CWDebugLog(str); ); } CWParseMessageElementEnd(); } CWBool CWParseACIPv6List(CWProtocolMessage * msgPtr, int len, ACIPv6ListValues * valPtr) { int i; CWParseMessageElementStart(); if (len == 0 || ((len % 16) != 0)) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Malformed AC IPv6 List Messame Element"); valPtr->ACIPv6ListCount = (len / 16); CW_CREATE_ARRAY_ERR(valPtr->ACIPv6List, valPtr->ACIPv6ListCount, struct in6_addr, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < valPtr->ACIPv6ListCount; i++) { struct sockaddr_in6 addr; /* * BUG ML09 * 19/10/2009 - Donato Capitella */ void *ptr; ptr = CWProtocolRetrieveRawBytes(msgPtr, 16); CW_COPY_MEMORY(&((valPtr->ACIPv6List)[i]), ptr, 16); CW_FREE_OBJECT(ptr); CW_COPY_MEMORY(&(addr.sin6_addr), &((valPtr->ACIPv6List)[i]), 16); addr.sin6_family = AF_INET6; addr.sin6_port = htons(CW_CONTROL_PORT); // CWUseSockNtop(&addr, CWDebugLog("AC IPv6 List: %s",str);); } CWParseMessageElementEnd(); } CWBool CWParseDeleteStation(CWProtocolMessage * msgPtr, int len) { int Length = 0; int radioID = 0; unsigned char *StationMacAddress; //CWParseMessageElementStart(); sostituire al posto delle righe successive quando passerò valPtr alla funzione CWarseAddStation /*--------------------------------------------------------------------------------------*/ int oldOffset; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); oldOffset = msgPtr->offset; /*----------------------------------------------------------------------------------*/ radioID = CWProtocolRetrieve8(msgPtr); //CWDebugLog("radio ID %d",radioID); Length = CWProtocolRetrieve8(msgPtr); //CWDebugLog("Length of mac address field %d",Length); StationMacAddress = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, Length); CWDebugLog("DEL MAC: %02X:%02X:%02X:%02X:%02X:%02X", (unsigned char)StationMacAddress[0], (unsigned char)StationMacAddress[1], (unsigned char)StationMacAddress[2], (unsigned char)StationMacAddress[3], (unsigned char)StationMacAddress[4], (unsigned char)StationMacAddress[5]); unsigned char tmp_mac[7]; memcpy(tmp_mac + 1, StationMacAddress, 6); CWWTPsend_command_to_hostapd_DEL_ADDR(tmp_mac, 7); CWDebugLog("STATION'S MAC ADDRESS TO FORWARD TRAFFIC: %02X:%02X:%02X:%02X:%02X:%02X", StationMacAddress[0] & 0xFF, StationMacAddress[1] & 0xFF, StationMacAddress[2] & 0xFF, StationMacAddress[3] & 0xFF, StationMacAddress[4] & 0xFF, StationMacAddress[5] & 0xFF); CWParseMessageElementEnd(); } CWBool CWParseDeleteWLAN(CWProtocolMessage * msgPtr, int len) { //CWParseMessageElementStart(); sostituire al posto delle righe successive quando passerò valPtr alla funzione CWarseAddStation /*--------------------------------------------------------------------------------------*/ int oldOffset; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); oldOffset = msgPtr->offset; /*----------------------------------------------------------------------------------*/ CWProtocolRetrieve8(msgPtr); CWProtocolRetrieve8(msgPtr); unsigned char tmp_ssid[3]; CWWTPsend_command_to_hostapd_DEL_WLAN(tmp_ssid, 3); CWParseMessageElementEnd(); } CWBool CWParseAddWLAN(CWProtocolMessage * msgPtr, int len) { CWDebugLog("CWParseAddWLAN() 1"); unsigned char *ssid; unsigned char tmp_buf[len + 1]; //CWParseMessageElementStart(); sostituire al posto delle righe successive quando passerò valPtr alla funzione CWarseAddStation /*--------------------------------------------------------------------------------------*/ int oldOffset; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); oldOffset = msgPtr->offset; /*----------------------------------------------------------------------------------*/ CWDebugLog("CWParseAddWLAN() 2"); tmp_buf[1] = CWProtocolRetrieve8(msgPtr); tmp_buf[2] = CWProtocolRetrieve8(msgPtr); tmp_buf[3] = CWProtocolRetrieve8(msgPtr); tmp_buf[4] = CWProtocolRetrieve8(msgPtr); tmp_buf[5] = CWProtocolRetrieve8(msgPtr); tmp_buf[6] = CWProtocolRetrieve8(msgPtr); unsigned short keyLength = CWProtocolRetrieve16(msgPtr); CWDebugLog("CWParseAddWLAN() 3, %d, %d", len, keyLength); tmp_buf[7] = keyLength >> 8; tmp_buf[8] = keyLength & 0xff; CWDebugLog("CWParseAddWLAN() 4"); if (keyLength) { unsigned char *key; CWDebugLog("CWParseAddWLAN() 5"); key = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, keyLength); CWDebugLog("CWParseAddWLAN() 6 %d", keyLength); memcpy(tmp_buf + 9, key, keyLength); CWDebugLog("CWParseAddWLAN() 7"); } CWDebugLog("CWParseAddWLAN() 5"); tmp_buf[9 + keyLength] = CWProtocolRetrieve8(msgPtr); CWDebugLog("CWParseAddWLAN() 6"); tmp_buf[10 + keyLength] = CWProtocolRetrieve8(msgPtr); CWDebugLog("CWParseAddWLAN() 7"); tmp_buf[11 + keyLength] = CWProtocolRetrieve8(msgPtr); CWDebugLog("CWParseAddWLAN() 8"); tmp_buf[12 + keyLength] = CWProtocolRetrieve8(msgPtr); tmp_buf[13 + keyLength] = CWProtocolRetrieve8(msgPtr); tmp_buf[14 + keyLength] = CWProtocolRetrieve8(msgPtr); CWDebugLog("CWParseAddWLAN() 4"); tmp_buf[15 + keyLength] = CWProtocolRetrieve8(msgPtr); tmp_buf[16 + keyLength] = CWProtocolRetrieve8(msgPtr); /* Auth Type */ tmp_buf[17 + keyLength] = gWTPMACMode = CWProtocolRetrieve8(msgPtr); /* MAC Mode */ tmp_buf[18 + keyLength] = gWTPTunnelMode = CWProtocolRetrieve8(msgPtr); /* Tunnel Mode */ tmp_buf[19 + keyLength] = CWProtocolRetrieve8(msgPtr); /* Suppress SSID */ CWDebugLog("CWParseAddWLAN() 5"); ssid = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, len - (19 + keyLength)); CWDebugLog("CWParseAddWLAN() 6"); memcpy(tmp_buf + 20 + keyLength, ssid, len - 19 - keyLength); CWDebugLog("CWParseAddWLAN() 7"); CWWTPsend_command_to_hostapd_ADD_WLAN(tmp_buf, len + 1); CWParseMessageElementEnd(); } CWBool CWParseAddStation(CWProtocolMessage * msgPtr, int len) { int Length; int radioID; unsigned char *StationMacAddress; //CWParseMessageElementStart(); sostituire al posto delle righe successive quando passerò valPtr alla funzione CWarseAddStation /*--------------------------------------------------------------------------------------*/ int oldOffset; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); oldOffset = msgPtr->offset; /*----------------------------------------------------------------------------------*/ radioID = CWProtocolRetrieve8(msgPtr); CWDebugLog("radio ID %d",radioID); Length = CWProtocolRetrieve8(msgPtr); CWDebugLog("Length of mac address field %d",Length); StationMacAddress = (unsigned char *)CWProtocolRetrieveRawBytes(msgPtr, Length); CWDebugLog("ADD MAC: %02X:%02X:%02X:%02X:%02X:%02X", (unsigned char)StationMacAddress[0], (unsigned char)StationMacAddress[1], (unsigned char)StationMacAddress[2], (unsigned char)StationMacAddress[3], (unsigned char)StationMacAddress[4], (unsigned char)StationMacAddress[5]); unsigned char tmp_mac[7]; memcpy(tmp_mac + 1, StationMacAddress, 6); CWWTPsend_command_to_hostapd_SET_ADDR(tmp_mac, 7); CWDebugLog("STATION'S MAC ADDRESS TO FORWARD TRAFFIC: %02X:%02X:%02X:%02X:%02X:%02X", StationMacAddress[0] & 0xFF, StationMacAddress[1] & 0xFF, StationMacAddress[2] & 0xFF, StationMacAddress[3] & 0xFF, StationMacAddress[4] & 0xFF, StationMacAddress[5] & 0xFF); CWParseMessageElementEnd(); } CWBool CWParseCWControlIPv4Addresses(CWProtocolMessage * msgPtr, int len, CWProtocolIPv4NetworkInterface * valPtr) { CWParseMessageElementStart(); valPtr->addr.sin_addr.s_addr = htonl(CWProtocolRetrieve32(msgPtr)); valPtr->addr.sin_family = AF_INET; valPtr->addr.sin_port = htons(CW_CONTROL_PORT); CWUseSockNtop((&(valPtr->addr)), CWDebugLog("Interface Address: %s", str); ); valPtr->WTPCount = CWProtocolRetrieve16(msgPtr); CWDebugLog("WTP Count: %d", valPtr->WTPCount); CWParseMessageElementEnd(); } CWBool CWParseCWControlIPv6Addresses(CWProtocolMessage * msgPtr, int len, CWProtocolIPv6NetworkInterface * valPtr) { CWParseMessageElementStart(); CW_COPY_MEMORY(&(valPtr->addr.sin6_addr), CWProtocolRetrieveRawBytes(msgPtr, 16), 16); valPtr->addr.sin6_family = AF_INET6; valPtr->addr.sin6_port = htons(CW_CONTROL_PORT); CWUseSockNtop((&(valPtr->addr)), CWDebugLog("Interface Address: %s", str); ); valPtr->WTPCount = CWProtocolRetrieve16(msgPtr); // CWDebugLog("WTP Count: %d", valPtr->WTPCount); CWParseMessageElementEnd(); } CWBool CWParseCWTimers(CWProtocolMessage * msgPtr, int len, CWProtocolConfigureResponseValues * valPtr) { CWParseMessageElementStart(); valPtr->discoveryTimer = CWProtocolRetrieve8(msgPtr); // CWDebugLog("Discovery Timer: %d", valPtr->discoveryTimer); valPtr->echoRequestTimer = CWProtocolRetrieve8(msgPtr); // CWDebugLog("Echo Timer: %d", valPtr->echoRequestTimer); CWParseMessageElementEnd(); } CWBool CWParseDecryptErrorReportPeriod(CWProtocolMessage * msgPtr, int len, WTPDecryptErrorReportValues * valPtr) { CWParseMessageElementStart(); valPtr->radioID = CWProtocolRetrieve8(msgPtr); valPtr->reportInterval = CWProtocolRetrieve16(msgPtr); // CWDebugLog("Decrypt Error Report Period: %d - %d", valPtr->radioID, valPtr->reportInterval); CWParseMessageElementEnd(); } CWBool CWParseIdleTimeout(CWProtocolMessage * msgPtr, int len, CWProtocolConfigureResponseValues * valPtr) { CWParseMessageElementStart(); valPtr->idleTimeout = CWProtocolRetrieve32(msgPtr); // CWDebugLog("Idle Timeout: %d", valPtr->idleTimeout); CWParseMessageElementEnd(); } CWBool CWParseWTPFallback(CWProtocolMessage * msgPtr, int len, CWProtocolConfigureResponseValues * valPtr) { CWParseMessageElementStart(); valPtr->fallback = CWProtocolRetrieve8(msgPtr); // CWDebugLog("WTP Fallback: %d", valPtr->fallback); CWParseMessageElementEnd(); } void CWWTPResetRebootStatistics(WTPRebootStatisticsInfo * rebootStatistics) { rebootStatistics->rebootCount = 0; rebootStatistics->ACInitiatedCount = 0; rebootStatistics->linkFailurerCount = 0; rebootStatistics->SWFailureCount = 0; rebootStatistics->HWFailuireCount = 0; rebootStatistics->otherFailureCount = 0; rebootStatistics->unknownFailureCount = 0; rebootStatistics->lastFailureType = NOT_SUPPORTED; } ================================================ FILE: WTPProtocol.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_WTPProtocol_HEADER__ #define __CAPWAP_WTPProtocol_HEADER__ /*_____________________________________________________*/ /* *******************___TYPES___******************* */ typedef struct { int ACIPv4ListCount; int *ACIPv4List; } ACIPv4ListValues; typedef struct { int ACIPv6ListCount; struct in6_addr *ACIPv6List; } ACIPv6ListValues; typedef struct { int stations; int limit; int activeWTPs; int maxWTPs; CWAuthSecurity security; int RMACField; // int WirelessField; int DTLSPolicy; CWACVendorInfos vendorInfos; char *name; CWProtocolIPv4NetworkInterface *IPv4Addresses; int IPv4AddressesCount; CWProtocolIPv6NetworkInterface *IPv6Addresses; int IPv6AddressesCount; ACIPv4ListValues ACIPv4ListInfo; ACIPv6ListValues ACIPv6ListInfo; CWNetworkLev4Address preferredAddress; CWNetworkLev4Address incomingAddress; } CWACInfoValues; typedef struct { CWACInfoValues ACInfoPtr; CWProtocolResultCode code; ACIPv4ListValues ACIPv4ListInfo; ACIPv6ListValues ACIPv6ListInfo; } CWProtocolJoinResponseValues; typedef struct { ACIPv4ListValues ACIPv4ListInfo; ACIPv6ListValues ACIPv6ListInfo; int discoveryTimer; int echoRequestTimer; int radioOperationalInfoCount; CWRadioOperationalInfoValues *radioOperationalInfo; WTPDecryptErrorReport radiosDecryptErrorPeriod; int idleTimeout; int fallback; void *bindingValues; } CWProtocolConfigureResponseValues; typedef struct { void *bindingValues; /*Update 2009: add new non-binding specific values */ void *protocolValues; } CWProtocolConfigurationUpdateRequestValues; /*__________________________________________________________*/ /* *******************___PROTOTYPES___******************* */ CWBool CWAssembleMsgElemACName(CWProtocolMessage * msgPtr); // 4 CWBool CWAssembleMsgElemACNameWithIndex(CWProtocolMessage * msgPtr); // 5 CWBool CWAssembleMsgElemDataTransferData(CWProtocolMessage * msgPtr, int data_type); //13 CWBool CWAssembleMsgElemDiscoveryType(CWProtocolMessage * msgPtr); //20 CWBool CWAssembleMsgElemDuplicateIPv4Address(CWProtocolMessage * msgPtr); //21 CWBool CWAssembleMsgElemLocationData(CWProtocolMessage * msgPtr); //27 CWBool CWAssembleMsgElemStatisticsTimer(CWProtocolMessage * msgPtr); //33 CWBool CWAssembleMsgElemWTPBoardData(CWProtocolMessage * msgPtr); //35 CWBool CWAssembleMsgElemWTPDescriptor(CWProtocolMessage * msgPtr); //36 CWBool CWAssembleMsgElemWTPFrameTunnelMode(CWProtocolMessage * msgPtr); //38 CWBool CWAssembleMsgElemWTPIPv4Address(CWProtocolMessage * msgPtr); //39 CWBool CWAssembleMsgElemWTPMACType(CWProtocolMessage * msgPtr); //40 CWBool CWAssembleMsgElemWTPRadioInformation(CWProtocolMessage * msgPtr); //1048 CWBool CWAssembleMsgElemSupportedRates(CWProtocolMessage * msgPtr); //1040 CWBool CWAssembleMsgElemMultiDomainCapability(CWProtocolMessage * msgPtr); //1032 CWBool CWAssembleMsgElemWTPName(CWProtocolMessage * msgPtr); //41 CWBool CWAssembleMsgElemWTPOperationalStatistics(CWProtocolMessage * msgPtr, int radio); //42 CWBool CWAssembleMsgElemWTPRadioStatistics(CWProtocolMessage * msgPtr, int radio); //43 CWBool CWAssembleMsgElemWTPRebootStatistics(CWProtocolMessage * msgPtr); //44 //CWBool CWAssembleMsgElemWTPStaticIPInfo(CWProtocolMessage *msgPtr); //45 //CWBool CWAssembleMsgElemWTPRadioInformation(CWProtocolMessage *msgPtr); //---------------------------------------------------------/ CWBool CWParseACDescriptor(CWProtocolMessage * msgPtr, int len, CWACInfoValues * valPtr); // 1 CWBool CWParseACIPv4List(CWProtocolMessage * msgPtr, int len, ACIPv4ListValues * valPtr); // 2 CWBool CWParseACIPv6List(CWProtocolMessage * msgPtr, int len, ACIPv6ListValues * valPtr); // 3 CWBool CWParseAddStation(CWProtocolMessage * msgPtr, int len); // 8 CWBool CWParseDeleteStation(CWProtocolMessage * msgPtr, int len); // 18 CWBool CWParseCWControlIPv4Addresses(CWProtocolMessage * msgPtr, int len, CWProtocolIPv4NetworkInterface * valPtr); //10 CWBool CWParseCWControlIPv6Addresses(CWProtocolMessage * msgPtr, int len, CWProtocolIPv6NetworkInterface * valPtr); //11 CWBool CWParseCWTimers(CWProtocolMessage * msgPtr, int len, CWProtocolConfigureResponseValues * valPtr); //12 CWBool CWParseDecryptErrorReportPeriod(CWProtocolMessage * msgPtr, int len, WTPDecryptErrorReportValues * valPtr); //16 CWBool CWParseIdleTimeout(CWProtocolMessage * msgPtr, int len, CWProtocolConfigureResponseValues * valPtr); //26 CWBool CWParseWTPFallback(CWProtocolMessage * msgPtr, int len, CWProtocolConfigureResponseValues * valPtr); //37 CWBool CWParseWTPRadioInformation_FromAC(CWProtocolMessage * msgPtr, int len, char *valPtr); // 1048 //si trova in CWProtocol.h //CWBool CWParseACName(CWProtocolMessage *msgPtr, int len, char **valPtr); // 4 //---------------------------------------------------------/ void CWWTPResetRebootStatistics(WTPRebootStatisticsInfo * rebootStatistics); int CWWTPGetDiscoveryType(void); int CWWTPGetMaxRadios(void); int CWWTPGetRadiosInUse(void); CWBool CWWTPGetEncCapabilities(CWWTPEncryptCaps * encc); void CWWTPDestroyEncCapabilities(CWWTPEncryptCaps * encc); CWBool CWWTPGetBoardData(CWWTPVendorInfos * valPtr); CWBool CWWTPGetVendorInfos(CWWTPVendorInfos * valPtr); int CWWTPGetMACType(void); char *CWWTPGetLocation(void); int CWWTPGetSessionID(void); int CWWTPGetIPv4Address(void); int CWWTPGetIPv4StatusDuplicate(void); int CWWTPGetIPv6StatusDuplicate(void); char *CWWTPGetName(void); CWBool CWWTPGetRadiosInformation(CWRadiosInformation * valPtr); int CWWTPGetACIndex(); char *CWWTPGetACName(); int CWWTPGetFrameTunnelMode(); CWBool CWGetWTPRadiosOperationalState(int radioID, CWRadiosOperationalInfo * valPtr); CWBool CWAssembleMsgElemDecryptErrorReport(CWProtocolMessage * msgPtr, int radioID); CWBool CWAssembleMsgElemDuplicateIPv6Address(CWProtocolMessage * msgPtr); CWBool CWAssembleMsgElemVendorSpecificPayload(CWProtocolMessage * msgPtr); CWBool CWParseAddWLAN(CWProtocolMessage * msgPtr, int len); CWBool CWParseDeleteWLAN(CWProtocolMessage * msgPtr, int len); //---------------------------------------------------------/ void CWWTPDestroyVendorInfos(CWWTPVendorInfos * valPtr); #endif ================================================ FILE: WTPProtocol_User.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #define MAC_ADDR_LEN 6 #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif __inline__ int CWWTPGetDiscoveryType() { return CW_MSG_ELEMENT_DISCOVERY_TYPE_CONFIGURED; } __inline__ int CWWTPGetMaxRadios() { return 1; } __inline__ int CWWTPGetRadiosInUse() { /*for (i=0; iencryptCapsCount = 1; CW_CREATE_ARRAY_ERR((encc->encryptCaps), encc->encryptCapsCount, CWWTPEncryptCapValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (encc->encryptCaps)[0].WBID = 1; (encc->encryptCaps)[0].encryptionCapabilities = 2569; return CW_TRUE; } void CWWTPDestroyEncCapabilities(CWWTPEncryptCaps * encc) { if (encc == NULL) return; CW_FREE_OBJECT(encc->encryptCaps); } CWBool CWWTPGetBoardData(CWWTPVendorInfos * valPtr) { if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); valPtr->vendorInfosCount = 2; // we fill 2 information (just the required ones) CW_CREATE_ARRAY_ERR((valPtr->vendorInfos), valPtr->vendorInfosCount, CWWTPVendorInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") (valPtr->vendorInfos)[0].vendorIdentifier = 23456; (valPtr->vendorInfos)[0].type = CW_WTP_MODEL_NUMBER; (valPtr->vendorInfos)[0].length = sizeof(long int); // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[0]).valuePtr), (valPtr->vendorInfos)[0].length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(int *)(((valPtr->vendorInfos)[0]).valuePtr) = 123456; // MODEL NUMBER // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") (valPtr->vendorInfos)[1].vendorIdentifier = 23456; (valPtr->vendorInfos)[1].type = CW_WTP_SERIAL_NUMBER; (valPtr->vendorInfos)[1].length = sizeof(long int); // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[1]).valuePtr), (valPtr->vendorInfos)[1].length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(int *)(((valPtr->vendorInfos)[1]).valuePtr) = 123456; // SERIAL NUMBER return CW_TRUE; } CWBool CWWTPGetVendorInfos(CWWTPVendorInfos * valPtr) { if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); valPtr->vendorInfosCount = 3; // we fill 3 information (just the required ones) CW_CREATE_ARRAY_ERR((valPtr->vendorInfos), valPtr->vendorInfosCount, CWWTPVendorInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") (valPtr->vendorInfos)[0].vendorIdentifier = 23456; (valPtr->vendorInfos)[0].type = CW_WTP_HARDWARE_VERSION; (valPtr->vendorInfos)[0].length = sizeof(long int); // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[0]).valuePtr), (valPtr->vendorInfos)[0].length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(int *)(((valPtr->vendorInfos)[0]).valuePtr) = 123456; // HW version // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") ((valPtr->vendorInfos)[1]).vendorIdentifier = 23456; ((valPtr->vendorInfos)[1]).type = CW_WTP_SOFTWARE_VERSION; ((valPtr->vendorInfos)[1]).length = sizeof(long int); // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[1]).valuePtr), (valPtr->vendorInfos)[1].length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(int *)(((valPtr->vendorInfos)[1]).valuePtr) = 12347; // SW version // my vendor identifier (IANA assigned "SMI Network Management Private Enterprise Code") (valPtr->vendorInfos)[2].vendorIdentifier = 23456; (valPtr->vendorInfos)[2].type = CW_BOOT_VERSION; (valPtr->vendorInfos)[2].length = sizeof(long int); // just one int CW_CREATE_OBJECT_SIZE_ERR((((valPtr->vendorInfos)[2]).valuePtr), (valPtr->vendorInfos)[2].length, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); *(int *)(((valPtr->vendorInfos)[2]).valuePtr) = 1234568; // Boot version return CW_TRUE; } __inline__ void CWWTPDestroyVendorInfos(CWWTPVendorInfos * valPtr) { int i; if (valPtr == NULL) return; for (i = 0; i < valPtr->vendorInfosCount; i++) { CW_FREE_OBJECT((valPtr->vendorInfos)[i].valuePtr); } CW_FREE_OBJECT(valPtr->vendorInfos); } __inline__ int CWWTPGetFrameTunnelMode() { //it may be also 802.3_FrameTunnelMode - NativeFrameTunnelMode - All #ifdef SOFTMAC return CW_NATIVE_BRIDGING | CW_802_DOT_3_BRIDGING; #else return CW_LOCAL_BRIDGING; #endif } __inline__ int CWWTPGetMACType() { #ifdef SOFTMAC return CW_BOTH; #else return CW_LOCAL_MAC; #endif } __inline__ char *CWWTPGetLocation() { return gWTPLocation; } __inline__ int CWWTPGetSessionID() { return CWRandomIntInRange(0, INT_MAX); } __inline__ int CWWTPGetIPv4Address() { struct sockaddr_in myAddr; unsigned int len = sizeof(myAddr); //CWDebugLog("WTPGetIPv4Address"); /* assume the socket is connected */ getsockname(gWTPSocket, (struct sockaddr *)&myAddr, &len); return ntohl(myAddr.sin_addr.s_addr); // TO-DO: this is garbage if we are an IPv6 client } __inline__ void CWWTPGetIPv6Address(struct sockaddr_in6 *myAddr) { unsigned int len = sizeof(*myAddr); /* assume the socket is connected */ getsockname(gWTPSocket, (struct sockaddr *)myAddr, &len); } __inline__ int CWWTPGetIPv4StatusDuplicate() { return gIPv4StatusDuplicate; } __inline__ int CWWTPGetIPv6StatusDuplicate() { return gIPv6StatusDuplicate; } __inline__ char *CWWTPGetName() { return gWTPName; } /*CWBool CWWTPGetRadiosInformation(CWRadiosInformation *valPtr) { if(valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); valPtr->radiosCount = 2; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioInformationValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); (valPtr->radios)[0].ID = 0; // first radio (valPtr->radios)[0].type = CW_802_DOT_11b; (valPtr->radios)[1].ID = 1; // second radio (valPtr->radios)[1].type = CW_802_DOT_11b; return CW_TRUE; } */ /* L'AC ha la funzione ridefinita */ CWBool CWGetWTPRadiosAdminState(CWRadiosAdminInfo * valPtr) { int i; if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); valPtr->radiosCount = gRadiosInfo.radioCount; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioAdminInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < gRadiosInfo.radioCount; i++) { (valPtr->radios)[i].ID = gRadiosInfo.radiosInfo[i].radioID; // first radio (valPtr->radios)[i].state = gRadiosInfo.radiosInfo[i].adminState; (valPtr->radios)[i].cause = gRadiosInfo.radiosInfo[i].adminCause; } return CW_TRUE; } CWBool CWGetWTPRadiosOperationalState(int radioID, CWRadiosOperationalInfo * valPtr) { int i; CWBool found = CW_FALSE; if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); if (radioID < 0) { valPtr->radiosCount = gRadiosInfo.radioCount; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < gRadiosInfo.radioCount; i++) { (valPtr->radios)[i].ID = gRadiosInfo.radiosInfo[i].radioID; (valPtr->radios)[i].state = gRadiosInfo.radiosInfo[i].operationalState; (valPtr->radios)[i].cause = gRadiosInfo.radiosInfo[i].operationalCause; } return CW_TRUE; } else { for (i = 0; i < gRadiosInfo.radioCount; i++) { if (gRadiosInfo.radiosInfo[i].radioID == radioID) { found = CW_TRUE; valPtr->radiosCount = 1; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWRadioOperationalInfoValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (valPtr->radios)[0].ID = gRadiosInfo.radiosInfo[i].radioID; (valPtr->radios)[0].state = gRadiosInfo.radiosInfo[i].operationalState; (valPtr->radios)[0].cause = gRadiosInfo.radiosInfo[i].operationalCause; break; } } return found; } } CWBool CWGetDecryptErrorReport(int radioID, CWDecryptErrorReportInfo * valPtr) { int i; CWBool found = CW_FALSE; /* CWMACAddress add, add2; for(i=0; i<6; i++) add[i]=i; for(i=0; i<6; i++) add2[i]=99; CWListElement elem,elem2; elem.data = add; elem.next = &elem2; elem2.data = &add2; elem2.next = NULL; gRadiosInfo.radiosInfo[0].decryptErrorMACAddressList = &elem; */ if (valPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); valPtr->radios = NULL; if (radioID < 0) { valPtr->radiosCount = gRadiosInfo.radioCount; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWDecryptErrorReportValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); for (i = 0; i < gRadiosInfo.radioCount; i++) { (valPtr->radios)[i].ID = gRadiosInfo.radiosInfo[i].radioID; (valPtr->radios)[i].numEntries = CWCountElementInList(gRadiosInfo.radiosInfo[i].decryptErrorMACAddressList); (valPtr->radios[i]).decryptErrorMACAddressList = NULL; CW_CREATE_ARRAY_ERR((valPtr->radios[i]).decryptErrorMACAddressList, (valPtr->radios[i]).numEntries, CWMACAddress, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); int j; CWListElement *temp; temp = gRadiosInfo.radiosInfo[i].decryptErrorMACAddressList; for (j = 0; j < (valPtr->radios[i]).numEntries; j++) { CW_COPY_MEMORY((valPtr->radios[i]).decryptErrorMACAddressList[j], temp->data, sizeof(CWMACAddress)); temp = temp->next; } } return CW_TRUE; } else { for (i = 0; i < gRadiosInfo.radioCount; i++) { if (gRadiosInfo.radiosInfo[i].radioID == radioID) { found = CW_TRUE; valPtr->radiosCount = 1; CW_CREATE_ARRAY_ERR(valPtr->radios, valPtr->radiosCount, CWDecryptErrorReportValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (valPtr->radios)[0].ID = gRadiosInfo.radiosInfo[i].radioID; (valPtr->radios)[0].numEntries = CWCountElementInList(gRadiosInfo.radiosInfo[i].decryptErrorMACAddressList); (valPtr->radios[0]).decryptErrorMACAddressList = NULL; CW_CREATE_ARRAY_ERR((valPtr->radios[0]).decryptErrorMACAddressList, (valPtr->radios[0]).numEntries, CWMACAddress, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); int j; CWListElement *temp; temp = gRadiosInfo.radiosInfo[0].decryptErrorMACAddressList; for (j = 0; j < (valPtr->radios[0]).numEntries; j++) { CW_COPY_MEMORY((valPtr->radios[0]).decryptErrorMACAddressList[j], temp->data, 6); temp = temp->next; } } } return found; } } int CWWTPGetACIndex() { return 1; //valore predefinito } char *CWWTPGetACName() { return gACInfoPtr->name; } int CWWTPGetStatisticsTimer() { return gWTPStatisticsTimer; } CWBool CWWTPGetACNameWithIndex(CWACNamesWithIndex * ACsInfo) { if (ACsInfo == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); ACsInfo->count = 2; CW_CREATE_ARRAY_ERR(ACsInfo->ACNameIndex, ACsInfo->count, CWACNameWithIndexValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (ACsInfo->ACNameIndex)[0].index = 0; // first radio CW_CREATE_STRING_FROM_STRING_ERR((ACsInfo->ACNameIndex)[0].ACName, "ACPrimary", return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); (ACsInfo->ACNameIndex)[1].index = 1; // first radio CW_CREATE_STRING_FROM_STRING_ERR((ACsInfo->ACNameIndex)[1].ACName, "ACSecondary", return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); );; return CW_TRUE; } int getInterfaceMacAddr(char *interface, unsigned char *macAddr) { struct ifreq ethreq; int i, sock; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { CWLog("Error Creating Socket for ioctl"); return -1; } memset(ðreq, 0, sizeof(ethreq)); strncpy(ethreq.ifr_name, interface, IFNAMSIZ); if (ioctl(sock, SIOCGIFHWADDR, ðreq) == -1) { return -1; } for (i = 0; i < MAC_ADDR_LEN; i++) { macAddr[i] = (unsigned char)ethreq.ifr_hwaddr.sa_data[i]; } return 0; } int initWTPSessionID(unsigned char *sessionID) { unsigned char macAddr0[MAC_ADDR_LEN]; unsigned char macAddr1[MAC_ADDR_LEN]; int i, randomInteger; unsigned char *buffer = sessionID; getInterfaceMacAddr(gEthInterfaceName, macAddr0); getInterfaceMacAddr(gRadioInterfaceName_0, macAddr1); randomInteger = CWRandomIntInRange(0, INT_MAX); randomInteger = htonl(randomInteger); CW_COPY_MEMORY(sessionID, macAddr0, MAC_ADDR_LEN); CW_COPY_MEMORY(&(sessionID[MAC_ADDR_LEN]), macAddr1, MAC_ADDR_LEN); CW_COPY_MEMORY(&(sessionID[MAC_ADDR_LEN + MAC_ADDR_LEN]), &(randomInteger), 4); for (i = 0; i < 16; i++) { if (i % 16 == 0) printf("\n%04x: ", i); printf("%02x:", buffer[i]); } printf("\n"); return 0; } ================================================ FILE: WTPRetransmission.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif void CWResetPendingMsgBox(CWPendingRequestMessage * pendingRequestMsgs) { pendingRequestMsgs->msgType = UNUSED_MSG_TYPE; pendingRequestMsgs->seqNum = 0; pendingRequestMsgs->retransmission = 0; pendingRequestMsgs->timer_sec = 0; pendingRequestMsgs->timer_hdl = NULL; CW_FREE_OBJECT(pendingRequestMsgs->timer_arg); pendingRequestMsgs->timer_arg = NULL; timer_rem(pendingRequestMsgs->timer, NULL); int i; for (i = 0; i < (pendingRequestMsgs->fragmentsNum); i++) { CW_FREE_PROTOCOL_MESSAGE((pendingRequestMsgs->msgElems)[i]); } CW_FREE_OBJECT(pendingRequestMsgs->msgElems); pendingRequestMsgs->fragmentsNum = 0; return; } int CWFindFreePendingMsgBox(CWPendingRequestMessage * pendingRequestMsgs, const int length) { int k; for (k = 0; k < length; k++) { if (pendingRequestMsgs[k].msgType == UNUSED_MSG_TYPE) { CWResetPendingMsgBox(pendingRequestMsgs + k); return k; } } return -1; } CWBool CWUpdatePendingMsgBox(CWPendingRequestMessage * pendingRequestMsgs, unsigned char msgType, int seqNum, int timer_sec, CWTimerArg timer_arg, void (*timer_hdl) (CWTimerArg), int retransmission, CWProtocolMessage * msgElems, int fragmentsNum) { if (pendingRequestMsgs == NULL) return CW_FALSE; if (pendingRequestMsgs->msgType != UNUSED_MSG_TYPE) return CW_TRUE; pendingRequestMsgs->msgType = msgType; pendingRequestMsgs->seqNum = seqNum; pendingRequestMsgs->retransmission = retransmission; pendingRequestMsgs->msgElems = msgElems; pendingRequestMsgs->fragmentsNum = fragmentsNum; pendingRequestMsgs->timer_sec = timer_sec; pendingRequestMsgs->timer_hdl = timer_hdl; pendingRequestMsgs->timer_arg = timer_arg; if ((pendingRequestMsgs->timer = timer_add(timer_sec, 0, timer_hdl, timer_arg))) { return CW_FALSE; } return CW_TRUE; } int CWFindPendingRequestMsgsBox(CWPendingRequestMessage * pendingRequestMsgs, const int length, const int msgType, const int seqNum) { if (pendingRequestMsgs == NULL) return -1; /* CWDebugLog("### TYPE = %d SEQNUM = %d", msgType, seqNum); */ int k; for (k = 0; k < length; k++) { /* CWDebugLog("### K = %d TYPE = %d SEQNUM = %d", k, pendingRequestMsgs[k].msgType, pendingRequestMsgs[k].seqNum); */ if ((pendingRequestMsgs[k].seqNum == seqNum) && (pendingRequestMsgs[k].msgType == msgType)) { timer_rem(pendingRequestMsgs[k].timer, NULL); return k; } } return -1; } int CWSendPendingRequestMessage(CWPendingRequestMessage * pendingRequestMsgs, CWProtocolMessage * messages, int fragmentsNum) { int pendingReqIndex = -1; if (messages == NULL || fragmentsNum < 0) { return -1; } pendingReqIndex = CWFindFreePendingMsgBox(pendingRequestMsgs, MAX_PENDING_REQUEST_MSGS); if (pendingReqIndex < 0) { return -1; } int i; for (i = 0; i < fragmentsNum; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected(gWTPSocket, messages[i].msg, messages[i].offset)) { #else if (!CWSecuritySend(gWTPSession, messages[i].msg, messages[i].offset)) { #endif return -1; } } return pendingReqIndex; } ================================================ FILE: WTPRunState.c ================================================ /************************************************************************************************ * Copyright (c) 2006-2009 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * -------------------------------------------------------------------------------------------- * * Project: Capwap * * * * Authors : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * * Antonio Davoli (antonio.davoli@gmail.com) * ************************************************************************************************/ #include #include #include #include #include #include #include "CWWTP.h" #include "CWVendorPayloads.h" #include "WTPipcHostapd.h" #include "WTPmacFrameReceive.h" #include "common.h" #include "ieee802_11_defs.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif CWBool CWWTPManageGenericRunMessage(CWProtocolMessage * msgPtr); CWBool CWWTPCheckForBindingFrame(); CWBool CWWTPCheckForWTPEventRequest(); CWBool CWParseWTPEventResponseMessage(unsigned char *msg, int len, int seqNum, void *values); CWBool CWSaveWTPEventResponseMessage(void *WTPEventResp); CWBool CWAssembleEchoRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList); CWBool CWParseConfigurationUpdateRequest(unsigned char *msg, int len, CWProtocolConfigurationUpdateRequestValues * valuesPtr, int *updateRequestType); CWBool CWSaveConfigurationUpdateRequest(CWProtocolConfigurationUpdateRequestValues * valuesPtr, CWProtocolResultCode * resultCode, int *updateRequestType); CWBool CWAssembleConfigurationUpdateResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode, CWProtocolConfigurationUpdateRequestValues values); CWBool CWSaveClearConfigurationRequest(CWProtocolResultCode * resultCode); CWBool CWAssembleClearConfigurationResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode); CWBool CWAssembleStationConfigurationResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode); CWBool CWAssembleWLANConfigurationResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode); CWBool CWParseStationConfigurationRequest(unsigned char *msg, int len); CWBool CWParseWLANConfigurationRequest(unsigned char *msg, int len); void CWConfirmRunStateToACWithEchoRequest(); void CWWTPKeepAliveDataTimerExpiredHandler(void *arg); CWTimerID gCWHeartBeatTimerID; CWTimerID gCWKeepAliveTimerID; CWTimerID gCWNeighborDeadTimerID; CWBool gNeighborDeadTimerSet = CW_FALSE; int gEchoInterval = CW_ECHO_INTERVAL_DEFAULT; int gDataChannelKeepAlive = CW_DATA_CHANNEL_KEEP_ALIVE_DEFAULT; /* * Manage DTLS packets. */ CW_THREAD_RETURN_TYPE CWWTPReceiveDtlsPacket(void *arg) { int readBytes; unsigned char buf[CW_BUFFER_SIZE]; CWSocket sockDTLS = (long) arg; CWNetworkLev4Address addr; char *pData; CW_REPEAT_FOREVER { if (!CWErr(CWNetworkReceiveUnsafe(sockDTLS, buf, CW_BUFFER_SIZE - 1, 0, &addr, &readBytes))) { if (CWErrorGetLastErrorCode() == CW_ERROR_INTERRUPTED) continue; break; } /* Clone data packet */ CW_CREATE_OBJECT_SIZE_ERR(pData, readBytes, { CWLog("Out Of Memory"); return NULL; } ); memcpy(pData, buf, readBytes); CWLockSafeList(gPacketReceiveList); CWAddElementToSafeListTailwitDataFlag(gPacketReceiveList, pData, readBytes, CW_FALSE); CWUnlockSafeList(gPacketReceiveList); } return NULL; } extern int gRawSock; /* * Manage data packets. */ #define HLEN_80211 24 int isEAPOL_Frame(unsigned char *buf, unsigned int len) { unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; int i; for (i = 0; i < 6; i++) if (rfc1042_header[i] != buf[i + HLEN_80211]) return 0; return 1; } CW_THREAD_RETURN_TYPE CWWTPReceiveDataPacket(void *arg) { int readBytes; unsigned char buf[CW_BUFFER_SIZE]; struct sockaddr_ll rawSockaddr; CWNetworkLev4Address addr; CWList fragments = NULL; CWProtocolMessage msgPtr; CWBool dataFlag = CW_TRUE; memset(&rawSockaddr, 0, sizeof(rawSockaddr)); rawSockaddr.sll_family = AF_PACKET; rawSockaddr.sll_protocol = htons(ETH_P_ALL); rawSockaddr.sll_ifindex = if_nametoindex(gRadioInterfaceName_0); rawSockaddr.sll_pkttype = PACKET_OTHERHOST; rawSockaddr.sll_halen = ETH_ALEN; CW_REPEAT_FOREVER { if (!CWErr(CWNetworkReceiveUnsafe(gWTPDataSocket, buf, CW_BUFFER_SIZE - 1, 0, &addr, &readBytes))) { if (CWErrorGetLastErrorCode() == CW_ERROR_INTERRUPTED) continue; break; } msgPtr.msg = NULL; msgPtr.offset = 0; if (!CWProtocolParseFragment(buf, readBytes, &fragments, &msgPtr, &dataFlag, NULL)) { if (CWErrorGetLastErrorCode()) { CWErrorCode error; error = CWErrorGetLastErrorCode(); switch (error) { case CW_ERROR_SUCCESS:{ CWDebugLog("ERROR: Success"); break; } case CW_ERROR_OUT_OF_MEMORY:{ CWDebugLog("ERROR: Out of Memory"); break; } case CW_ERROR_WRONG_ARG:{ CWDebugLog("ERROR: Wrong Argument"); break; } case CW_ERROR_INTERRUPTED:{ CWDebugLog("ERROR: Interrupted"); break; } case CW_ERROR_NEED_RESOURCE:{ CWDebugLog("ERROR: Need Resource"); break; } case CW_ERROR_COMUNICATING:{ CWDebugLog("ERROR: Comunicating"); break; } case CW_ERROR_CREATING:{ CWDebugLog("ERROR: Creating"); break; } case CW_ERROR_GENERAL:{ CWDebugLog("ERROR: General"); break; } case CW_ERROR_OPERATION_ABORTED:{ CWDebugLog("ERROR: Operation Aborted"); break; } case CW_ERROR_SENDING:{ CWDebugLog("ERROR: Sending"); break; } case CW_ERROR_RECEIVING:{ CWDebugLog("ERROR: Receiving"); break; } case CW_ERROR_INVALID_FORMAT:{ CWDebugLog("ERROR: Invalid Format"); break; } case CW_ERROR_TIME_EXPIRED:{ CWDebugLog("ERROR: Time Expired"); break; } case CW_ERROR_NONE:{ CWDebugLog("ERROR: None"); break; } } } } else { if (msgPtr.data_msgType == CW_DATA_MSG_KEEP_ALIVE_TYPE) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWDebugLog("Got KeepAlive len:%d from AC", msgPtr.offset); msgPtr.offset = 0; CWParseFormatMsgElem(&msgPtr, &elemType, &elemLen); } else if (msgPtr.data_msgType == CW_IEEE_802_3_FRAME_TYPE) { CWDebugLog("Got 802.3 len:%d from AC", msgPtr.offset); /*MAC - begin */ rawSockaddr.sll_addr[0] = msgPtr.msg[0]; rawSockaddr.sll_addr[1] = msgPtr.msg[1]; rawSockaddr.sll_addr[2] = msgPtr.msg[2]; rawSockaddr.sll_addr[3] = msgPtr.msg[3]; rawSockaddr.sll_addr[4] = msgPtr.msg[4]; rawSockaddr.sll_addr[5] = msgPtr.msg[5]; /*MAC - end */ rawSockaddr.sll_addr[6] = 0x00; /*not used */ rawSockaddr.sll_addr[7] = 0x00; /*not used */ rawSockaddr.sll_hatype = htons(msgPtr.msg[12] << 8 | msgPtr.msg[13]); sendto(gRawSock, msgPtr.msg, msgPtr.offset, 0, (struct sockaddr *)&rawSockaddr, sizeof(rawSockaddr)); } else if (msgPtr.data_msgType == CW_IEEE_802_11_FRAME_TYPE) { struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *)msgPtr.msg; fc = le_to_host16(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT || isEAPOL_Frame(msgPtr.msg, msgPtr.offset)) { CWDebugLog("Got 802.11 Management Packet (stype=%d) from AC(hostapd) len:%d", WLAN_FC_GET_STYPE(fc), msgPtr.offset); CWWTPsend_data_to_hostapd(msgPtr.msg, msgPtr.offset); } else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_NULLFUNC) { CWDebugLog("Got 802.11 Data Packet (stype=%d) from AC(hostapd) len:%d", WLAN_FC_GET_STYPE(fc), msgPtr.offset); CWWTPsend_data_to_hostapd(msgPtr.msg, msgPtr.offset); } else { CWDebugLog("Got 802.11 Data Packet (stype=%d) from AC(hostapd) len:%d", WLAN_FC_GET_STYPE(fc), msgPtr.offset); CWWTPSendFrame(msgPtr.msg, msgPtr.offset); } } else { CWLog("Control/Unknow Type type=%d", WLAN_FC_GET_TYPE(fc)); } } else { CWLog("Unknow data_msgType"); } CW_FREE_PROTOCOL_MESSAGE(msgPtr); } } return NULL; } /* * Manage Run State. */ extern int gRawSock; int wtpInRunState = 0; CWStateTransition CWWTPEnterRun() { int k; CWLog("\n"); CWLog("######### WTP enters in RUN State #########"); CWWTPKeepAliveDataTimerExpiredHandler(NULL); for (k = 0; k < MAX_PENDING_REQUEST_MSGS; k++) CWResetPendingMsgBox(gPendingRequestMsgs + k); if (!CWErr(CWStartHeartbeatTimer())) { return CW_ENTER_RESET; } wtpInRunState = 1; CW_REPEAT_FOREVER { struct timespec timenow; CWBool bReceivePacket = CW_FALSE; CWBool bReveiveBinding = CW_FALSE; if (gWTPNextState == CW_ENTER_RESET) { wtpInRunState = 0; CWStopHeartbeatTimer(); return CW_ENTER_RESET; } /* Wait packet */ if (gWTPForceACAddress != NULL) timenow.tv_sec = time(0) + CW_NEIGHBORDEAD_INTERVAL_DEFAULT; else timenow.tv_sec = time(0) + CW_NEIGHBORDEAD_RESTART_DISCOVERY_DELTA_DEFAULT; /* greater than NeighborDeadInterval */ timenow.tv_nsec = 0; CWThreadMutexLock(&gInterfaceMutex); /* * if there are no frames from stations * and no packets from AC... */ if ((CWGetCountElementFromSafeList(gPacketReceiveList) == 0) && (CWGetCountElementFromSafeList(gFrameList) == 0)) { /* * ...wait at most 4 mins for a frame or packet. */ if (!CWErr(CWWaitThreadConditionTimeout(&gInterfaceWait, &gInterfaceMutex, &timenow))) { CWThreadMutexUnlock(&gInterfaceMutex); if (CWErrorGetLastErrorCode() == CW_ERROR_TIME_EXPIRED) { CWLog("No Message from AC for a long time... restart Discovery State"); break; } continue; } } bReceivePacket = ((CWGetCountElementFromSafeList(gPacketReceiveList) != 0) ? CW_TRUE : CW_FALSE); bReveiveBinding = ((CWGetCountElementFromSafeList(gFrameList) != 0) ? CW_TRUE : CW_FALSE); CWThreadMutexUnlock(&gInterfaceMutex); if (bReceivePacket) { CWProtocolMessage msg; msg.msg = NULL; msg.offset = 0; if (!(CWReceiveMessage(&msg))) { CW_FREE_PROTOCOL_MESSAGE(msg); CWLog("Failure Receiving Response"); wtpInRunState = 0; return CW_ENTER_RESET; } if (!CWErr(CWWTPManageGenericRunMessage(&msg))) { if (CWErrorGetLastErrorCode() == CW_ERROR_INVALID_FORMAT) { /* Log and ignore message */ CWErrorHandleLast(); CWLog("--> Received something different from a valid Run Message"); } else { CW_FREE_PROTOCOL_MESSAGE(msg); CWLog ("--> Critical Error Managing Generic Run Message... we enter RESET State"); wtpInRunState = 0; return CW_ENTER_RESET; } } } if (bReveiveBinding) CWWTPCheckForBindingFrame(); } wtpInRunState = 0; CWStopHeartbeatTimer(); return CW_ENTER_RESET; } CWBool CWWTPManageGenericRunMessage(CWProtocolMessage * msgPtr) { CWControlHeaderValues controlVal; if (msgPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); msgPtr->offset = 0; /* will be handled by the caller */ if (!(CWParseControlHeader(msgPtr, &controlVal))) return CW_FALSE; int len = controlVal.msgElemsLen - CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; int pendingMsgIndex = 0; pendingMsgIndex = CWFindPendingRequestMsgsBox(gPendingRequestMsgs, MAX_PENDING_REQUEST_MSGS, controlVal.messageTypeValue, controlVal.seqNum); /* we have received a new Request or an Echo Response */ if (pendingMsgIndex < 0) { CWProtocolMessage *messages = NULL; int fragmentsNum = 0; CWBool toSend = CW_FALSE; switch (controlVal.messageTypeValue) { case CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_REQUEST:{ CWProtocolResultCode resultCode = CW_PROTOCOL_FAILURE; CWProtocolConfigurationUpdateRequestValues values; int updateRequestType; /*Update 2009: check to see if a time-out on session occur... In case it happens it should go back to CW_ENTER_RESET */ if (!CWResetTimers()) { CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } CWLog("Configuration Update Request received"); /************************************************************************************************ * Update 2009: * * These two function need an additional parameter (Pointer to updateRequestType) * * for distinguish between all types of message elements. * ************************************************************************************************/ if (!CWParseConfigurationUpdateRequest ((msgPtr->msg) + (msgPtr->offset), len, &values, &updateRequestType)) return CW_FALSE; if (!CWSaveConfigurationUpdateRequest(&values, &resultCode, &updateRequestType)) return CW_FALSE; /* if ( updateRequestType == BINDING_MSG_ELEMENT_TYPE_OFDM_CONTROL ) break; */ /*Update 2009: Added values (to return stuff with a conf update response) */ if (!CWAssembleConfigurationUpdateResponse(&messages, &fragmentsNum, gWTPPathMTU, controlVal.seqNum, resultCode, values)) return CW_FALSE; toSend = CW_TRUE; /* * BUG-ML01- memory leak fix * * 16/10/2009 - Donato Capitella */ /* CWProtocolVendorSpecificValues* psValues = values.protocolValues; if (psValues->vendorPayloadType == CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI) CW_FREE_OBJECT(((CWVendorUciValues *)psValues->payload)->response); CW_FREE_OBJECT(psValues->payload); CW_FREE_OBJECT(values.protocolValues); */ break; break; } case CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_REQUEST:{ CWProtocolResultCode resultCode = CW_PROTOCOL_FAILURE; /*Update 2009: check to see if a time-out on session occur... In case it happens it should go back to CW_ENTER_RESET */ if (!CWResetTimers()) { CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } CWLog("Clear Configuration Request received"); /*WTP RESET ITS CONFIGURAION TO MANUFACTURING DEFAULT} */ if (!CWSaveClearConfigurationRequest(&resultCode)) return CW_FALSE; if (!CWAssembleClearConfigurationResponse (&messages, &fragmentsNum, gWTPPathMTU, controlVal.seqNum, resultCode)) return CW_FALSE; toSend = CW_TRUE; break; } case CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_REQUEST:{ CWProtocolResultCode resultCode = CW_PROTOCOL_SUCCESS; //CWProtocolStationConfigurationRequestValues values; --> da implementare /*Update 2009: check to see if a time-out on session occur... In case it happens it should go back to CW_ENTER_RESET */ if (!CWResetTimers()) { CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } CWLog("Station Configuration Request received"); if (!CWParseStationConfigurationRequest((msgPtr->msg) + (msgPtr->offset), len)) return CW_FALSE; if (!CWAssembleStationConfigurationResponse (&messages, &fragmentsNum, gWTPPathMTU, controlVal.seqNum, resultCode)) return CW_FALSE; toSend = CW_TRUE; break; } case CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_REQUEST:{ CWProtocolResultCode resultCode = CW_PROTOCOL_SUCCESS; if (!CWResetTimers()) { CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } CWLog("WLAN Configuration Request received"); if (!CWParseWLANConfigurationRequest((msgPtr->msg) + (msgPtr->offset), len)) return CW_FALSE; if (!CWAssembleWLANConfigurationResponse (&messages, &fragmentsNum, gWTPPathMTU, controlVal.seqNum, resultCode)) return CW_FALSE; toSend = CW_TRUE; break; } case CW_MSG_TYPE_VALUE_ECHO_RESPONSE:{ /*Update 2009: check to see if a time-out on session occur... In case it happens it should go back to CW_ENTER_RESET */ if (!CWResetTimers()) { CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } CWLog("Echo Response received"); break; } default: /* * We can't recognize the received Request so * we have to send a corresponding response * containing a failure result code */ CWLog("--> Not valid Request in Run State... we send a failure Response"); /*Update 2009: check to see if a time-out on session occur... In case it happens it should go back to CW_ENTER_RESET */ if (!CWResetTimers()) { CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } if (!(CWAssembleUnrecognizedMessageResponse(&messages, &fragmentsNum, gWTPPathMTU, controlVal.seqNum, controlVal.messageTypeValue + 1))) return CW_FALSE; toSend = CW_TRUE; /* return CWErrorRaise(CW_ERROR_INVALID_FORMAT, * "Received Message not valid in Run State"); */ } if (toSend) { int i; for (i = 0; i < fragmentsNum; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected(gWTPSocket, messages[i].msg, messages[i].offset)) #else if (!CWSecuritySend(gWTPSession, messages[i].msg, messages[i].offset)) #endif { CWLog("Error sending message"); CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); return CW_FALSE; } } CWLog("Message Sent\n"); CWFreeMessageFragments(messages, fragmentsNum); CW_FREE_OBJECT(messages); /* * Check if we have to exit due to an update commit request. */ if (WTPExitOnUpdateCommit) { exit(EXIT_SUCCESS); } } } else { /* we have received a Response */ /*Update 2009: check to see if a time-out on session occur... In case it happens it should go back to CW_ENTER_RESET */ if (!CWResetTimers()) return CW_FALSE; switch (controlVal.messageTypeValue) { case CW_MSG_TYPE_VALUE_CHANGE_STATE_EVENT_RESPONSE: CWLog("Change State Event Response received"); break; case CW_MSG_TYPE_VALUE_WTP_EVENT_RESPONSE: CWLog("WTP Event Response received"); break; case CW_MSG_TYPE_VALUE_DATA_TRANSFER_RESPONSE: CWLog("Data Transfer Response received"); break; default: /* * We can't recognize the received Response: we * ignore the message and log the event. */ return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Received Message not valid in Run State"); } CWResetPendingMsgBox(&(gPendingRequestMsgs[pendingMsgIndex])); } CW_FREE_PROTOCOL_MESSAGE(*msgPtr); return CW_TRUE; } /*______________________________________________________________*/ /* *******************___TIMER HANDLERS___******************* */ void CWWTPHeartBeatTimerExpiredHandler(void *arg) { CWList msgElemList = NULL; CWProtocolMessage *messages = NULL; int fragmentsNum = 0; int seqNum; if (!gNeighborDeadTimerSet) { if (!CWStartNeighborDeadTimer()) { CWStopHeartbeatTimer(); CWStopNeighborDeadTimer(); return; } } CWLog("WTP HeartBeat Timer Expired... we send an ECHO Request"); CWLog("\n"); CWLog("#________ Echo Request Message (Run) ________#"); /* Send WTP Event Request */ seqNum = CWGetSeqNum(); if (!CWAssembleEchoRequest(&messages, &fragmentsNum, gWTPPathMTU, seqNum, msgElemList)) { int i; CWDebugLog("Failure Assembling Echo Request"); if (messages) for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); return; } int i; for (i = 0; i < fragmentsNum; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected(gWTPSocket, messages[i].msg, messages[i].offset)) { #else if (!CWSecuritySend(gWTPSession, messages[i].msg, messages[i].offset)) { #endif CWLog("Failure sending Request"); int k; for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); break; } } int k; for (k = 0; messages && k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); if (!CWStartHeartbeatTimer()) { return; } } void CWWTPKeepAliveDataTimerExpiredHandler(void *arg) { CWProtocolMessage *messages = NULL; CWProtocolMessage sessionIDmsgElem; int fragmentsNum = 0; CWAssembleMsgElemSessionID(&sessionIDmsgElem, &gWTPSessionID[0]); /* Send WTP Event Request */ if (!CWAssembleDataMessage(&messages, &fragmentsNum, gWTPPathMTU, &sessionIDmsgElem, NULL, CW_PACKET_PLAIN, 1)) { int i; CWDebugLog("Failure Assembling KeepAlive Request"); if (messages) for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); return; } int i; for (i = 0; i < fragmentsNum; i++) { if (!CWNetworkSendUnsafeConnected(gWTPDataSocket, messages[i].msg, messages[i].offset)) { CWLog("Failure sending KeepAlive Request"); int k; for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); break; } } int k; for (k = 0; messages && k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); } void CWWTPNeighborDeadTimerExpired(void *arg) { CWLog("WTP NeighborDead Timer Expired... we consider Peer Dead."); #ifdef DMALLOC dmalloc_shutdown(); #endif return; } CWBool CWStartHeartbeatTimer() { gCWHeartBeatTimerID = timer_add(gEchoInterval, 0, &CWWTPHeartBeatTimerExpiredHandler, NULL); if (gCWHeartBeatTimerID == -1) return CW_FALSE; CWDebugLog("Echo Heartbeat Timer Started"); gCWKeepAliveTimerID = timer_add(gDataChannelKeepAlive, 0, &CWWTPKeepAliveDataTimerExpiredHandler, NULL); if (gCWKeepAliveTimerID == -1) return CW_FALSE; CWDebugLog("Keepalive Heartbeat Timer Started"); return CW_TRUE; } CWBool CWStopHeartbeatTimer() { timer_rem(gCWHeartBeatTimerID, NULL); CWDebugLog("Echo Heartbeat Timer Stopped"); timer_rem(gCWKeepAliveTimerID, NULL); CWDebugLog("KeepAlive Heartbeat Timer Stopped"); return CW_TRUE; } CWBool CWStartNeighborDeadTimer() { gCWNeighborDeadTimerID = timer_add(gCWNeighborDeadInterval, 0, &CWWTPNeighborDeadTimerExpired, NULL); if (gCWNeighborDeadTimerID == -1) return CW_FALSE; CWDebugLog("NeighborDead Timer Started"); gNeighborDeadTimerSet = CW_TRUE; return CW_TRUE; } CWBool CWStopNeighborDeadTimer() { timer_rem(gCWNeighborDeadTimerID, NULL); CWDebugLog("NeighborDead Timer Stopped"); gNeighborDeadTimerSet = CW_FALSE; return CW_TRUE; } CWBool CWResetTimers() { if (gNeighborDeadTimerSet) { if (!CWStopNeighborDeadTimer()) return CW_FALSE; } if (!CWStopHeartbeatTimer()) return CW_FALSE; if (!CWStartHeartbeatTimer()) return CW_FALSE; return CW_TRUE; } /*__________________________________________________________________*/ /* *******************___ASSEMBLE FUNCTIONS___******************* */ CWBool CWAssembleEchoRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Echo Request..."); if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_ECHO_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Echo Request Assembled"); return CW_TRUE; } CWBool CWAssembleWTPDataTransferRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; int i; CWListElement *current; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL || msgElemList == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); msgElemCount = CWCountElementInList(msgElemList); if (msgElemCount > 0) { CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } else msgElems = NULL; CWLog("Assembling WTP Data Transfer Request..."); current = msgElemList; for (i = 0; i < msgElemCount; i++) { switch (((CWMsgElemData *) current->data)->type) { case CW_MSG_ELEMENT_DATA_TRANSFER_DATA_CW_TYPE: if (! (CWAssembleMsgElemDataTransferData (&(msgElems[++k]), ((CWMsgElemData *) current->data)->value))) goto cw_assemble_error; break; /*case CW_MSG_ELEMENT_DATA_TRANSFER_MODE_CW_TYPE: if (!(CWAssembleMsgElemDataTansferMode(&(msgElems[++k])))) goto cw_assemble_error; break; */ default: goto cw_assemble_error; break; } current = current->next; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_DATA_TRANSFER_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("WTP Data Transfer Request Assembled"); return CW_TRUE; cw_assemble_error:{ int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } } CWBool CWAssembleWTPEventRequest(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWList msgElemList) { CWProtocolMessage *msgElems = NULL; int msgElemCount = 0; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; int i; CWListElement *current; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL || msgElemList == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); msgElemCount = CWCountElementInList(msgElemList); if (msgElemCount > 0) { CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); } else msgElems = NULL; CWLog("Assembling WTP Event Request..."); current = msgElemList; for (i = 0; i < msgElemCount; i++) { switch (((CWMsgElemData *) current->data)->type) { case CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_CW_TYPE: if (! (CWAssembleMsgElemDecryptErrorReport (&(msgElems[++k]), ((CWMsgElemData *) current->data)->value))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_DUPLICATE_IPV4_ADDRESS_CW_TYPE: if (!(CWAssembleMsgElemDuplicateIPv4Address(&(msgElems[++k])))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_DUPLICATE_IPV6_ADDRESS_CW_TYPE: if (!(CWAssembleMsgElemDuplicateIPv6Address(&(msgElems[++k])))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_WTP_OPERAT_STATISTICS_CW_TYPE: if (! (CWAssembleMsgElemWTPOperationalStatistics (&(msgElems[++k]), ((CWMsgElemData *) current->data)->value))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_WTP_RADIO_STATISTICS_CW_TYPE: if (! (CWAssembleMsgElemWTPRadioStatistics (&(msgElems[++k]), ((CWMsgElemData *) current->data)->value))) goto cw_assemble_error; break; case CW_MSG_ELEMENT_WTP_REBOOT_STATISTICS_CW_TYPE: if (!(CWAssembleMsgElemWTPRebootStatistics(&(msgElems[++k])))) goto cw_assemble_error; break; default: goto cw_assemble_error; break; } current = current->next; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_WTP_EVENT_REQUEST, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("WTP Event Request Assembled"); return CW_TRUE; cw_assemble_error:{ int i; for (i = 0; i <= k; i++) { CW_FREE_PROTOCOL_MESSAGE(msgElems[i]); } CW_FREE_OBJECT(msgElems); return CW_FALSE; // error will be handled by the caller } } /*Update 2009: Added values to args... values is used to determine if we have some payload (in this case only vendor and only UCI) to send back with the configuration update response*/ CWBool CWAssembleConfigurationUpdateResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode, CWProtocolConfigurationUpdateRequestValues values) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 1; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; CWProtocolVendorSpecificValues *protoValues = NULL; /*Get protocol data if we have it */ if (values.protocolValues) protoValues = (CWProtocolVendorSpecificValues *) values.protocolValues; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Configuration Update Response..."); CW_CREATE_OBJECT_ERR(msgElems, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (protoValues) { switch (protoValues->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: if (!(CWAssembleVendorMsgElemResultCodeWithPayload(msgElems, resultCode, protoValues))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } break; default: /*Result Code only */ if (!(CWAssembleMsgElemResultCode(msgElems, resultCode))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } } } else { /*Result Code only */ if (!(CWAssembleMsgElemResultCode(msgElems, resultCode))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Configuration Update Response Assembled"); return CW_TRUE; } CWBool CWAssembleClearConfigurationResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 1; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Clear Configuration Response..."); CW_CREATE_OBJECT_ERR(msgElems, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWAssembleMsgElemResultCode(msgElems, resultCode))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Clear Configuration Response Assembled"); return CW_TRUE; } CWBool CWAssembleStationConfigurationResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 1; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling Sattion Configuration Response..."); CW_CREATE_OBJECT_ERR(msgElems, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWAssembleMsgElemResultCode(msgElems, resultCode))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("Station Configuration Response Assembled"); return CW_TRUE; } CWBool CWAssembleWLANConfigurationResponse(CWProtocolMessage ** messagesPtr, int *fragmentsNumPtr, int PMTU, int seqNum, CWProtocolResultCode resultCode) { CWProtocolMessage *msgElems = NULL; const int msgElemCount = 1; CWProtocolMessage *msgElemsBinding = NULL; const int msgElemBindingCount = 0; int k = -1; if (messagesPtr == NULL || fragmentsNumPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Assembling WLAN Configuration Response..."); //CW_CREATE_OBJECT_ERR(msgElems, CWProtocolMessage, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL);); CW_CREATE_PROTOCOL_MSG_ARRAY_ERR(msgElems, msgElemCount, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); if (!(CWAssembleMsgElemResultCode((&(msgElems[++k])), resultCode))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } /* if (!(CWAssembleMsgElemVendorSpecificPayload((&(msgElems[++k]))))) { CW_FREE_OBJECT(msgElems); return CW_FALSE; } */ if (!(CWAssembleMessage(messagesPtr, fragmentsNumPtr, PMTU, seqNum, CW_MSG_TYPE_VALUE_WLAN_CONFIGURATION_RESPONSE, msgElems, msgElemCount, msgElemsBinding, msgElemBindingCount))) return CW_FALSE; CWLog("WLAN Configuration Response Assembled"); return CW_TRUE; } /*_______________________________________________________________*/ /* *******************___PARSE FUNCTIONS___******************* */ /*Update 2009: Function that parses vendor payload, filling in valuesPtr*/ CWBool CWParseVendorMessage(unsigned char *msg, int len, void **valuesPtr) { CWProtocolMessage completeMsg; unsigned short int GlobalElemType = 0; // = CWProtocolRetrieve32(&completeMsg); if (msg == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing Vendor Specific Message..."); completeMsg.msg = msg; completeMsg.offset = 0; CWProtocolVendorSpecificValues *vendPtr; // parse message elements while (completeMsg.offset < len) { unsigned short int elemType = 0; // = CWProtocolRetrieve32(&completeMsg); unsigned short int elemLen = 0; // = CWProtocolRetrieve16(&completeMsg); CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); GlobalElemType = elemType; //CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); switch (elemType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE: completeMsg.offset += elemLen; break; default: if (elemType == CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE) { CW_FREE_OBJECT(valuesPtr); return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } else { completeMsg.offset += elemLen; break; } } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); switch (GlobalElemType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE: CW_CREATE_OBJECT_ERR(vendPtr, CWProtocolVendorSpecificValues, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); /*Allocate various other vendor specific fields */ break; default: vendPtr = NULL; break; } completeMsg.offset = 0; while (completeMsg.offset < len) { unsigned short int type = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(&completeMsg, &type, &elemLen); switch (type) { /*Once we know it is a vendor specific payload... */ case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE:{ if (! (CWParseVendorPayload (&completeMsg, elemLen, (CWProtocolVendorSpecificValues *) vendPtr))) { CW_FREE_OBJECT(vendPtr); return CW_FALSE; // will be handled by the caller } } break; default: completeMsg.offset += elemLen; break; } } *valuesPtr = (void *)vendPtr; CWLog("Vendor Message Parsed"); return CW_TRUE; } CWBool CWParseConfigurationUpdateRequest(unsigned char *msg, int len, CWProtocolConfigurationUpdateRequestValues * valuesPtr, int *updateRequestType) { CWBool bindingMsgElemFound = CW_FALSE; CWBool vendorMsgElemFound = CW_FALSE; CWProtocolMessage completeMsg; unsigned short int GlobalElementType = 0; if (msg == NULL || valuesPtr == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing Configuration Update Request..."); completeMsg.msg = msg; completeMsg.offset = 0; valuesPtr->bindingValues = NULL; /*Update 2009: added protocolValues (non-binding) */ valuesPtr->protocolValues = NULL; /* parse message elements */ while (completeMsg.offset < len) { unsigned short int elemType = 0; /* = CWProtocolRetrieve32(&completeMsg); */ unsigned short int elemLen = 0; /* = CWProtocolRetrieve16(&completeMsg); */ CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); GlobalElementType = elemType; /* CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); */ CWLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); if (CWBindingCheckType(elemType)) { bindingMsgElemFound = CW_TRUE; completeMsg.offset += elemLen; continue; } switch (elemType) { /*Update 2009: Added case for vendor specific payload (Used mainly to parse UCI messages)... */ case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_CW_TYPE: vendorMsgElemFound = CW_TRUE; completeMsg.offset += elemLen; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); /*Update 2009: deal with vendor specific messages */ if (vendorMsgElemFound) { /* For the knownledge of SaveConfiguration */ *updateRequestType = GlobalElementType; if (!(CWParseVendorMessage(msg, len, &(valuesPtr->protocolValues)))) { return CW_FALSE; } } if (bindingMsgElemFound) { /* For the knownledge of SaveConfiguration */ *updateRequestType = GlobalElementType; if (!(CWBindingParseConfigurationUpdateRequest(msg, len, &(valuesPtr->bindingValues)))) { return CW_FALSE; } } CWLog("Configure Update Request Parsed"); return CW_TRUE; } CWBool CWParseWLANConfigurationRequest(unsigned char *msg, int len) { CWProtocolMessage completeMsg; if (msg == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing WLAN Configuration Request..."); completeMsg.msg = msg; completeMsg.offset = 0; // parse message elements while (completeMsg.offset < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); switch (elemType) { case CW_MSG_ELEMENT_IEEE80211_ADD_WLAN_CW_TYPE: if (!(CWParseAddWLAN(&completeMsg, elemLen))) return CW_FALSE; break; case CW_MSG_ELEMENT_IEEE80211_DELETE_WLAN_CW_TYPE: if (!(CWParseDeleteWLAN(&completeMsg, elemLen))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); CWLog("Station WLAN Request Parsed"); return CW_TRUE; } CWBool CWParseStationConfigurationRequest(unsigned char *msg, int len) { //CWBool bindingMsgElemFound=CW_FALSE; CWProtocolMessage completeMsg; if (msg == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing Station Configuration Request..."); completeMsg.msg = msg; completeMsg.offset = 0; //valuesPtr->bindingValues = NULL; // parse message elements while (completeMsg.offset < len) { unsigned short int elemType = 0; unsigned short int elemLen = 0; CWParseFormatMsgElem(&completeMsg, &elemType, &elemLen); CWDebugLog("Parsing Message Element: %u, elemLen: %u", elemType, elemLen); /*if(CWBindingCheckType(elemType)) { bindingMsgElemFound=CW_TRUE; completeMsg.offset += elemLen; continue; } */ switch (elemType) { case CW_MSG_ELEMENT_ADD_STATION_CW_TYPE: if (!(CWParseAddStation(&completeMsg, elemLen))) return CW_FALSE; break; case CW_MSG_ELEMENT_DELETE_STATION_CW_TYPE: if (!(CWParseDeleteStation(&completeMsg, elemLen))) return CW_FALSE; break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Unrecognized Message Element"); } } if (completeMsg.offset != len) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Garbage at the End of the Message"); /* if(bindingMsgElemFound) { if(!(CWBindingParseConfigurationUpdateRequest (msg, len, &(valuesPtr->bindingValues)))) { return CW_FALSE; } } */ CWLog("Station Configuration Request Parsed"); return CW_TRUE; } CWBool CWParseWTPEventResponseMessage(unsigned char *msg, int len, int seqNum, void *values) { CWControlHeaderValues controlVal; CWProtocolMessage completeMsg; if (msg == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); CWLog("Parsing WTP Event Response..."); completeMsg.msg = msg; completeMsg.offset = 0; /* error will be handled by the caller */ if (!(CWParseControlHeader(&completeMsg, &controlVal))) return CW_FALSE; /* different type */ if (controlVal.messageTypeValue != CW_MSG_TYPE_VALUE_WTP_EVENT_RESPONSE) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not WTP Event Response as Expected"); if (controlVal.seqNum != seqNum) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Different Sequence Number"); /* skip timestamp */ controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; if (controlVal.msgElemsLen != 0) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "WTP Event Response must carry no message element"); CWLog("WTP Event Response Parsed..."); return CW_TRUE; } /*______________________________________________________________*/ /* *******************___SAVE FUNCTIONS___******************* */ CWBool CWSaveWTPEventResponseMessage(void *WTPEventResp) { CWDebugLog("Saving WTP Event Response..."); CWDebugLog("WTP Response Saved"); return CW_TRUE; } /*Update 2009: Save a vendor message (mainly UCI configuration messages)*/ CWBool CWSaveVendorMessage(void *protocolValuesPtr, CWProtocolResultCode * resultCode) { if (protocolValuesPtr == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } *resultCode = CW_PROTOCOL_SUCCESS; CWProtocolVendorSpecificValues *vendorPtr = (CWProtocolVendorSpecificValues *) protocolValuesPtr; /*Find out which custom vendor paylod really is... */ switch (vendorPtr->vendorPayloadType) { case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_UCI: if (!CWWTPSaveUCIValues((CWVendorUciValues *) (vendorPtr->payload), resultCode)) { CW_FREE_OBJECT(((CWVendorUciValues *) vendorPtr->payload)->commandArgs); CW_FREE_OBJECT(vendorPtr->payload); CW_FREE_OBJECT(vendorPtr); return CW_FALSE; } break; case CW_MSG_ELEMENT_VENDOR_SPEC_PAYLOAD_WUM: if (!CWWTPSaveWUMValues((CWVendorWumValues *) (vendorPtr->payload), resultCode)) { CW_FREE_OBJECT(vendorPtr->payload); CW_FREE_OBJECT(vendorPtr); return CW_FALSE; } break; } return CW_TRUE; } CWBool CWSaveConfigurationUpdateRequest(CWProtocolConfigurationUpdateRequestValues * valuesPtr, CWProtocolResultCode * resultCode, int *updateRequestType) { *resultCode = CW_TRUE; if (valuesPtr == NULL) { return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); } if (valuesPtr->bindingValues != NULL) { if (!CWBindingSaveConfigurationUpdateRequest(valuesPtr->bindingValues, resultCode, updateRequestType)) return CW_FALSE; } if (valuesPtr->protocolValues != NULL) { /*Update 2009: We have a msg which is not a binding specific message... */ if (!CWSaveVendorMessage(valuesPtr->protocolValues, resultCode)) return CW_FALSE; } return CW_TRUE; } CWBool CWSaveClearConfigurationRequest(CWProtocolResultCode * resultCode) { *resultCode = CW_TRUE; /*Back to manufacturing default configuration */ if (!CWErr(CWWTPLoadConfiguration()) || !CWErr(CWWTPInitConfiguration())) { CWLog("Can't restore default configuration..."); return CW_FALSE; } *resultCode = CW_TRUE; return CW_TRUE; } /* CWBool CWWTPManageACRunRequest(char *msg, int len) { CWControlHeaderValues controlVal; CWProtocolMessage completeMsg; if(msg == NULL) return CWErrorRaise(CW_ERROR_WRONG_ARG, NULL); completeMsg.msg = msg; completeMsg.offset = 0; if(!(CWParseControlHeader(&completeMsg, &controlVal))) return CW_FALSE; // error will be handled by the caller switch(controlVal.messageTypeValue) { case CW_MSG_TYPE_VALUE_CONFIGURE_UPDATE_REQUEST: break; case CW_MSG_TYPE_VALUE_ECHO_REQUEST: break; case CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_REQUEST: break; case CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_REQUEST: break; default: return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Message is not Change State Event Response as Expected"); } //if(controlVal.seqNum != seqNum) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Different Sequence Number"); controlVal.msgElemsLen -= CW_CONTROL_HEADER_OFFSET_FOR_MSG_ELEMS; // skip timestamp if(controlVal.msgElemsLen != 0 ) return CWErrorRaise(CW_ERROR_INVALID_FORMAT, "Change State Event Response must carry no message elements"); CWDebugLog("Change State Event Response Parsed"); CWDebugLog("#########################"); CWDebugLog("###### STO DENTRO #######"); CWDebugLog("#########################"); return CW_TRUE; } */ void CWConfirmRunStateToACWithEchoRequest() { CWList msgElemList = NULL; CWProtocolMessage *messages = NULL; int fragmentsNum = 0; int seqNum; CWLog("\n"); CWLog("#________ Echo Request Message (Confirm Run) ________#"); /* Send WTP Event Request */ seqNum = CWGetSeqNum(); if (!CWAssembleEchoRequest(&messages, &fragmentsNum, gWTPPathMTU, seqNum, msgElemList)) { int i; CWDebugLog("Failure Assembling Echo Request"); if (messages) for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); return; } int i; for (i = 0; i < fragmentsNum; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected(gWTPSocket, messages[i].msg, messages[i].offset)) { #else if (!CWSecuritySend(gWTPSession, messages[i].msg, messages[i].offset)) { #endif CWLog("Failure sending Request"); int k; for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); break; } } int k; for (k = 0; messages && k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); } ================================================ FILE: WTPRunStateCheck.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif /*_______________________________________________________________*/ /* *******************___CHECK FUNCTIONS___******************* */ CWBool CWWTPCheckForBindingFrame() { // CWLockSafeList(gFrameList); while (CWGetCountElementFromSafeList(gFrameList) > 0) { CWBindingDataListElement *dataFirstElem = CWRemoveHeadElementFromSafeList(gFrameList, NULL); if (dataFirstElem) { int k; int fragmentsNum = 0; CWProtocolMessage *completeMsgPtr = NULL; if (!CWAssembleDataMessage(&completeMsgPtr, &fragmentsNum, gWTPPathMTU, dataFirstElem->frame, dataFirstElem->bindingValues, CW_PACKET_PLAIN, 0)) { for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*(dataFirstElem->frame)); CW_FREE_OBJECT(dataFirstElem->frame); CW_FREE_OBJECT(dataFirstElem->bindingValues); CW_FREE_OBJECT(dataFirstElem); continue; } for (k = 0; k < fragmentsNum; k++) { if (!CWNetworkSendUnsafeConnected (gWTPDataSocket, completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { CWDebugLog("Failure sending Request"); break; } CWDebugLog("Sending binding Request to AC"); } for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_PROTOCOL_MESSAGE(*(dataFirstElem->frame)); CW_FREE_OBJECT(dataFirstElem->frame); CW_FREE_OBJECT(dataFirstElem->bindingValues); CW_FREE_OBJECT(dataFirstElem); } } CWUnlockSafeList(gFrameList); return CW_TRUE; } CWBool CWWTPCheckForWTPEventRequest() { CWLog("\n"); CWLog("#________ WTP Event Request Message (Run) ________#"); /* Send WTP Event Request */ CWList msgElemList = NULL; CWProtocolMessage *messages = NULL; int fragmentsNum = 0; int seqNum; int *pendingReqIndex; seqNum = CWGetSeqNum(); CW_CREATE_OBJECT_ERR(pendingReqIndex, int, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_OBJECT_ERR(msgElemList, CWListElement, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); CW_CREATE_OBJECT_ERR(msgElemList->data, CWMsgElemData, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); msgElemList->next = NULL; //Change type and value to change the msg elem to send ((CWMsgElemData *) (msgElemList->data))->type = CW_MSG_ELEMENT_CW_DECRYPT_ER_REPORT_CW_TYPE; ((CWMsgElemData *) (msgElemList->data))->value = 0; if (!CWAssembleWTPEventRequest(&messages, &fragmentsNum, gWTPPathMTU, seqNum, msgElemList)) { int i; if (messages) for (i = 0; i < fragmentsNum; i++) { CW_FREE_PROTOCOL_MESSAGE(messages[i]); } CW_FREE_OBJECT(messages); return CW_FALSE; } *pendingReqIndex = CWSendPendingRequestMessage(gPendingRequestMsgs, messages, fragmentsNum); if (*pendingReqIndex < 0) { CWDebugLog("Failure sending WTP Event Request"); int k; for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(messages[k]); } CW_FREE_OBJECT(messages); CWDeleteList(&msgElemList, CWProtocolDestroyMsgElemData); return CW_FALSE; } CWUpdatePendingMsgBox(&(gPendingRequestMsgs[*pendingReqIndex]), CW_MSG_TYPE_VALUE_WTP_EVENT_RESPONSE, seqNum, gCWRetransmitTimer, pendingReqIndex, CWWTPRetransmitTimerExpiredHandler, 0, messages, fragmentsNum); CWDeleteList(&msgElemList, CWProtocolDestroyMsgElemData); return CW_TRUE; } /* void CWWTPRetransmitTimerExpiredHandler(CWTimerArg arg, CWTimerID id) { CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); CWDebugLog("Retransmit Timer Expired for Thread: %08x", (unsigned int)CWThreadSelf()); if(gPendingRequestMsgs[arg].retransmission == gCWMaxRetransmit) { CWDebugLog("Peer is Dead"); CWThreadSetSignals(SIG_UNBLOCK, 1, SIGALRM); //_CWCloseThread(*iPtr); return; } CWDebugLog("Retransmission Count increases to %d", gPendingRequestMsgs[arg].retransmission); int i; for(i = 0; i < gPendingRequestMsgs[arg].fragmentsNum; i++) { if(!CWSecuritySend(gWTPSession, gPendingRequestMsgs[arg].msgElems[i].msg, gPendingRequestMsgs[arg].msgElems[i].offset)){ CWDebugLog("Failure sending Request"); int k; for(k = 0; k < gPendingRequestMsgs[arg].fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(gPendingRequestMsgs[arg].msgElems[k]); } CW_FREE_OBJECT(gPendingRequestMsgs[arg].msgElems); CWThreadSetSignals(SIG_UNBLOCK, 1, SIGALRM); return; } } gPendingRequestMsgs[arg].retransmission++; if(!CWTimerCreate(gPendingRequestMsgs[arg].timer_sec, &(gPendingRequestMsgs[arg].timer), gPendingRequestMsgs[arg].timer_hdl, gPendingRequestMsgs[arg].timer_arg)) { CWThreadSetSignals(SIG_UNBLOCK, 1, SIGALRM); return; } CWThreadSetSignals(SIG_UNBLOCK, 1, SIGALRM); return; } */ void CWWTPRetransmitTimerExpiredHandler(CWTimerArg hdl_arg) { int index = *((int *)hdl_arg); CWDebugLog("Retransmit Timer Expired for Thread: %08x", (unsigned int)CWThreadSelf()); if (gPendingRequestMsgs[index].retransmission == gCWMaxRetransmit) { CWDebugLog("Peer is Dead"); //_CWCloseThread(*iPtr); return; } CWDebugLog("Retransmission Count increases to %d", gPendingRequestMsgs[index].retransmission); int i; for (i = 0; i < gPendingRequestMsgs[index].fragmentsNum; i++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected(gWTPSocket, gPendingRequestMsgs[index].msgElems[i].msg, gPendingRequestMsgs[index].msgElems[i].offset)) { #else if (!CWSecuritySend(gWTPSession, gPendingRequestMsgs[index].msgElems[i].msg, gPendingRequestMsgs[index].msgElems[i].offset)) { #endif CWDebugLog("Failure sending Request"); int k; for (k = 0; k < gPendingRequestMsgs[index].fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(gPendingRequestMsgs[index].msgElems[k]); } CW_FREE_OBJECT(gPendingRequestMsgs[index].msgElems); CW_FREE_OBJECT(hdl_arg); return; } } gPendingRequestMsgs[index].retransmission++; gPendingRequestMsgs[index].timer = timer_add(gPendingRequestMsgs[index].timer_sec, 0, gPendingRequestMsgs[index].timer_hdl, gPendingRequestMsgs[index].timer_arg); CW_FREE_OBJECT(hdl_arg); return; } ================================================ FILE: WTPSettingsFile.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWCommon.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define CW_SETTINGS_FILE "settings.wtp.txt" FILE *gSettingsFile = NULL; char *gInterfaceName = NULL; char *gEthInterfaceName = NULL; char *gRadioInterfaceName_0 = NULL; char *gBaseMACInterfaceName = NULL; char gBoardReversionNo; int gHostapd_port; char *gHostapd_unix_path; void CWExtractValue(char *start, char **startValue, char **endValue, int *offset) { *offset = strspn(start + 1, " \t\n\r"); *startValue = start + 1 + *offset; *offset = strcspn(*startValue, " \t\n\r"); *endValue = *startValue + *offset - 1; } CWBool CWParseSettingsFile() { char *line = NULL; gSettingsFile = fopen(CW_SETTINGS_FILE, "rb"); if (gSettingsFile == NULL) { CWErrorRaiseSystemError(CW_ERROR_GENERAL); } while ((line = (char *)CWGetCommand(gSettingsFile)) != NULL) { char *startTag = NULL; char *endTag = NULL; if ((startTag = strchr(line, '<')) == NULL) { CW_FREE_OBJECT(line); continue; } if ((endTag = strchr(line, '>')) == NULL) { CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "IF_NAME", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; CWExtractValue(endTag, &startValue, &endValue, &offset); CW_CREATE_STRING_ERR(gInterfaceName, offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); strncpy(gInterfaceName, startValue, offset); gInterfaceName[offset] = '\0'; CWLog(": %s", gInterfaceName); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "WTP_ETH_IF_NAME", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; CWExtractValue(endTag, &startValue, &endValue, &offset); CW_CREATE_STRING_ERR(gEthInterfaceName, offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); strncpy(gEthInterfaceName, startValue, offset); gEthInterfaceName[offset] = '\0'; CWLog(": %s", gEthInterfaceName); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "RADIO_0_IF_NAME", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; CWExtractValue(endTag, &startValue, &endValue, &offset); CW_CREATE_STRING_ERR(gRadioInterfaceName_0, offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); strncpy(gRadioInterfaceName_0, startValue, offset); gRadioInterfaceName_0[offset] = '\0'; CWLog(": %s", gRadioInterfaceName_0); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "BASE_MAC_IF_NAME", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; CWExtractValue(endTag, &startValue, &endValue, &offset); CW_CREATE_STRING_ERR(gBaseMACInterfaceName, offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); strncpy(gBaseMACInterfaceName, startValue, offset); gBaseMACInterfaceName[offset] = '\0'; CWLog(": %s", gBaseMACInterfaceName); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "BOARD_REVISION_NO", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; char reversion[16]; CWExtractValue(endTag, &startValue, &endValue, &offset); strncpy(reversion, startValue, offset); reversion[offset] = '\0'; gBoardReversionNo = atoi(reversion); CWLog(": %d", gBoardReversionNo); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "WTP_HOSTAPD_PORT", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; char port_str[16]; CWExtractValue(endTag, &startValue, &endValue, &offset); strncpy(port_str, startValue, offset); port_str[offset] = '\0'; gHostapd_port = atoi(port_str); CWLog(": %d", gHostapd_port); CW_FREE_OBJECT(line); continue; } if (!strncmp(startTag + 1, "WTP_HOSTAPD_UNIX_PATH", endTag - startTag - 1)) { char *startValue = NULL; char *endValue = NULL; int offset = 0; CWExtractValue(endTag, &startValue, &endValue, &offset); CW_CREATE_STRING_ERR(gHostapd_unix_path, offset, return CWErrorRaise(CW_ERROR_OUT_OF_MEMORY, NULL); ); strncpy(gHostapd_unix_path, startValue, offset); gHostapd_unix_path[offset] = '\0'; CWLog(": %s", gHostapd_unix_path); CW_FREE_OBJECT(line); continue; } CW_FREE_OBJECT(line); } return CW_TRUE; } ================================================ FILE: WTPStatsReceive.c ================================================ /******************************************************************************************* * Copyright (c) 2008 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Daniele De Sanctis (danieledesanctis@gmail.com) * * * *******************************************************************************************/ #include "WTPStatsReceive.h" int create_data_Frame(CWProtocolMessage ** frame, char *buffer, int len) { CW_CREATE_OBJECT_ERR(*frame, CWProtocolMessage, return 0; ); CWProtocolMessage *auxPtr = *frame; CW_CREATE_PROTOCOL_MESSAGE(*auxPtr, len, return 0; ); memcpy(auxPtr->msg, buffer, len); auxPtr->offset = len; return 1; } CW_THREAD_RETURN_TYPE CWWTPReceiveStats(void *arg) { int sock, rlen, len, k, fragmentsNum = 0, fromlen; MM_MONITOR_DATA *pData; struct sockaddr_un servaddr; struct sockaddr_un from; static char buffer[PACKET_SIZE + 1]; CWProtocolMessage *completeMsgPtr = NULL; CWProtocolMessage *data = NULL; CWBindingTransportHeaderValues *bindingValuesPtr = NULL; CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); /* Create a UNIX datagram socket for this thread */ if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { CWDebugLog("THR STATS: Error creating socket"); CWExitThread(); } /* Set up address structure for server socket */ bzero(&servaddr, sizeof(servaddr)); bzero(&from, sizeof(from)); servaddr.sun_family = AF_UNIX; strcpy(servaddr.sun_path, SOCKET_PATH); unlink(SOCKET_PATH); len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); if (bind(sock, (const struct sockaddr *)&servaddr, len) < 0) { CWDebugLog("THR STATS: Error binding socket"); CWExitThread(); } CW_CREATE_OBJECT_ERR(pData, MM_MONITOR_DATA, EXIT_THREAD); fromlen = sizeof(from); /* Receive data */ CW_REPEAT_FOREVER { rlen = recvfrom(sock, buffer, PACKET_SIZE, 0, (struct sockaddr *)&from, (socklen_t *) & fromlen); if (rlen == -1) { CWDebugLog("THR STATS: Error receiving from unix socket"); CWExitThread(); } else { completeMsgPtr = NULL; if (!create_data_Frame(&data, buffer, rlen)) { CWDebugLog("Error extracting a data stats frame"); CWExitThread(); }; pData = (MM_MONITOR_DATA *) data->msg; CW_CREATE_OBJECT_ERR(bindingValuesPtr, CWBindingTransportHeaderValues, EXIT_THREAD); bindingValuesPtr->dataRate = -1; //to distinguish between wireless frame e data message (Daniele) see CWBindig.c line 224 if (CWAssembleDataMessage(&completeMsgPtr, &fragmentsNum, gWTPPathMTU, data, bindingValuesPtr, CW_PACKET_PLAIN, 0)) { for (k = 0; k < fragmentsNum; k++) { #ifdef CW_NO_DTLS if (!CWNetworkSendUnsafeConnected (gWTPSocket, completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { #else if (!CWSecuritySend (gWTPSession, completeMsgPtr[k].msg, completeMsgPtr[k].offset)) { #endif CWDebugLog("Failure sending Request"); break; } } } for (k = 0; k < fragmentsNum; k++) { CW_FREE_PROTOCOL_MESSAGE(completeMsgPtr[k]); } CW_FREE_OBJECT(completeMsgPtr); CW_FREE_OBJECT(data); CW_FREE_OBJECT(bindingValuesPtr); } } close(sock); return (NULL); } ================================================ FILE: WTPStatsReceive.h ================================================ /******************************************************************************************* * Copyright (c) 2008 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Daniele De Sanctis (danieledesanctis@gmail.com) * * * *******************************************************************************************/ #ifndef __CAPWAP_WTPStatsReceive_HEADER__ #define __CAPWAP_WTPStatsReceive_HEADER__ #include "CWWTP.h" #include #include #include #define SOCKET_PATH "/tmp/wtp" #define PACKET_SIZE 65536 #define EXIT_THREAD CWLog("ERROR Handling Stats: application will be closed!"); \ close(sock); \ exit(1); //////////////////// copy of ath_clone.h //////////////////////////////////////////////////////// /* * Ioctl-related defintions for the Atheros Wireless LAN controller driver. */ #ifndef WME_AC_BE #define WME_AC_BE 0 #endif #ifndef WME_AC_BK #define WME_AC_BK 1 #endif #ifndef WME_AC_VI #define WME_AC_VI 2 #endif #ifndef WME_AC_VO #define WME_AC_VO 3 #endif #ifndef WME_NUM_AC #define WME_NUM_AC 4 #endif #ifndef u_int32_t #define u_int32_t unsigned long #endif #ifndef u_int16_t #define u_int16_t unsigned short #endif #ifndef u_int8_t #define u_int8_t unsigned char #endif #ifndef int8_t #define int8_t char #endif struct ath_stats_wme_clone { u_int32_t tx_packetscount; u_int32_t tx_packetslen; u_int32_t rx_packetscount; u_int32_t rx_packetslen; u_int32_t tx_shortretry; /* tx on-chip retries (short) */ u_int32_t tx_longretry; /* tx on-chip retries (long) */ u_int32_t tx_pending; /* tx packet pending */ u_int32_t tx_queue; /* tx packet queue */ u_int32_t tx_totalqueued; /* tx packet total queued */ u_int32_t tx_failed; /* tx packet failed */ u_int32_t tx_discard; /* tx packet discard */ u_int8_t wme_chan_logcwmin; /* cwmin in exponential form */ u_int8_t wme_chan_logcwmax; /* cwmax in exponential form */ u_int8_t wme_chan_aifsn; /* AIFSN parameters */ u_int16_t wme_chan_txopLimit; /* txopLimit */ u_int8_t wme_bss_logcwmin; /* cwmin in exponential form */ u_int8_t wme_bss_logcwmax; /* cwmax in exponential form */ u_int8_t wme_bss_aifsn; /* AIFSN parameters */ u_int16_t wme_bss_txopLimit; /* txopLimit */ }; struct ath_stats_clone { u_int32_t ast_watchdog; /* device reset by watchdog */ u_int32_t ast_hardware; /* fatal hardware error interrupts */ u_int32_t ast_bmiss; /* beacon miss interrupts */ u_int32_t ast_rxorn; /* rx overrun interrupts */ u_int32_t ast_rxeol; /* rx eol interrupts */ u_int32_t ast_txurn; /* tx underrun interrupts */ u_int32_t ast_mib; /* mib interrupts */ u_int32_t ast_tx_packets; /* packet sent on the interface */ u_int32_t ast_tx_bytes; /* total bytes transmitted */ u_int32_t ast_tx_mgmt; /* management frames transmitted */ u_int32_t ast_tx_discard; /* frames discarded prior to assoc */ u_int32_t ast_tx_invalid; /* frames discarded due to is device gone */ u_int32_t ast_tx_qstop; /* tx queue stopped because it's full */ u_int32_t ast_tx_encap; /* tx encapsulation failed */ u_int32_t ast_tx_nonode; /* tx failed due to of no node */ u_int32_t ast_tx_nobuf; /* tx failed due to of no tx buffer (data) */ u_int32_t ast_tx_nobufmgt; /* tx failed due to of no tx buffer (mgmt) */ u_int32_t ast_tx_xretries; /* tx failed due to of too many retries */ u_int32_t ast_tx_fifoerr; /* tx failed due to of FIFO underrun */ u_int32_t ast_tx_filtered; /* tx failed due to xmit filtered */ u_int32_t ast_tx_shortretry; /* tx on-chip retries (short) */ u_int32_t ast_tx_longretry; /* tx on-chip retries (long) */ u_int32_t ast_tx_badrate; /* tx failed due to of bogus xmit rate */ u_int32_t ast_tx_noack; /* tx frames with no ack marked */ u_int32_t ast_tx_rts; /* tx frames with rts enabled */ u_int32_t ast_tx_cts; /* tx frames with cts enabled */ u_int32_t ast_tx_shortpre; /* tx frames with short preamble */ u_int32_t ast_tx_altrate; /* tx frames with alternate rate */ u_int32_t ast_tx_protect; /* tx frames with protection */ u_int32_t ast_rx_orn; /* rx failed due to of desc overrun */ u_int32_t ast_rx_crcerr; /* rx failed due to of bad CRC */ u_int32_t ast_rx_fifoerr; /* rx failed due to of FIFO overrun */ u_int32_t ast_rx_badcrypt; /* rx failed due to of decryption */ u_int32_t ast_rx_badmic; /* rx failed due to of MIC failure */ u_int32_t ast_rx_phyerr; /* rx PHY error summary count */ u_int32_t ast_rx_phy[32]; /* rx PHY error per-code counts */ u_int32_t ast_rx_tooshort; /* rx discarded due to frame too short */ u_int32_t ast_rx_toobig; /* rx discarded due to frame too large */ u_int32_t ast_rx_nobuf; /* rx setup failed due to of no skbuff */ u_int32_t ast_rx_packets; /* packet recv on the interface */ u_int32_t ast_rx_bytes; /* total bytes received */ u_int32_t ast_rx_mgt; /* management frames received */ u_int32_t ast_rx_ctl; /* control frames received */ int8_t ast_tx_rssi; /* tx rssi of last ack */ int8_t ast_rx_rssi; /* rx rssi from histogram */ u_int32_t ast_be_xmit; /* beacons transmitted */ u_int32_t ast_be_nobuf; /* no skbuff available for beacon */ u_int32_t ast_per_cal; /* periodic calibration calls */ u_int32_t ast_per_calfail; /* periodic calibration failed */ u_int32_t ast_per_rfgain; /* periodic calibration rfgain reset */ u_int32_t ast_rate_calls; /* rate control checks */ u_int32_t ast_rate_raise; /* rate control raised xmit rate */ u_int32_t ast_rate_drop; /* rate control dropped xmit rate */ u_int32_t ast_ant_defswitch; /* rx/default antenna switches */ u_int32_t ast_ant_txswitch; /* tx antenna switches */ u_int32_t ast_ant_rx[8]; /* rx frames with antenna */ u_int32_t ast_ant_tx[8]; /* tx frames with antenna */ struct ath_stats_wme_clone ast_wme[WME_NUM_AC]; }; //////////////////// copy of ath-monitor.h //////////////////////////////////////////////////////// /* Monitoraggio dei dati dell'interfaccia di rete */ typedef struct _MM_MONITOR_DATA { int nInterfaceId; struct timeval timeData; unsigned long nInputFrame; unsigned long nInputBandwidth; unsigned long nOutputFrame; unsigned long nOutputBandwidth; struct ath_stats_clone athCurrentStats; } MM_MONITOR_DATA; int create_data_Frame(CWProtocolMessage ** frame, char *buffer, int len); #endif ================================================ FILE: WTPSulkingState.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "CWWTP.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #ifdef CW_DEBUGGING int gCWSilentInterval = 5; #else int gCWSilentInterval = 30; #endif /* * WTP enters sulking when no AC is responding to Discovery Request. */ CWStateTransition CWWTPEnterSulking() { struct timeval timeout, before, after, delta, newTimeout; CWLog("\n"); CWLog("######### Sulking State #########"); /* * wait for Silent Interval and discard * all the packets that are coming */ timeout.tv_sec = newTimeout.tv_sec = gCWSilentInterval; timeout.tv_usec = newTimeout.tv_usec = 0; gettimeofday(&before, NULL); CW_REPEAT_FOREVER { /* check if something is available to read until newTimeout */ if (CWNetworkTimedPollRead(gWTPSocket, &newTimeout)) { /* * success * if there was no error, raise a "success error", so we can easily handle * all the cases in the switch */ CWErrorRaise(CW_ERROR_SUCCESS, NULL); } switch (CWErrorGetLastErrorCode()) { case CW_ERROR_TIME_EXPIRED: goto cw_sulk_time_over; break; case CW_ERROR_SUCCESS: /* there's something to read */ { CWNetworkLev4Address addr; unsigned char buf[CW_BUFFER_SIZE]; int readBytes; /* read and discard */ if (!CWErr (CWNetworkReceiveUnsafe(gWTPSocket, buf, CW_BUFFER_SIZE, 0, &addr, &readBytes))) { return CW_QUIT; } } case CW_ERROR_INTERRUPTED: /* * something to read OR interrupted by the * system * wait for the remaining time (NetworkPoll * will be recalled with the remaining time) */ gettimeofday(&after, NULL); CWTimevalSubtract(&delta, &after, &before); if (CWTimevalSubtract(&newTimeout, &timeout, &delta) == 1) { /* negative delta: time is over */ goto cw_sulk_time_over; } break; default: CWErrorHandleLast(); goto cw_error; break; } } cw_sulk_time_over: CWLog("End of Sulking Period"); cw_error: return CW_ENTER_DISCOVERY; } ================================================ FILE: WTPipcHostapd.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Sotiraq Sima (Sotiraq.Sima@gmail.com) * * * *******************************************************************************************/ #include #include "WTPipcHostapd.h" #include "WTPmacFrameReceive.h" #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define EXIT_FRAME_THREAD(sock) CWLog("ERROR Handling Frames: application will be closed!"); close(sock); exit(1); //#define LOCALUDP //#define NETUDP //#define NETSEQ //#define USEIPV6 socklen_t address_size; #if defined(LOCALUDP) struct sockaddr_un client; #else #if defined(USEIPV6) struct sockaddr_in6 client; #else struct sockaddr_in client; #endif #endif char connected = 0; int sock; extern int wtpInRunState; pthread_mutex_t gRADIO_MAC_mutex; pthread_mutex_t mutext_info; unsigned char WTP_Radio_Information = 0; unsigned char WTP_Rates[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char WTP_MDC[6] = { 0, 0, 0, 0, 0, 0 }; unsigned char gRADIO_MAC[6]; int flush_pcap(u_char * buf, int len, char *filename) { return 0; FILE *file; file = fopen(filename, "a+"); u_char index = 0x00; int cnt = 0; int i; int giro = 0; for (i = 0; cnt < len; i++) { fprintf(file, "0%02X0 ", index); for (; cnt < len;) { fprintf(file, "%02X ", buf[cnt]); cnt++; if (giro == 15) { giro = 0; break; } giro++; } fprintf(file, "\n"); index++; } fprintf(file, "\n"); fclose(file); return 0; } void CWWTP_get_WTP_Rates(unsigned char *buf) { CWThreadMutexLock(&mutext_info); memcpy(buf, WTP_Rates, 8); CWThreadMutexUnlock(&mutext_info); } void CWWTP_get_WTP_MDC(unsigned char *buf) { CWThreadMutexLock(&mutext_info); memcpy(buf, WTP_MDC, 6); CWThreadMutexUnlock(&mutext_info); } unsigned char CWTP_get_WTP_Radio_Information() { unsigned char tmp_info; CWThreadMutexLock(&mutext_info); tmp_info = WTP_Radio_Information; CWThreadMutexUnlock(&mutext_info); return tmp_info; } void CWWTPsend_data_to_hostapd(unsigned char *buf, int len) { if (!connected) return; unsigned char tmp_buf[CW_BUFFER_SIZE]; tmp_buf[0] = DATE_TO_WTP; memcpy(tmp_buf + 1, buf, len); if (sendto(sock, tmp_buf, len + 1, 0, (struct sockaddr *)&client, address_size) < 0) { CWDebugLog("Error to send data frame on Unix socket"); return; } } void CWWTPsend_command_to_hostapd_SET_TXQ(unsigned char *buf, int len) { if (!connected) return; buf[0] = SET_TXQ; if (sendto(sock, buf, len, 0, (struct sockaddr *)&client, address_size) < 0) { CWDebugLog("Error to send command frame on Unix socket"); return; } } void CWWTPsend_command_to_hostapd_SET_ADDR(unsigned char *buf, int len) { if (!connected) return; buf[0] = SET_ADDR; if (sendto(sock, buf, len, 0, (struct sockaddr *)&client, address_size) < 0) { CWDebugLog("Error to send command frame on socket"); return; } } void CWWTPsend_command_to_hostapd_ADD_WLAN(unsigned char *buf, int len) { CWDebugLog("CWWTPsend_command_to_hostapd_ADD_WLAN()"); WAITHOSTAPDADD: if (!connected) { sleep(0.2); goto WAITHOSTAPDADD; } buf[0] = ADD_WLAN; if (sendto(sock, buf, len, 0, (struct sockaddr *)&client, address_size) < 0) { CWDebugLog("Error to send command ADD WLAN on socket"); return; } } void CWWTPsend_command_to_hostapd_DEL_WLAN(unsigned char *buf, int len) { WAITHOSTAPDDEL: if (!connected) { sleep(0.2); goto WAITHOSTAPDDEL; } buf[0] = DEL_WLAN; if (sendto(sock, buf, len, 0, (struct sockaddr *)&client, address_size) < 0) { CWLog("Error to send command DEL WLAN on socket"); return; } } void CWWTPsend_command_to_hostapd_DEL_ADDR(unsigned char *buf, int len) { if (!connected) return; buf[0] = DEL_ADDR; if (sendto(sock, buf, len, 0, (struct sockaddr *)&client, address_size) < 0) { CWLog("Error to send command frame on socket"); return; } } void CWWTPsend_command_to_hostapd_CLOSE(unsigned char *buf, int len) { buf[0] = CLOSE; if (sendto(sock, buf, len, 0, (struct sockaddr *)&client, address_size) < 0) { CWLog("Error to send command frame on socket"); return; } } CW_THREAD_RETURN_TYPE CWWTPThread_read_data_from_hostapd(void *arg) { /* CWThreadMutexLock(&gRADIO_MAC_mutex); gRADIO_MAC[0]=0xAA; gRADIO_MAC[1]=0xBB; gRADIO_MAC[2]=0xCC; gRADIO_MAC[3]=0xDD; gRADIO_MAC[4]=0xEE; gRADIO_MAC[5]=0xFF; CWThreadMutexUnlock(&gRADIO_MAC_mutex); */ int len; #if defined(LOCALUDP) struct sockaddr_un server; #else #if defined(USEIPV6) struct sockaddr_in6 server; #else struct sockaddr_in server; #endif #endif unsigned char buffer[CW_BUFFER_SIZE]; int connect_ret; unsigned char cmd[10]; CWProtocolMessage *frame = NULL; CWBindingDataListElement *listElement = NULL; CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); #if defined(LOCALUDP) sock = socket(AF_UNIX, SOCK_DGRAM, 0); #elif defined(NETUDP) #if defined(USEIPV6) bzero(&server, sizeof(server)); sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); #else memset(&server, 0, sizeof(server)); sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #endif #else #if defined(USEIPV6) bzero(&server, sizeof(server)); sock = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); #else memset(&server, 0, sizeof(server)); sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); #endif #endif if (sock < 0) { CWDebugLog("WTP ipc HOSTAPD: Error creating socket"); EXIT_FRAME_THREAD(sock); } CWDebugLog("WTP ipc HOSTAPD: Trying to connect to hostapd (wtp)..."); #if defined(LOCALUDP) server.sun_family = AF_UNIX; strcpy(server.sun_path, gHostapd_unix_path); unlink(server.sun_path); connect_ret = bind(sock, (struct sockaddr *)&server, strlen(server.sun_path) + sizeof(server.sun_family)); client.sun_family = AF_UNIX; #else #if defined(USEIPV6) server.sin6_family = AF_INET6; server.sin6_port = gHostapd_port; server.sin6_addr = in6addr_any; #else server.sin_family = AF_INET; server.sin_port = gHostapd_port; server.sin_addr.s_addr = INADDR_ANY; #endif connect_ret = bind(sock, (struct sockaddr *)&server, sizeof(server)); #endif if (connect_ret == -1) { CWDebugLog("WTP ipc HOSTAPD: Error connect/bind to socket"); EXIT_FRAME_THREAD(sock); } #if defined(LOCALUDP) #elif defined(NETUDP) #else /* 1: Only one daemon Hostapd_WTP at time */ if (listen(sock, 1) < 0) { CWDebugLog("WTP ipc HOSTAPD: Error listen "); EXIT_FRAME_THREAD(sock); } #endif #if defined(LOCALUDP) CWDebugLog("Waiting packet from Hostapd_WTP at Pipe:%s", gHostapd_unix_path); #else CWDebugLog("Waiting packet from Hostapd_WTP at Port:%d", gHostapd_port); #endif client.sin_family = AF_INET; client.sin_addr.s_addr = inet_addr("127.0.0.1"); client.sin_port = htons(6444); address_size = sizeof(client); int sig_byte = 1; #if defined(LOCALUDP) sig_byte += 5; #endif CWDebugLog("Checking if hostapd is started already"); cmd[0] = CONNECT_R; sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); cmd[0] = WTPRINFO; //Next info to get sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); CW_REPEAT_FOREVER { len = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&client, &address_size); #if defined(LOCALUDP) sprintf(client.sun_path, "%s%c%c%c%c%c", server.sun_path, buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); #endif if (len <= 0) { EXIT_FRAME_THREAD(sock) } if (connected == 0 && buffer[0] != CONNECT && buffer[0] != WTPRINFO_R) { CWDebugLog("IPC packet - WTP is not in RUN state"); CWWTPsend_command_to_hostapd_CLOSE(cmd, 10); continue; } if (buffer[0] == DATE_TO_AC) { if (!wtpInRunState) continue; if (!extract802_11_Frame(&frame, buffer + sig_byte, len - sig_byte)) { CWLog("THR FRAME: Error extracting a frame"); EXIT_FRAME_THREAD(sock); } CWDebugLog("Send 802.11 management(len:%d) to AC", len - 1); CW_CREATE_OBJECT_ERR(listElement, CWBindingDataListElement, EXIT_FRAME_THREAD(sock); ); listElement->frame = frame; listElement->bindingValues = NULL; listElement->frame->data_msgType = CW_IEEE_802_11_FRAME_TYPE; CWLockSafeList(gFrameList); CWAddElementToSafeListTail(gFrameList, listElement, sizeof(CWBindingDataListElement)); CWUnlockSafeList(gFrameList); } else if (buffer[0] == CONNECT) { connected = 1; cmd[0] = CONNECT_R; sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); cmd[0] = WTPRINFO; //Next info to get sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); } else if (buffer[0] == WTPRINFO_R) { connected = 1; #if defined(LOCALUDP) CWDebugLog("Hostapd_wtp Unix Domain Connect: %s", client.sun_path); #else #if defined(USEIPV6) CWDebugLog("Hostapd_wtp (v6) Connect: %d", client.sin6_port); #else CWDebugLog("Hostapd_wtp (v4) Connect: %s:%d", inet_ntoa(client.sin_addr), client.sin_port); #endif #endif CWThreadMutexLock(&mutext_info); memcpy(&WTP_Radio_Information, buffer + sig_byte, 1); CWThreadMutexUnlock(&mutext_info); CWDebugLog("WTPRINFO_R: %02X", WTP_Radio_Information); cmd[0] = GET_RATES; //Next info to get sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); } else if (buffer[0] == GET_RATES_R) { CWThreadMutexLock(&mutext_info); memcpy(WTP_Rates, buffer + sig_byte, 8); CWThreadMutexUnlock(&mutext_info); CWDebugLog("GET_RATES_R: %02X %02X %02X %02X %02X %02X %02X %02X", WTP_Rates[0], WTP_Rates[1], WTP_Rates[2], WTP_Rates[3], WTP_Rates[4], WTP_Rates[5], WTP_Rates[6], WTP_Rates[7]); cmd[0] = GET_MDC; //Next info to get sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); } else if (buffer[0] == GET_MDC_R) { CWThreadMutexLock(&mutext_info); memcpy(WTP_MDC, buffer + sig_byte, 6); CWThreadMutexUnlock(&mutext_info); CWDebugLog("GET_MDC_R: %02X %02X %02X %02X %02X %02X", WTP_MDC[0], WTP_MDC[1], WTP_MDC[2], WTP_MDC[3], WTP_MDC[4], WTP_MDC[5]); cmd[0] = GET_MAC; sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); } else if (buffer[0] == GET_MAC_R) { CWThreadMutexLock(&gRADIO_MAC_mutex); memcpy(gRADIO_MAC, buffer + sig_byte, 6); CWThreadMutexUnlock(&gRADIO_MAC_mutex); CWDebugLog("GET_MAC_R: %02X %02X %02X %02X %02X %02X", (unsigned char)gRADIO_MAC[0], (unsigned char)gRADIO_MAC[1], (unsigned char)gRADIO_MAC[2], (unsigned char)gRADIO_MAC[3], (unsigned char)gRADIO_MAC[4], (unsigned char)gRADIO_MAC[5]); cmd[0] = GOWAITWLAN; sendto(sock, cmd, 1, 0, (struct sockaddr *)&client, address_size); } else if (buffer[0] == CLOSE) { connected = 0; #if defined(LOCALUDP) CWDebugLog("Hostapd_wtp Unix Domain DisConnect: %s", client.sun_path); #else #if defined(USEIPV6) CWDebugLog("Hostapd_wtp (v6) DisConnect: %d", client.sin6_port); #else CWDebugLog("Hostapd_wtp (v4) Disconnect: %s:%d", inet_ntoa(client.sin_addr), client.sin_port); #endif #endif } else if (buffer[0] == SET_TXQ_R) { CWDebugLog("Hostapd WTP \"SET_TXQ_R\" Command\n"); } else if (buffer[0] == GOWAITWLAN_R) { CWDebugLog("Hostapd WTP in WAIT \"ADD WLAN\" Command\n"); if( gWTPNextState == CW_ENTER_RUN) gWTPNextState = CW_ENTER_RESET; } else { CWDebugLog("Received Unknow Command from Hostapd WTP(%d)", buffer[0]); } } close(sock); return (NULL); } ================================================ FILE: WTPipcHostapd.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Sotiraq Sima (Sotiraq.Sima@gmail.com) * * * *******************************************************************************************/ #ifndef __WTPipcHostapd_H #define __WTPipcHostapd_H #include #include #include #include #include #include #include #include "smac_code.h" #include "CWWTP.h" void CWWTPsend_data_to_hostapd(unsigned char *buf, int len); void CWWTPsend_command_to_hostapd_SET_TXQ(unsigned char *buf, int len); void CWWTPsend_command_to_hostapd_SET_ADDR(unsigned char *buf, int len); void CWWTPsend_command_to_hostapd_ADD_WLAN(unsigned char *buf, int len); void CWWTPsend_command_to_hostapd_DEL_WLAN(unsigned char *buf, int len); void CWWTPsend_command_to_hostapd_DEL_ADDR(unsigned char *buf, int len); void CWWTPsend_command_to_hostapd_CLOSE(unsigned char *buf, int len); void CWWTP_get_WTP_MDC(unsigned char *buf); void CWWTP_get_WTP_Rates(unsigned char *buf); unsigned char CWTP_get_WTP_Radio_Information(void); #endif ================================================ FILE: WTPmacDriverInteraction.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ /*prototipi da includere in CWWTP.h*/ #include "CWWTP.h" #include "WTPipcHostapd.h" int set_rts_threshold(int value); int get_rts_threshold(int *value); int set_frag_threshold(int value); int get_frag_threshold(int *value); /*--------------------------- RTS/CTS Threshold ---------------------------*/ int set_rts_threshold(int value) { printf("\nRTS/CTS threshold impostato a: %d\n", value); return 1; } int get_rts_threshold(int *value) { printf("\nRTS/CTS threshold: %d\n", *value); return 1; } /*--------------------------- Fragmentation Threshold ---------------------------*/ int set_frag_threshold(int value) { printf("\nFragmentation threshold impostato a: %d\n", value); return 1; } int get_frag_threshold(int *value) { printf("\nFragmentation threshold: %d\n", *value); return 1; } int set_txq(int code, int cwmin, int cwmax, int aifs, int burst_time) { char str[32]; sprintf(str, "X%d %d %d %d %d", code, cwmin, cwmax, aifs, burst_time); CWWTPsend_command_to_hostapd_SET_TXQ((unsigned char*)str, strlen(str)); return 1; } /*set CWMIN*/ int set_wme_cwmin(int class, int value) { printf("\nCWMIN impostato a: %d\n", value); return 1; } /*set CWMAX*/ int set_wme_cwmax(int class, int value) { printf("\nCWMAX impostato a: %d\n", value); return 1; } /*set AIFSN*/ int set_wme_aifsn(int class, int value) { printf("\nAIFSN impostato a: %d\n", value); return 1; } ================================================ FILE: WTPmacDriverInteraction.h ================================================ #define __CAPWAP_WTPBroadcomDriverInteraction_HEADER__ /* check this magic number */ #define WLC_IOCTL_MAGIC 0x14e46c77 /* bump this number if you change the ioctl interface */ #define WLC_IOCTL_VERSION 1 #define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ #define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ /* common ioctl definitions */ #define WLC_GET_MAGIC 0 #define WLC_GET_VERSION 1 #define WLC_UP 2 #define WLC_DOWN 3 #define WLC_DUMP 6 #define WLC_GET_MSGLEVEL 7 #define WLC_SET_MSGLEVEL 8 #define WLC_GET_PROMISC 9 #define WLC_SET_PROMISC 10 #define WLC_GET_RATE 12 /* #define WLC_SET_RATE 13 *//* no longer supported */ #define WLC_GET_INSTANCE 14 /* #define WLC_GET_FRAG 15 *//* no longer supported */ /* #define WLC_SET_FRAG 16 *//* no longer supported */ /* #define WLC_GET_RTS 17 *//* no longer supported */ /* #define WLC_SET_RTS 18 *//* no longer supported */ #define WLC_GET_INFRA 19 #define WLC_SET_INFRA 20 #define WLC_GET_AUTH 21 #define WLC_SET_AUTH 22 #define WLC_GET_BSSID 23 #define WLC_SET_BSSID 24 #define WLC_GET_SSID 25 #define WLC_SET_SSID 26 #define WLC_RESTART 27 #define WLC_GET_CHANNEL 29 #define WLC_SET_CHANNEL 30 #define WLC_GET_SRL 31 #define WLC_SET_SRL 32 #define WLC_GET_LRL 33 #define WLC_SET_LRL 34 #define WLC_GET_PLCPHDR 35 #define WLC_SET_PLCPHDR 36 #define WLC_GET_RADIO 37 #define WLC_SET_RADIO 38 #define WLC_GET_PHYTYPE 39 /* #define WLC_GET_WEP 42 *//* no longer supported */ /* #define WLC_SET_WEP 43 *//* no longer supported */ #define WLC_GET_KEY 44 #define WLC_SET_KEY 45 #define WLC_GET_REGULATORY 46 #define WLC_SET_REGULATORY 47 #define WLC_GET_PASSIVE 48 #define WLC_SET_PASSIVE 49 #define WLC_SCAN 50 #define WLC_SCAN_RESULTS 51 #define WLC_DISASSOC 52 #define WLC_REASSOC 53 #define WLC_GET_ROAM_TRIGGER 54 #define WLC_SET_ROAM_TRIGGER 55 #define WLC_GET_TXANT 61 #define WLC_SET_TXANT 62 #define WLC_GET_ANTDIV 63 #define WLC_SET_ANTDIV 64 /* #define WLC_GET_TXPWR 65 *//* no longer supported */ /* #define WLC_SET_TXPWR 66 *//* no longer supported */ #define WLC_GET_CLOSED 67 #define WLC_SET_CLOSED 68 #define WLC_GET_MACLIST 69 #define WLC_SET_MACLIST 70 #define WLC_GET_RATESET 71 #define WLC_SET_RATESET 72 #define WLC_GET_LOCALE 73 #define WLC_LONGTRAIN 74 #define WLC_GET_BCNPRD 75 #define WLC_SET_BCNPRD 76 #define WLC_GET_DTIMPRD 77 #define WLC_SET_DTIMPRD 78 #define WLC_GET_SROM 79 #define WLC_SET_SROM 80 #define WLC_GET_WEP_RESTRICT 81 #define WLC_SET_WEP_RESTRICT 82 #define WLC_GET_COUNTRY 83 #define WLC_SET_COUNTRY 84 #define WLC_GET_PM 85 #define WLC_SET_PM 86 #define WLC_GET_WAKE 87 #define WLC_SET_WAKE 88 #define WLC_GET_D11CNTS 89 #define WLC_GET_FORCELINK 90 /* ndis only */ #define WLC_SET_FORCELINK 91 /* ndis only */ #define WLC_FREQ_ACCURACY 92 #define WLC_CARRIER_SUPPRESS 93 #define WLC_GET_PHYREG 94 #define WLC_SET_PHYREG 95 #define WLC_GET_RADIOREG 96 #define WLC_SET_RADIOREG 97 #define WLC_GET_REVINFO 98 #define WLC_GET_UCANTDIV 99 #define WLC_SET_UCANTDIV 100 #define WLC_R_REG 101 #define WLC_W_REG 102 #define WLC_DIAG_LOOPBACK 103 #define WLC_RESET_D11CNTS 104 #define WLC_GET_MACMODE 105 #define WLC_SET_MACMODE 106 #define WLC_GET_MONITOR 107 #define WLC_SET_MONITOR 108 #define WLC_GET_GMODE 109 #define WLC_SET_GMODE 110 #define WLC_GET_LEGACY_ERP 111 #define WLC_SET_LEGACY_ERP 112 #define WLC_GET_RX_ANT 113 #define WLC_GET_CURR_RATESET 114 /* current rateset */ #define WLC_GET_SCANSUPPRESS 115 #define WLC_SET_SCANSUPPRESS 116 #define WLC_GET_AP 117 #define WLC_SET_AP 118 #define WLC_GET_EAP_RESTRICT 119 #define WLC_SET_EAP_RESTRICT 120 #define WLC_SCB_AUTHORIZE 121 #define WLC_SCB_DEAUTHORIZE 122 #define WLC_GET_WDSLIST 123 #define WLC_SET_WDSLIST 124 #define WLC_GET_ATIM 125 #define WLC_SET_ATIM 126 #define WLC_GET_RSSI 127 #define WLC_GET_PHYANTDIV 128 #define WLC_SET_PHYANTDIV 129 #define WLC_AP_RX_ONLY 130 #define WLC_GET_TX_PATH_PWR 131 #define WLC_SET_TX_PATH_PWR 132 #define WLC_GET_WSEC 133 #define WLC_SET_WSEC 134 #define WLC_GET_PHY_NOISE 135 #define WLC_GET_BSS_INFO 136 #define WLC_GET_PKTCNTS 137 #define WLC_GET_LAZYWDS 138 #define WLC_SET_LAZYWDS 139 #define WLC_GET_BANDLIST 140 #define WLC_GET_BAND 141 #define WLC_SET_BAND 142 #define WLC_SCB_DEAUTHENTICATE 143 #define WLC_GET_SHORTSLOT 144 #define WLC_GET_SHORTSLOT_OVERRIDE 145 #define WLC_SET_SHORTSLOT_OVERRIDE 146 #define WLC_GET_SHORTSLOT_RESTRICT 147 #define WLC_SET_SHORTSLOT_RESTRICT 148 #define WLC_GET_GMODE_PROTECTION 149 #define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 #define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 #define WLC_UPGRADE 152 /* #define WLC_GET_MRATE 153 *//* no longer supported */ /* #define WLC_SET_MRATE 154 *//* no longer supported */ #define WLC_GET_ASSOCLIST 159 #define WLC_GET_CLK 160 #define WLC_SET_CLK 161 #define WLC_GET_UP 162 #define WLC_OUT 163 #define WLC_GET_WPA_AUTH 164 #define WLC_SET_WPA_AUTH 165 #define WLC_GET_PROTECTION_CONTROL 178 #define WLC_SET_PROTECTION_CONTROL 179 #define WLC_GET_PHYLIST 180 #define WLC_GET_KEY_SEQ 183 /* #define WLC_GET_GMODE_PROTECTION_CTS 198 *//* no longer supported */ /* #define WLC_SET_GMODE_PROTECTION_CTS 199 *//* no longer supported */ #define WLC_GET_PIOMODE 203 #define WLC_SET_PIOMODE 204 #define WLC_SET_LED 209 #define WLC_GET_LED 210 #define WLC_GET_CHANNEL_SEL 215 #define WLC_START_CHANNEL_SEL 216 #define WLC_GET_VALID_CHANNELS 217 #define WLC_GET_FAKEFRAG 218 #define WLC_SET_FAKEFRAG 219 #define WLC_GET_WET 230 #define WLC_SET_WET 231 #define WLC_GET_KEY_PRIMARY 235 #define WLC_SET_KEY_PRIMARY 236 #define WLC_GET_RADAR 242 #define WLC_SET_RADAR 243 #define WLC_SET_SPECT_MANAGMENT 244 #define WLC_GET_SPECT_MANAGMENT 245 #define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ #define WLC_SET_CS_SCAN_TIMER 248 #define WLC_GET_CS_SCAN_TIMER 249 #define WLC_SEND_PWR_CONSTRAINT 254 #define WLC_CURRENT_PWR 256 #define WLC_GET_CHANNELS_IN_COUNTRY 260 #define WLC_GET_COUNTRY_LIST 261 #define WLC_GET_VAR 262 /* get value of named variable */ #define WLC_SET_VAR 263 /* set named variable to value */ #define WLC_NVRAM_GET 264 /* deprecated */ #define WLC_NVRAM_SET 265 #define WLC_SET_WSEC_PMK 268 #define WLC_GET_AUTH_MODE 269 #define WLC_SET_AUTH_MODE 270 #define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ #define WLC_NVOTPW 274 #define WLC_OTPW 275 #define WLC_SET_LOCALE 278 #define WLC_LAST 279 /* do not change - use get_var/set_var */ /* ** driver/apps-shared section ** */ #define BCME_STRLEN 64 /* Max string length for BCM errors */ #define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) /* * error codes could be added but the defined ones shouldn't be changed/deleted * these error codes are exposed to the user code * when ever a new error code is added to this list * please update errorstring table with the related error string and * update osl files with os specific errorcode map */ #define BCME_OK 0 /* Success */ #define BCME_ERROR -1 /* Error generic */ #define BCME_BADARG -2 /* Bad Argument */ #define BCME_BADOPTION -3 /* Bad option */ #define BCME_NOTUP -4 /* Not up */ #define BCME_NOTDOWN -5 /* Not down */ #define BCME_NOTAP -6 /* Not AP */ #define BCME_NOTSTA -7 /* Not STA */ #define BCME_BADKEYIDX -8 /* BAD Key Index */ #define BCME_RADIOOFF -9 /* Radio Off */ #define BCME_NOTBANDLOCKED -10 /* Not band locked */ #define BCME_NOCLK -11 /* No Clock */ #define BCME_BADRATESET -12 /* BAD Rate valueset */ #define BCME_BADBAND -13 /* BAD Band */ #define BCME_BUFTOOSHORT -14 /* Buffer too short */ #define BCME_BUFTOOLONG -15 /* Buffer too long */ #define BCME_BUSY -16 /* Busy */ #define BCME_NOTASSOCIATED -17 /* Not Associated */ #define BCME_BADSSIDLEN -18 /* Bad SSID len */ #define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ #define BCME_BADCHAN -20 /* Bad Channel */ #define BCME_BADADDR -21 /* Bad Address */ #define BCME_NORESOURCE -22 /* Not Enough Resources */ #define BCME_UNSUPPORTED -23 /* Unsupported */ #define BCME_BADLEN -24 /* Bad length */ #define BCME_NOTREADY -25 /* Not Ready */ #define BCME_EPERM -26 /* Not Permitted */ #define BCME_NOMEM -27 /* No Memory */ #define BCME_ASSOCIATED -28 /* Associated */ #define BCME_RANGE -29 /* Not In Range */ #define BCME_NOTFOUND -30 /* Not Found */ #define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ #define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ #define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ #define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ #define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ #define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ #define BCME_LAST BCME_DONGLE_DOWN /* These are collection of BCME Error strings */ #define BCMERRSTRINGTABLE { \ "OK", \ "Undefined error", \ "Bad Argument", \ "Bad Option", \ "Not up", \ "Not down", \ "Not AP", \ "Not STA", \ "Bad Key Index", \ "Radio Off", \ "Not band locked", \ "No clock", \ "Bad Rate valueset", \ "Bad Band", \ "Buffer too short", \ "Buffer too long", \ "Busy", \ "Not Associated", \ "Bad SSID len", \ "Out of Range Channel", \ "Bad Channel", \ "Bad Address", \ "Not Enough Resources", \ "Unsupported", \ "Bad length", \ "Not Ready", \ "Not Permitted", \ "No Memory", \ "Associated", \ "Not In Range", \ "Not Found", \ "WME Not Enabled", \ "TSPEC Not Found", \ "ACM Not Supported", \ "Not WME Association", \ "SDIO Bus Error", \ "Dongle Not Accessible" \ } /* Types definition*/ /* * Inferred Typedefs * */ /* Infer the compile environment based on preprocessor symbols and pramas. * Override type definitions as needed, and include configuration dependent * header files to define types. */ #ifdef __cplusplus #define TYPEDEF_BOOL #ifndef FALSE #define FALSE false #endif #ifndef TRUE #define TRUE true #endif #endif /* __cplusplus */ #if defined(_NEED_SIZE_T_) typedef long unsigned int size_t; #endif #define TYPEDEF_UINT #define TYPEDEF_USHORT #define TYPEDEF_ULONG /* Do not support the (u)int64 types with strict ansi for GNU C */ #if defined(__GNUC__) && defined(__STRICT_ANSI__) #define TYPEDEF_INT64 #define TYPEDEF_UINT64 #endif /* pick up ushort & uint from standard types.h */ #if defined(linux) && defined(__KERNEL__) #include /* sys/types.h and linux/types.h are oil and water */ #else #include #endif /* use the default typedefs in the next section of this file */ #define USE_TYPEDEF_DEFAULTS /* * Default Typedefs * */ #ifdef USE_TYPEDEF_DEFAULTS #undef USE_TYPEDEF_DEFAULTS #ifndef TYPEDEF_BOOL typedef /* @abstract@ */ unsigned char bool; #endif /* define uchar, ushort, uint, ulong */ #ifndef TYPEDEF_UCHAR typedef unsigned char uchar; #endif #ifndef TYPEDEF_USHORT typedef unsigned short ushort; #endif #ifndef TYPEDEF_UINT typedef unsigned int uint; #endif #ifndef TYPEDEF_ULONG typedef unsigned long ulong; #endif /* define [u]int8/16/32/64, uintptr */ #ifndef TYPEDEF_UINT8 typedef unsigned char uint8; #endif #ifndef TYPEDEF_UINT16 typedef unsigned short uint16; #endif #ifndef TYPEDEF_UINT32 typedef unsigned int uint32; #endif #ifndef TYPEDEF_UINT64 typedef unsigned long long uint64; #endif #ifndef TYPEDEF_UINTPTR typedef unsigned int uintptr; #endif #ifndef TYPEDEF_INT8 typedef signed char int8; #endif #ifndef TYPEDEF_INT16 typedef signed short int16; #endif #ifndef TYPEDEF_INT32 typedef signed int int32; #endif #ifndef TYPEDEF_INT64 typedef signed long long int64; #endif /* define float32/64, float_t */ #ifndef TYPEDEF_FLOAT32 typedef float float32; #endif #ifndef TYPEDEF_FLOAT64 typedef double float64; #endif /* * abstracted floating point type allows for compile time selection of * single or double precision arithmetic. Compiling with -DFLOAT32 * selects single precision; the default is double precision. */ #ifndef TYPEDEF_FLOAT_T #if defined(FLOAT32) typedef float32 float_t; #else /* default to double precision floating point */ typedef float64 float_t; #endif #endif /* TYPEDEF_FLOAT_T */ /* define macro values */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 /* TRUE */ #endif #ifndef NULL #define NULL 0 #endif #ifndef OFF #define OFF 0 #endif #ifndef ON #define ON 1 /* ON = 1 */ #endif #define AUTO (-1) /* Auto = -1 */ /* define PTRSZ, INLINE */ #ifndef PTRSZ #define PTRSZ sizeof(char*) #endif #ifndef INLINE #ifdef _MSC_VER #define INLINE __inline #elif __GNUC__ #define INLINE __inline__ #else #define INLINE #endif /* _MSC_VER */ #endif /* INLINE */ #undef TYPEDEF_BOOL #undef TYPEDEF_UCHAR #undef TYPEDEF_USHORT #undef TYPEDEF_UINT #undef TYPEDEF_ULONG #undef TYPEDEF_UINT8 #undef TYPEDEF_UINT16 #undef TYPEDEF_UINT32 #undef TYPEDEF_UINT64 #undef TYPEDEF_UINTPTR #undef TYPEDEF_INT8 #undef TYPEDEF_INT16 #undef TYPEDEF_INT32 #undef TYPEDEF_INT64 #undef TYPEDEF_FLOAT32 #undef TYPEDEF_FLOAT64 #undef TYPEDEF_FLOAT_T /* WME Access Category Indices (ACIs) */ #define AC_BE 0 /* Best Effort */ #define AC_BK 1 /* Background */ #define AC_VI 2 /* Video */ #define AC_VO 3 /* Voice */ #define AC_COUNT 4 /* number of ACs */ struct edcf_acparam { uint8 ACI; uint8 ECW; uint16 TXOP; /* stored in network order (ls octet first) */ } PACKED; typedef struct edcf_acparam edcf_acparam_t; /* Linux network driver ioctl encoding */ typedef struct wl_ioctl { uint cmd; /* common ioctl definition */ void *buf; /* pointer to user buffer */ uint len; /* length of user buffer */ bool set; /* get or set request (optional) */ uint used; /* bytes read or written (optional) */ uint needed; /* bytes needed (optional) */ } wl_ioctl_t; /* * Pass a wlioctl request to the specified interface. * @param name interface name * @param cmd WLC_GET_MAGIC <= cmd < WLC_LAST * @param buf buffer for passing in and/or receiving data * @param len length of buf * @return >= 0 if successful or < 0 otherwise */ extern int wl_ioctl(char *name, int cmd, void *buf, int len); extern int wl_iovar_set(char *ifname, char *iovar, void *param, int paramlen); extern int wl_iovar_get(char *ifname, char *iovar, void *bufptr, int buflen); /* * Set/Get named variable. * @param ifname interface name * @param iovar variable name * @param param input param value/buffer * @param paramlen input param value/buffer length * @param bufptr io buffer * @param buflen io buffer length * @param val val or val pointer for int routines * @return success == 0, failure != 0 */ /* * set named driver variable to int value * calling example: wl_iovar_setint(ifname, "arate", rate) */ static inline int wl_iovar_setint(char *ifname, char *iovar, int val) { return wl_iovar_set(ifname, iovar, &val, sizeof(val)); } /* * get named driver variable to int value and return error indication * calling example: wl_iovar_getint(ifname, "arate", &rate) */ static inline int wl_iovar_getint(char *ifname, char *iovar, int *val) { return wl_iovar_get(ifname, iovar, val, sizeof(int)); } #endif ================================================ FILE: WTPmacFrameReceive.c ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #include "WTPmacFrameReceive.h" #include "common.h" #include "ieee802_11_defs.h" #define TYPE_LEN 2 #define ETH_ALEN 6 #define ETH_HLEN 14 #define FRAME_80211_LEN 24 #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif #define EXIT_FRAME_THREAD(sock) CWLog("ERROR Handling Frames: application will be closed!"); \ close(sock); \ exit(1); int getMacAddr(int sock, char *interface, unsigned char *macAddr) { struct ifreq s; int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); strcpy(s.ifr_name, interface); if (!ioctl(fd, SIOCGIFHWADDR, &s)) memcpy(macAddr, s.ifr_addr.sa_data, MAC_ADDR_LEN); CWDebugLog("\n"); return 1; } int extractFrameInfo(char *buffer, char *RSSI, char *SNR, int *dataRate) { int signal, noise; *RSSI = buffer[RSSI_BYTE] - ATHEROS_CONV_VALUE; //RSSI in dBm signal = buffer[SIGNAL_BYTE] - ATHEROS_CONV_VALUE; noise = buffer[NOISE_BYTE]; *SNR = (char)signal - noise; //RSN in dB *dataRate = (buffer[DATARATE_BYTE] / 2) * 10; //Data rate in Mbps*10 return 1; } int extractFrame(CWProtocolMessage ** frame, unsigned char *buffer, int len) { CW_CREATE_OBJECT_ERR(*frame, CWProtocolMessage, return 0; ); CWProtocolMessage *auxPtr = *frame; CW_CREATE_PROTOCOL_MESSAGE(*auxPtr, len - PRISMH_LEN, return 0; ); memcpy(auxPtr->msg, buffer + PRISMH_LEN, len - PRISMH_LEN); auxPtr->offset = len - PRISMH_LEN; return 1; } int extract802_11_Frame(CWProtocolMessage ** frame, unsigned char *buffer, int len) { CW_CREATE_OBJECT_ERR(*frame, CWProtocolMessage, return 0; ); CWProtocolMessage *auxPtr = *frame; CW_CREATE_PROTOCOL_MESSAGE(*auxPtr, len, return 0; ); memcpy(auxPtr->msg, buffer, len); auxPtr->offset = len; return 1; } int extractAddr(unsigned char *destAddr, unsigned char *sourceAddr, char *frame) { memset(destAddr, 0, MAC_ADDR_LEN); memset(sourceAddr, 0, MAC_ADDR_LEN); memcpy(destAddr, frame + DEST_ADDR_START, MAC_ADDR_LEN); memcpy(sourceAddr, frame + SOURCE_ADDR_START, MAC_ADDR_LEN); return 1; } int macAddrCmp(unsigned char *addr1, unsigned char *addr2) { int i, ok = 1; for (i = 0; i < MAC_ADDR_LEN; i++) { if (addr1[i] != addr2[i]) { ok = 0; } } if (ok == 1) { CWDebugLog("MAC Address test: OK\n"); } else { CWDebugLog("MAC Address test: Failed\n"); } return ok; } int from_8023_to_80211(unsigned char *inbuffer, int inlen, unsigned char *outbuffer, unsigned char *own_addr) { int indx = 0; struct ieee80211_hdr hdr; os_memset(&hdr, 0, sizeof(struct ieee80211_hdr)); hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA) | host_to_le16(WLAN_FC_TODS); hdr.duration_id = 0; hdr.seq_ctrl = 0; os_memcpy(hdr.addr1, own_addr, ETH_ALEN); os_memcpy(hdr.addr2, inbuffer + ETH_ALEN, ETH_ALEN); os_memcpy(hdr.addr3, inbuffer, ETH_ALEN); os_memcpy(outbuffer + indx, &hdr, sizeof(hdr)); indx += sizeof(hdr); os_memcpy(outbuffer + indx, inbuffer, inlen); indx += inlen; return indx; } int gRawSock; extern int wtpInRunState; int CWWTPSendFrame(unsigned char *buf, int len) { if (send(gRawSock, buf + FRAME_80211_LEN, len - FRAME_80211_LEN, 0) < 1) { CWDebugLog("Error to send frame on raw socket"); return -1; } CWDebugLog("Send (%d) bytes on raw socket", len - FRAME_80211_LEN); return 1; } CW_THREAD_RETURN_TYPE CWWTPReceiveFrame(void *arg) { int n, encaps_len; unsigned char buffer[CW_BUFFER_SIZE]; unsigned char buf80211[CW_BUFFER_SIZE]; unsigned char macAddr[MAC_ADDR_LEN]; struct sockaddr_ll addr; CWBindingDataListElement *listElement = NULL; struct ifreq ethreq; CWThreadSetSignals(SIG_BLOCK, 1, SIGALRM); if ((gRawSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { CWDebugLog("THR FRAME: Error creating socket"); CWExitThread(); } memset(&addr, 0, sizeof(addr)); addr.sll_family = AF_PACKET; addr.sll_protocol = htons(ETH_P_ALL); addr.sll_pkttype = PACKET_HOST; addr.sll_ifindex = if_nametoindex(gRadioInterfaceName_0); if ((bind(gRawSock, (struct sockaddr *)&addr, sizeof(addr))) < 0) { CWDebugLog("THR FRAME: Error binding socket"); CWExitThread(); } if (!getMacAddr(gRawSock, gRadioInterfaceName_0, macAddr)) { CWDebugLog("THR FRAME: Ioctl error"); EXIT_FRAME_THREAD(gRawSock); } /* Set the network card in promiscuos mode */ strncpy(ethreq.ifr_name, gRadioInterfaceName_0, IFNAMSIZ); if (ioctl(gRawSock, SIOCGIFFLAGS, ðreq) == -1) { CWDebugLog("THR FRAME: Error ioctl"); EXIT_FRAME_THREAD(gRawSock); } ethreq.ifr_flags |= IFF_PROMISC; if (ioctl(gRawSock, SIOCSIFFLAGS, ðreq) == -1) { CWDebugLog("THR FRAME: Error ioctl"); EXIT_FRAME_THREAD(gRawSock); } #ifdef FILTER_ON /* Attach the filter to the socket */ if (setsockopt(gRawSock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter)) < 0) { CWDebugLog("THR FRAME: Error attaching filter"); EXIT_FRAME_THREAD(gRawSock); } #endif CW_REPEAT_FOREVER { n = recvfrom(gRawSock, buffer, sizeof(buffer), 0, NULL, NULL); if (n < 0) continue; //disabling data tunnel continue; if (!wtpInRunState) { CWLog("macframe packet - WTP is not in RUN state"); continue; } CW_CREATE_OBJECT_ERR(listElement, CWBindingDataListElement, EXIT_FRAME_THREAD(gRawSock); ); if (gWTPTunnelMode == CW_TUNNEL_MODE_802_DOT_11_TUNNEL) { encaps_len = from_8023_to_80211(buffer, n, buf80211, macAddr); if (!extract802_11_Frame(&listElement->frame, buf80211, encaps_len)) { CWDebugLog("THR FRAME: Error extracting a frame"); EXIT_FRAME_THREAD(gRawSock); } listElement->frame->data_msgType = CW_IEEE_802_11_FRAME_TYPE; CWDebugLog("Recv 802.11 data(len:%d) from %s", encaps_len, gRadioInterfaceName_0); } else { if (!extract802_11_Frame(&listElement->frame, buffer, n)) { CWDebugLog("THR FRAME: Error extracting a frame"); EXIT_FRAME_THREAD(gRawSock); } listElement->frame->data_msgType = CW_IEEE_802_3_FRAME_TYPE; CWDebugLog("Recv 802.3 data(len:%d) from %s", n, gRadioInterfaceName_0); } listElement->bindingValues = NULL; CWLockSafeList(gFrameList); CWAddElementToSafeListTail(gFrameList, listElement, sizeof(CWBindingDataListElement)); CWUnlockSafeList(gFrameList); } close(gRawSock); return (NULL); } ================================================ FILE: WTPmacFrameReceive.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __CAPWAP_WTPFrameReceive_HEADER__ #define __CAPWAP_WTPFrameReceive_HEADER__ #include #include #include #include #include #include #include "CWWTP.h" #ifndef B_ENDIAN #define CHECK_PRISM_HEADER (buffer[0]==MESSAGE_CODE_1) && \ (buffer[1]==MESSAGE_CODE_2) && \ (buffer[2]==MESSAGE_CODE_3) && \ (buffer[3]==MESSAGE_CODE_4) #else #define CHECK_PRISM_HEADER (buffer[3]==MESSAGE_CODE_1) && \ (buffer[2]==MESSAGE_CODE_2) && \ (buffer[1]==MESSAGE_CODE_3) && \ (buffer[0]==MESSAGE_CODE_4) #endif //#define PROMODE_ON //#define FILTER_ON #define PRISMH_LEN 144 #define RSSI_BYTE 68 #define SIGNAL_BYTE 92 #define NOISE_BYTE 104 #define DATARATE_BYTE 116 #define DEST_ADDR_START 4 #define SOURCE_ADDR_START 10 #define MESSAGE_CODE_1 68 #define MESSAGE_CODE_2 0 #define MESSAGE_CODE_3 0 #define MESSAGE_CODE_4 0 #define MAC_ADDR_LEN 6 #define ATHEROS_CONV_VALUE 95 #define ASSOCIATION_REQUEST_SUBTYPE 0 #define ASSOCIATION_RESPONSE_SUBTYPE 1 #define REASSOCIATION_REQUEST_SUBTYPE 2 #define REASSOCIATION_RESPONSE_SUBTYPE 3 #define PROBE_REQUEST_SUBTYPE 4 #define PROBE_RESPONSE_SUBTYPE 5 #define RESERVED6_SUBTYPE 6 #define RESERVED7_SUBTYPE 7 #define BEACON_SUBTYPE 8 #define ATIM_SUBTYPE 9 #define DISASSOCIATION_SUBTYPE 10 #define AUTHENTICATION_SUBTYPE 11 #define DEAUTHENTICATION_SUBTYPE 12 #define RESERVED0_SUBTYPE 0 #define RESERVED9_SUBTYPE 9 #define POWER_SAVE_SUBTYPE 10 #define RTS_SUBTYPE 11 #define CTS_SUBTYPE 12 #define ACKNOLEDGEMENT_SUBTYPE 13 #define CF_END_SUBTYPE 14 #define CF_END_CF_ACK_SUBTYPE 15 #define DATA_SUBTYPE 0 #define DATA_CF_ACK_SUBTYPE 1 #define DATA_CF_POLL_SUBTYPE 2 #define DATA_CF_ACK_CF_POLL_SUBTYPE 3 #define NO_DATA_SUBTYPE 4 #define CF_ACK_SUBTYPE 5 #define CF_POLL_SUBTYPE 6 #define CF_ACK_CF_POLL_SUBTYPE 7 #define RESERVED8_SUBTYPE 8 #define RESERVED15_SUBTYPE 15 int extract802_11_Frame(CWProtocolMessage ** frame, unsigned char *buffer, int len); int CWWTPSendFrame(unsigned char *buf, int len); #endif ================================================ FILE: WUA.c ================================================ /******************************************************************************************* * Copyright (c) 2008 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author: Donato Capitella (d.capitella@gmail.com) * * * *******************************************************************************************/ #include #include #include #include #include #include "CWCommon.h" #include "WUM.h" /* WUA Constants */ #define BUF_SIZE 1024 #define CUP_UNPACK_DIR "/tmp/cup.unpack" #define BACKUP_DIR "/tmp/cup.backup" #define CUD_FILE_NAME "update.cud" #define LOG_FILE "/var/log/wua.log" #define WTP_DIR_VAR "WTP_DIR" #define CUP_DIR_VAR "CUP_DIR" /* Execute the system() function * and return CW_FALSE in case of failure. */ #define SYSTEM_ERR(cmd) \ do { \ int exit_c = system(cmd); \ if (!WIFEXITED(exit_c) || WEXITSTATUS(exit_c) != 0 ) { \ return CW_FALSE; \ } \ } while(0) /* CUPWAP Update Descriptor */ struct CWUpdateDescriptor { char version[BUF_SIZE]; char pre_script[BUF_SIZE]; char post_script[BUF_SIZE]; }; /* Default values for CUD */ struct CWUpdateDescriptor cud = { .version[0] = '\0', .pre_script[0] = '\0', .post_script[0] = '\0', }; /* Function prototypes */ CWBool Unzip(char *filename, char *destdir); CWBool MakeDir(char *dirname); CWBool BackupCurrentWTP(char *WTPDir); CWBool CheckCUPIntegrity(); CWBool ParseCUD(); CWBool StartWTP(char *WTPDir); void CleanTmpFiles(char *); CWBool RestoreBackupWTP(char *WTPDir); CWBool WUAStage1(char *CupPath, char *WTPDir); CWBool WUAStage2(); void WaitForWTPTermination(); void daemonize(); /* Log related varibales and functions */ FILE *log_file = NULL; CWBool WUAInitLog(char *logFile); void WUALog(char *msg, ...); void WUALogClose(); int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s cup_file\n", argv[0]); } daemonize(); WTPUpdateAgent(argv[1]); return 0; } /* * WTPUpdateAgent - main routine of the WUA * * CupPath: pathname of the capwap update package * * This function executes an update session, which is divided * into three stages: * * - Stage 1: preparation for the update (unpack CUP and * backup current WTP) * * - Stage 2: executes pre-update script, copies new files, * then executes post-update script * * - Final Stage: cleans temp files and start new WTP */ void WTPUpdateAgent(char *CupPath) { int exit_status = EXIT_SUCCESS; char WTPDir[BUF_SIZE]; if (!WUAInitLog(LOG_FILE)) { goto quit_wua; } WaitForWTPTermination(); WUALog("Update Session Started."); if (!getcwd(WTPDir, BUF_SIZE)) { WUALog("The impossible happened: can't get current working directory!"); exit_status = EXIT_FAILURE; goto quit_wua; } if (!WUAStage1(CupPath, WTPDir)) { exit_status = EXIT_FAILURE; goto quit_wua; } if (!WUAStage2(WTPDir)) { exit_status = EXIT_FAILURE; if (!RestoreBackupWTP(WTPDir)) { WUALog("***CRITICAL ERROR*** -> Can't restore backup WTP!!!"); exit(EXIT_FAILURE); } goto quit_wua; } /* Final Stage */ quit_wua: CleanTmpFiles(CupPath); StartWTP(WTPDir); WUALog("Update Session Ended %s", (exit_status == EXIT_SUCCESS) ? "Successefully" : "With Errors"); WUALogClose(); exit(exit_status); } /* * WaitForWTPTermination * This function returns when the WTP terminates. A lock on a file * is used for synchronization purposes. */ void WaitForWTPTermination() { struct flock fl; int fd; /* The following lock in set just for synchronization purposes */ fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); if ((fd = open(WTP_LOCK_FILE, O_WRONLY)) < 0) { WUALog("Error while opening lock file: %s\n", WTP_LOCK_FILE); } fcntl(fd, F_SETLKW, &fl); close(fd); remove(WTP_LOCK_FILE); return; } /* * State 1 of the update process * * - Unpack & Check CUP file * - Backup current WTP */ CWBool WUAStage1(char *CupPath, char *WTPDir) { WUALog("Entering Stage 1..."); if (!MakeDir(CUP_UNPACK_DIR)) { return CW_FALSE; } if (!Unzip(CupPath, CUP_UNPACK_DIR)) { WUALog("Something wrong happened while unzipping the CUP archive."); return CW_FALSE; } /* if (!CheckCUPIntegrity()) { WUALog("Problems with the CUP archive."); return CW_FALSE; } */ if (!ParseCUD()) { WUALog("Error while parsing CUD."); return CW_FALSE; } WUALog("Update Version: %s", cud.version); if (!MakeDir(BACKUP_DIR)) { return CW_FALSE; } if (!BackupCurrentWTP(WTPDir)) { WUALog("Can't backup current WTP."); return CW_FALSE; } WUALog("Stage 1 completed successfully..."); return CW_TRUE; } /* * State 2 of the update process * * - Set scripts variables * - Execute preupdate script * - Copy new files * - Execute postupdate script */ CWBool WUAStage2(char *WTPDir) { int ret; char cmd_buf[BUF_SIZE]; WUALog("Entering Stage 2..."); /* Prepare env variables for the scripts */ ret = setenv(WTP_DIR_VAR, WTPDir, 1); if (ret != 0) { WUALog("Error while setting env variable."); return CW_FALSE; } ret = setenv(CUP_DIR_VAR, CUP_UNPACK_DIR, 1); if (ret != 0) { WUALog("Error while setting env variable."); return CW_FALSE; } /* Execute pre-update script, if any */ if (strlen(cud.pre_script) > 0) { SYSTEM_ERR(cud.pre_script); } /* Copy new WTP files */ ret = snprintf(cmd_buf, BUF_SIZE, "cp -r %s/WTP/* %s/", CUP_UNPACK_DIR, WTPDir); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } SYSTEM_ERR(cmd_buf); /* Execute post-upsate script, if any */ if (strlen(cud.post_script) > 0) { SYSTEM_ERR(cud.post_script); } WUALog("Stage 2 completed successefully."); return CW_TRUE; } /* * Unzip - unzips a gzipped archive into the provided directory. * * Notes: this implementation relies on the tar command. */ CWBool Unzip(char *filename, char *destdir) { char cmd_buf[BUF_SIZE]; int ret; ret = snprintf(cmd_buf, BUF_SIZE, "tar xzf %s -C %s", filename, destdir); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } SYSTEM_ERR(cmd_buf); return CW_TRUE; } /* * StartWTP - starts a WTP daemon * * WTPDir: the directory where the WTP binary resides. */ CWBool StartWTP(char *WTPDir) { char cmd_buf[BUF_SIZE]; int pid, ret; ret = snprintf(cmd_buf, BUF_SIZE, "%s/WTP", WTPDir); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } pid = fork(); if (pid == 0) { execl(cmd_buf, "WTP", WTPDir, NULL); exit(EXIT_FAILURE); } else if (pid < 0) { WUALog("Error while forking"); return CW_FALSE; } return CW_TRUE; } CWBool RestoreBackupWTP(char *WTPDir) { char cmd_buf[BUF_SIZE]; int ret; WUALog("Restoring old WTP..."); /* Del WTPDir content */ ret = snprintf(cmd_buf, BUF_SIZE, "rm -rf %s/*", WTPDir); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } SYSTEM_ERR(cmd_buf); /* Restore backup */ ret = snprintf(cmd_buf, BUF_SIZE, "cp -ra %s/* %s/", BACKUP_DIR, WTPDir); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } SYSTEM_ERR(cmd_buf); return CW_TRUE; } void StringToLower(char *str) { for (; *str != '\0'; str++) *str = tolower(*str); } CWBool ParseCUD() { FILE *fp; char buf[BUF_SIZE]; char *token; int ret = CW_TRUE; ret = snprintf(buf, BUF_SIZE, "%s/%s", CUP_UNPACK_DIR, CUD_FILE_NAME); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } fp = fopen(buf, "r"); if (fp == NULL) { WUALog("Error while opening update descriptor."); return CW_FALSE; } while (fgets(buf, BUF_SIZE, fp) != NULL) { token = strtok(buf, " "); StringToLower(token); if (strncmp(token, "preupdate", 9) == 0) { token = strtok(NULL, " "); if (token == NULL) { WUALog("Error while parsing update descriptor."); ret = CW_FALSE; goto exit_parse;; } snprintf(cud.pre_script, BUF_SIZE, "%s/scripts/%s", CUP_UNPACK_DIR, token); } else if (strncmp(token, "postupdate", 10) == 0) { token = strtok(NULL, " "); if (token == NULL) { WUALog("Error while parsing update descriptor."); ret = CW_FALSE; goto exit_parse;; } snprintf(cud.post_script, BUF_SIZE, "%s/scripts/%s", CUP_UNPACK_DIR, token); } else if (strncmp(token, "version", 7) == 0) { token = strtok(NULL, " "); if (token == NULL) { WUALog("Error while parsing update descriptor."); ret = CW_FALSE; goto exit_parse;; } snprintf(cud.version, BUF_SIZE, "%s", token); } } if (strlen(cud.version) == 0) { WUALog("Error while parsing CUD file, no version specified."); ret = CW_FALSE; } exit_parse: fclose(fp); return ret; } void CleanTmpFiles(char *cupFile) { int ret; char cmd_buf[BUF_SIZE]; /* In this function we can afford to ignore return values */ /* Remove CUP file */ remove(cupFile); /* Remove Unpack and Backup Directory */ ret = snprintf(cmd_buf, BUF_SIZE, "rm -rf %s %s", CUP_UNPACK_DIR, BACKUP_DIR); if (ret < 0 || ret >= BUF_SIZE) { return; } ret = system(cmd_buf); } CWBool BackupCurrentWTP(char *WTPDir) { char cmd_buf[BUF_SIZE]; int ret; ret = snprintf(cmd_buf, BUF_SIZE, "cp -ar %s/* %s", WTPDir, BACKUP_DIR); if (ret < 0 || ret >= BUF_SIZE) { return CW_FALSE; } SYSTEM_ERR(cmd_buf); return CW_TRUE; } CWBool MakeDir(char *dirname) { int ret; ret = mkdir(dirname, 0700); if (ret != 0) { WUALog("Can't create directory %s", dirname); return CW_FALSE; } return CW_TRUE; } /**************************************************************** * Log Functions ****************************************************************/ CWBool WUAInitLog(char *logFile) { if ((log_file = fopen(logFile, "a")) == NULL) { return CW_FALSE; } return CW_TRUE; } void WUALog(char *msg, ...) { if (log_file == NULL) return; char date_buf[BUF_SIZE] = { '\0' }; time_t time_s = time(NULL); struct tm *tm_s = localtime(&time_s); strftime(date_buf, BUF_SIZE, "%d/%b/%Y:%H:%M:%S %z", tm_s); fprintf(log_file, "%s: ", date_buf); va_list argp; va_start(argp, msg); vfprintf(log_file, msg, argp); va_end(argp); fprintf(log_file, "\n"); fflush(log_file); } void WUALogClose() { if (log_file != NULL) fclose(log_file); } void daemonize() { pid_t pid; int sid; /* already a daemon */ if (getppid() == 1) return; /* Fork off the parent process */ pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) { exit(EXIT_SUCCESS); } /* At this point we are executing as the child process */ /* Change the file mode mask */ umask(0); /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { exit(EXIT_FAILURE); } /* Redirect standard files to /dev/null */ freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); } ================================================ FILE: WUM.h ================================================ /* * WUM.h - WTP Update Messages * * * 4/11/2009 - Donato Capitella (d.capitella@gmail.com) */ #ifndef WUM_H #define WUM_H #include "CWCommon.h" #define WTP_VERSION_MAJOR 0 #define WTP_VERSION_MINOR 93 #define WTP_VERSION_REVISION 2 #define WTP_VERSION_REQUEST 1 #define WTP_VERSION_RESPONSE 2 #define WTP_UPDATE_REQUEST 3 #define WTP_UPDATE_RESPONSE 4 #define WTP_CUP_FRAGMENT 5 #define WTP_CUP_ACK 6 #define WTP_COMMIT_UPDATE 7 #define WTP_COMMIT_ACK 8 #define WTP_CANCEL_UPDATE_REQUEST 9 #define WTP_CANCEL_UPDATE_RESPONSE 10 #define WTP_LOCK_FILE "wtp.lock" void WTPUpdateAgent(char *CupPath); #endif /* WUM_H */ ================================================ FILE: capwap_bugfix_0.01 ================================================ ___ ____ / _ \ _ __ ___ _ __ / ___|__ _ _ ____ ____ _ _ __ | | | | '_ \ / _ \ '_ \| | / _` | '_ \ \ /\ / / _` | '_ \ | |_| | |_) | __/ | | | |__| (_| | |_) \ V V / (_| | |_) | \___/| .__/ \___|_| |_|\____\__,_| .__/ \_/\_/ \__,_| .__/ |_| |_|BUGFIX 0.01 |_| by mty (Matteo Latini, mtylty@gmail.com) This stuff """should""" now work the way is intended below...Please don't be harsh!!! :) ===> WTP re-enters Discovery State when session times out (WTPRunstate.c in CWWTPManageGenericRunMessage when using CWResetTimers) <=== ===> Fixed Segfault when using configuration tags missing preceding whitespace (ACConfigFile.c and WTPConfigFile.c) <=== ===> *** Neighbour Dead interval timeout is now down to 70 (previous value 200). DTLS doesn't complain anymore about wrong format certificates when Neighbour Dead interval timeout drops below 200. Please read the quick note to know more... *** <=== ===> WTP won't crash anymore when changing the status of the interface on which its socket is binded. Now it simply reenters discovery state with a reset <=== *** Quick Note: It should be possible (in my opinion) to lower the Neighbour Dead interval timeout even more... WARNING! Before doing so, another bugfix will be required. Infact, by running some tests, I found a bug (???) which I could not fix. Essentially, the problem lays in a concurrent thread-wait-for-condition function of both WTP and AC, after the Neighbour dead interval alarm has been started on both daemons. The condition (if I got it correctly) is just the daemon waiting for some frames on the interface. Since both daemons are waiting to hear from each other, they take some time to unlock... So, if the neighbour dead interval timeout is too low, they both (the AC and the WTP) get stuck in an endless loop (every time the timeout reaches zero the AC will think the WTP is dead so it will close the DTLS session while the WTP is still waiting to send Echo requests to the AC). The current setting (70) is the value I found working in all my tests. DISCLAIMER: Since all tests I made were carried out on my home LAN, maybe a value below 70 is even possible (or maybe my LAN did not work properly during the tests and this isn't a bug at all..) In case you were curious, this is the code (or at least this is where it got stuck (checked it with gdb)): AC Side (Function CWManageWTP inside ACMainLoop.c): /* Wait WTP action */ CWThreadMutexLock(&gWTPs[i].interfaceMutex); while ((gWTPs[i].isRequestClose == CW_FALSE) && (CWGetCountElementFromSafeList(gWTPs[i].packetReceiveList) == 0) && (gWTPs[i].interfaceCommand == NO_CMD)) { /*TODO: Check system */ CWWaitThreadCondition(&gWTPs[i].interfaceWait, &gWTPs[i].interfaceMutex); } CWThreadMutexUnlock(&gWTPs[i].interfaceMutex); WTP Side (Function CWManageWTP inside ACMainLoop.c): /* * if there are no frames from stations * and no packets from AC... */ if ((CWGetCountElementFromSafeList(gPacketReceiveList) == 0) && (CWGetCountElementFromSafeList(gFrameList) == 0)) { /* * ...wait at most 4 mins for a frame or packet. */ if (!CWErr(CWWaitThreadConditionTimeout(&gInterfaceWait, &gInterfaceMutex, &timenow))) { CWThreadMutexUnlock(&gInterfaceMutex); if (CWErrorGetLastErrorCode() == CW_ERROR_TIME_EXPIRED) { CWLog("No Message from AC for a long time... restart Discovery State"); break; } continue; } } ================================================ FILE: changeLog-0.92 ================================================ OpenCapWap 0.92 - 27/10/2009 Donato Capitella - d.capitella@gmail.com This version corrects 18 bugs mainly related to resource leakages in the WTP. Here follows a brief report: Note: TRL(Thread Resource Leakage) ML (Memory Leak) LE (Logic Error) UMR (Uninitialized Memory Rea) (Descriptions about each bug can be found in the source code) TRL01 - ACInterface.c LE01 - ACInterface.c ML01 - WTPRunState.c TRL02 - timerlib.c ML02 - WTPConfigureState.c ML03 - WTPJoinState.c ML04 - WTPConfigureState.c ML05 - WTPConfigureState.c ML06 - WTPProtocol.c LE02 - CWConfigFile.c ML07 - WTPJoinState.c ML08 - WTPJoinState.c ML09 - WTPProtocol.c UMR02 - WTPFrameReceive.c LE03 - CWStevens.c ML11 - ACDiscoveryState.c ML12 - ACRetransmission.c UMR03 - ACMainLoop.c ================================================ FILE: changeLog-0.93 ================================================ OpenCapWap 0.93.3 - 02/12/2009 Donato Capitella - d.capitella@gmail.com This version adds a vendor specific WTP Update System together with some minor bugfixes. *----------------------------* | WTP Update System | *----------------------------* The update system consists of a tool used AC-side to send updates (wum) and an update agent (WUA) executed WTP-side which takes care of installing an update package. *** WUA *** The WUA can be compiled like this: $ make WUA Once compiled, it has to be reside in the same directory as the WTP binary. *** wum *** The wum commmad source code is located in the /wum sub-directory. To compile it, just cd into /wum and then execute 'make'. This command can be installed anywhere on the AC machine and it relies on the AC Interface to operate. For further information about the update system and how update packages are biult, refer to the document WTPUpdateSystem.pdf in the /docs sub-directory in this source tree. *---------------------------* Note about log location *---------------------------* From this version on, WTP and AC logs are stored in /var/log/. This behaviour can be changed editing the header files CWAC.h and CWWTP.h before building Open CAPWAP. ================================================ FILE: changeLog-0.93.3 ================================================ OpenCAPWAP 0.93.3 - 03/02/2010 Elena Agostini & Donato Capitella A bug in timerlib.c was identified and corrected. This bug caused a pointer to be freed multiple times. Files changed: timerlib.c - LE-03-02-2010.01 CWThread.c - LE-03-02-2010.01 CWThread.c - LE-03-02-2010.02 ================================================ FILE: client.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDNo9iIeIifo0astEKSDLU/TsIVckZ4/K/b/8KrZ6cE6Lx7wROE u/QWjEXYe6nPRX80TeQ4zEe989QMLkD9p28binly7c8SyGNMlTGKLDksNndVMa1r bXS+XxeqJ6I1VDe7c42jb9E4wzgpCkHlitG+r/va9rx+GqHVZFs05YctVQIDAQAB AoGAVa7ea0alzrZunUlir44h+yXq0prR6FmJQQaZa2f9/Jqo5nu1kUnrU3XRKHmm cJnJfdaysEPV5Lzy7rxbEhWwwi6vq5gvPWkRgJ5VLFQv3/l65+ZLgq3E9a9pv6uz AG77YDzHuTKpc5o0Nc1G+vvdsklAM3RwA0TRXmcDMj9EZYUCQQDsXKkdfuoZGzj+ a6nlV7SaiANuG9WSTBoFAbJtKDBOm8HucvjmnrCD8NRRz8zMJZ86E6vdPyotOAy1 92DgSD8HAkEA3rm9cxml08Ar9xes1WCIbKFaskJBXfOAOhqgUBMjbMDo4MgS2L8f +TszJPsUfXRLRRjEdEpSZDl7gOqIk5G9wwJAR6MB4p2vp/JXQM0yzf7aDygAGiQ3 g8Kq9C+Ce5D9qyWMDpAsHgGksCiSwUUA5jLU4o5JvaHCT7g4KgKTCwb6iwJBAMSs QXV07XC5nlkYB9932aALL3p/dRdQYSdtwahT7hEnm7x6D+Jjiwla1EPQjvxlB95h C4Eg6/ZiqANjluywYl8CQFn3HbACM4//Yy0Z50gvokERAYW9W/94J+4W3siB4lmC FBa29h7GVu0Zt1G9OQBfi0dmp2UN3NjfZaCrhXAShTQ= -----END RSA PRIVATE KEY----- Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: md5WithRSAEncryption Issuer: CN=Local CAPWAP Root Certificate Authority, ST=Some State, C=IT/emailAddress=root@somename.somewhere.com, O=Root Certificate Authority, OU=My Subunit of Large Organization Validity Not Before: Oct 5 09:58:10 2006 GMT Not After : Oct 4 09:58:10 2011 GMT Subject: CN=somename.somewhere.com, ST=Some State, C=IT/emailAddress=root@somename.somewhere.com, O=My Large Organization Name, OU=My Subunit of Large Organization Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:cd:a3:d8:88:78:88:9f:a3:46:ac:b4:42:92:0c: b5:3f:4e:c2:15:72:46:78:fc:af:db:ff:c2:ab:67: a7:04:e8:bc:7b:c1:13:84:bb:f4:16:8c:45:d8:7b: a9:cf:45:7f:34:4d:e4:38:cc:47:bd:f3:d4:0c:2e: 40:fd:a7:6f:1b:8a:79:72:ed:cf:12:c8:63:4c:95: 31:8a:2c:39:2c:36:77:55:31:ad:6b:6d:74:be:5f: 17:aa:27:a2:35:54:37:bb:73:8d:a3:6f:d1:38:c3: 38:29:0a:41:e5:8a:d1:be:af:fb:da:f6:bc:7e:1a: a1:d5:64:5b:34:e5:87:2d:55 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Extended Key Usage: 1.3.6.1.5.5.7.3.19 Netscape Cert Type: SSL Client X509v3 Subject Alternative Name: DNS:altname.somewhere.com X509v3 Basic Constraints: CA:FALSE Signature Algorithm: md5WithRSAEncryption 91:b8:93:f1:01:49:44:55:7d:09:f1:d8:69:7e:5f:bf:a5:7a: a0:f5:32:5f:8a:df:47:0d:87:b8:da:76:49:17:24:6b:e0:fd: 67:b4:43:8c:1d:c6:68:d3:82:7f:0c:b5:48:80:af:3a:58:fd: 73:99:dc:f5:b8:17:af:99:6d:ce:0e:19:e9:a5:74:03:90:c9: 02:e4:72:b2:56:07:43:67:61:8b:33:da:5a:b5:39:dc:c9:eb: f2:5f:10:35:c5:14:18:ac:3f:f5:70:a6:63:c6:d4:0c:d4:f7: 4d:6f:ea:2d:0d:6f:4a:65:27:af:ff:b7:9f:fa:d0:83:8d:a2: df:a3 -----BEGIN CERTIFICATE----- MIIDXjCCAsegAwIBAgIBAjANBgkqhkiG9w0BAQQFADCB0DEwMC4GA1UEAxMnTG9j YWwgQ0FQV0FQIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRMwEQYDVQQIEwpT b21lIFN0YXRlMQswCQYDVQQGEwJJVDEqMCgGCSqGSIb3DQEJARYbcm9vdEBzb21l bmFtZS5zb21ld2hlcmUuY29tMSMwIQYDVQQKExpSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eTEpMCcGA1UECxMgTXkgU3VidW5pdCBvZiBMYXJnZSBPcmdhbml6YXRp b24wHhcNMDYxMDA1MDk1ODEwWhcNMTExMDA0MDk1ODEwWjCBvzEfMB0GA1UEAxMW c29tZW5hbWUuc29tZXdoZXJlLmNvbTETMBEGA1UECBMKU29tZSBTdGF0ZTELMAkG A1UEBhMCSVQxKjAoBgkqhkiG9w0BCQEWG3Jvb3RAc29tZW5hbWUuc29tZXdoZXJl LmNvbTEjMCEGA1UEChMaTXkgTGFyZ2UgT3JnYW5pemF0aW9uIE5hbWUxKTAnBgNV BAsTIE15IFN1YnVuaXQgb2YgTGFyZ2UgT3JnYW5pemF0aW9uMIGfMA0GCSqGSIb3 DQEBAQUAA4GNADCBiQKBgQDNo9iIeIifo0astEKSDLU/TsIVckZ4/K/b/8KrZ6cE 6Lx7wROEu/QWjEXYe6nPRX80TeQ4zEe989QMLkD9p28binly7c8SyGNMlTGKLDks NndVMa1rbXS+XxeqJ6I1VDe7c42jb9E4wzgpCkHlitG+r/va9rx+GqHVZFs05Yct VQIDAQABo1cwVTATBgNVHSUEDDAKBggrBgEFBQcDEzARBglghkgBhvhCAQEEBAMC B4AwIAYDVR0RBBkwF4IVYWx0bmFtZS5zb21ld2hlcmUuY29tMAkGA1UdEwQCMAAw DQYJKoZIhvcNAQEEBQADgYEAkbiT8QFJRFV9CfHYaX5fv6V6oPUyX4rfRw2HuNp2 SRcka+D9Z7RDjB3GaNOCfwy1SICvOlj9c5nc9bgXr5ltzg4Z6aV0A5DJAuRyslYH Q2dhizPaWrU53Mnr8l8QNcUUGKw/9XCmY8bUDNT3TW/qLQ1vSmUnr/+3n/rQg42i 36M= -----END CERTIFICATE----- ================================================ FILE: common.h ================================================ /* * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef COMMON_H #define COMMON_H #include "os.h" #if defined(__linux__) || defined(__GLIBC__) #include #include #endif /* __linux__ */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ defined(__OpenBSD__) #include #include #define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN #ifdef __OpenBSD__ #define bswap_16 swap16 #define bswap_32 swap32 #define bswap_64 swap64 #else /* __OpenBSD__ */ #define bswap_16 bswap16 #define bswap_32 bswap32 #define bswap_64 bswap64 #endif /* __OpenBSD__ */ #endif /* defined(__FreeBSD__) || defined(__NetBSD__) || * defined(__DragonFly__) || defined(__OpenBSD__) */ #ifdef __APPLE__ #include #include #define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN static inline unsigned short bswap_16(unsigned short v) { return ((v & 0xff) << 8) | (v >> 8); } static inline unsigned int bswap_32(unsigned int v) { return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24); } #endif /* __APPLE__ */ #ifdef CONFIG_TI_COMPILER #define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 #ifdef __big_endian__ #define __BYTE_ORDER __BIG_ENDIAN #else #define __BYTE_ORDER __LITTLE_ENDIAN #endif #endif /* CONFIG_TI_COMPILER */ #ifdef __SYMBIAN32__ #define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 #define __BYTE_ORDER __LITTLE_ENDIAN #endif /* __SYMBIAN32__ */ #ifdef CONFIG_NATIVE_WINDOWS #include typedef int socklen_t; #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 /* not supported */ #endif #endif /* CONFIG_NATIVE_WINDOWS */ #ifdef _MSC_VER #define inline __inline #undef vsnprintf #define vsnprintf _vsnprintf #undef close #define close closesocket #endif /* _MSC_VER */ /* Define platform specific integer types */ #ifdef _MSC_VER typedef UINT64 u64; typedef UINT32 u32; typedef UINT16 u16; typedef UINT8 u8; typedef INT64 s64; typedef INT32 s32; typedef INT16 s16; typedef INT8 s8; #define WPA_TYPES_DEFINED #endif /* _MSC_VER */ #ifdef __vxworks typedef unsigned long long u64; typedef UINT32 u32; typedef UINT16 u16; typedef UINT8 u8; typedef long long s64; typedef INT32 s32; typedef INT16 s16; typedef INT8 s8; #define WPA_TYPES_DEFINED #endif /* __vxworks */ #ifdef CONFIG_TI_COMPILER #ifdef _LLONG_AVAILABLE typedef unsigned long long u64; #else /* * TODO: 64-bit variable not available. Using long as a workaround to test the * build, but this will likely not work for all operations. */ typedef unsigned long u64; #endif typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; #define WPA_TYPES_DEFINED #endif /* CONFIG_TI_COMPILER */ #ifdef __SYMBIAN32__ #define __REMOVE_PLATSEC_DIAGNOSTICS__ #include typedef TUint64 u64; typedef TUint32 u32; typedef TUint16 u16; typedef TUint8 u8; #define WPA_TYPES_DEFINED #endif /* __SYMBIAN32__ */ #ifndef WPA_TYPES_DEFINED #ifdef CONFIG_USE_INTTYPES_H #include #else #include #endif typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; typedef int64_t s64; typedef int32_t s32; typedef int16_t s16; typedef int8_t s8; #define WPA_TYPES_DEFINED #endif /* !WPA_TYPES_DEFINED */ /* Define platform specific byte swapping macros */ #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) static inline unsigned short wpa_swap_16(unsigned short v) { return ((v & 0xff) << 8) | (v >> 8); } static inline unsigned int wpa_swap_32(unsigned int v) { return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24); } #define le_to_host16(n) (n) #define host_to_le16(n) (n) #define be_to_host16(n) wpa_swap_16(n) #define host_to_be16(n) wpa_swap_16(n) #define le_to_host32(n) (n) #define be_to_host32(n) wpa_swap_32(n) #define host_to_be32(n) wpa_swap_32(n) #define WPA_BYTE_SWAP_DEFINED #endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ #ifndef WPA_BYTE_SWAP_DEFINED #ifndef __BYTE_ORDER #ifndef __LITTLE_ENDIAN #ifndef __BIG_ENDIAN #define __LITTLE_ENDIAN 1234 #define __BIG_ENDIAN 4321 #if defined(sparc) #define __BYTE_ORDER __BIG_ENDIAN #endif #endif /* __BIG_ENDIAN */ #endif /* __LITTLE_ENDIAN */ #endif /* __BYTE_ORDER */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define le_to_host16(n) ((__force u16) (le16) (n)) #define host_to_le16(n) ((__force le16) (u16) (n)) #define be_to_host16(n) bswap_16((__force u16) (be16) (n)) #define host_to_be16(n) ((__force be16) bswap_16((n))) #define le_to_host32(n) ((__force u32) (le32) (n)) #define host_to_le32(n) ((__force le32) (u32) (n)) #define be_to_host32(n) bswap_32((__force u32) (be32) (n)) #define host_to_be32(n) ((__force be32) bswap_32((n))) #define le_to_host64(n) ((__force u64) (le64) (n)) #define host_to_le64(n) ((__force le64) (u64) (n)) #define be_to_host64(n) bswap_64((__force u64) (be64) (n)) #define host_to_be64(n) ((__force be64) bswap_64((n))) #elif __BYTE_ORDER == __BIG_ENDIAN #define le_to_host16(n) bswap_16(n) #define host_to_le16(n) bswap_16(n) #define be_to_host16(n) (n) #define host_to_be16(n) (n) #define le_to_host32(n) bswap_32(n) #define be_to_host32(n) (n) #define host_to_be32(n) (n) #define le_to_host64(n) bswap_64(n) #define host_to_le64(n) bswap_64(n) #define be_to_host64(n) (n) #define host_to_be64(n) (n) #ifndef WORDS_BIGENDIAN #define WORDS_BIGENDIAN #endif #else #error Could not determine CPU byte order #endif #define WPA_BYTE_SWAP_DEFINED #endif /* !WPA_BYTE_SWAP_DEFINED */ /* Macros for handling unaligned memory accesses */ #define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) #define WPA_PUT_BE16(a, val) \ do { \ (a)[0] = ((u16) (val)) >> 8; \ (a)[1] = ((u16) (val)) & 0xff; \ } while (0) #define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) #define WPA_PUT_LE16(a, val) \ do { \ (a)[1] = ((u16) (val)) >> 8; \ (a)[0] = ((u16) (val)) & 0xff; \ } while (0) #define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ((u32) (a)[2])) #define WPA_PUT_BE24(a, val) \ do { \ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ (a)[2] = (u8) (((u32) (val)) & 0xff); \ } while (0) #define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) #define WPA_PUT_BE32(a, val) \ do { \ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ (a)[3] = (u8) (((u32) (val)) & 0xff); \ } while (0) #define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ (((u32) (a)[1]) << 8) | ((u32) (a)[0])) #define WPA_PUT_LE32(a, val) \ do { \ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ (a)[0] = (u8) (((u32) (val)) & 0xff); \ } while (0) #define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ (((u64) (a)[6]) << 8) | ((u64) (a)[7])) #define WPA_PUT_BE64(a, val) \ do { \ (a)[0] = (u8) (((u64) (val)) >> 56); \ (a)[1] = (u8) (((u64) (val)) >> 48); \ (a)[2] = (u8) (((u64) (val)) >> 40); \ (a)[3] = (u8) (((u64) (val)) >> 32); \ (a)[4] = (u8) (((u64) (val)) >> 24); \ (a)[5] = (u8) (((u64) (val)) >> 16); \ (a)[6] = (u8) (((u64) (val)) >> 8); \ (a)[7] = (u8) (((u64) (val)) & 0xff); \ } while (0) #define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ (((u64) (a)[1]) << 8) | ((u64) (a)[0])) #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IFNAMSIZ #define IFNAMSIZ 16 #endif #ifndef ETH_P_ALL #define ETH_P_ALL 0x0003 #endif #ifndef ETH_P_80211_ENCAP #define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ #endif #ifndef ETH_P_PAE #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ #endif /* ETH_P_PAE */ #ifndef ETH_P_EAPOL #define ETH_P_EAPOL ETH_P_PAE #endif /* ETH_P_EAPOL */ #ifndef ETH_P_RSN_PREAUTH #define ETH_P_RSN_PREAUTH 0x88c7 #endif /* ETH_P_RSN_PREAUTH */ #ifndef ETH_P_RRB #define ETH_P_RRB 0x890D #endif /* ETH_P_RRB */ #ifdef __GNUC__ #define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) #define STRUCT_PACKED __attribute__ ((packed)) #else #define PRINTF_FORMAT(a,b) #define STRUCT_PACKED #endif #ifdef CONFIG_ANSI_C_EXTRA #if !defined(_MSC_VER) || _MSC_VER < 1400 /* snprintf - used in number of places; sprintf() is _not_ a good replacement * due to possible buffer overflow; see, e.g., * http://www.ijs.si/software/snprintf/ for portable implementation of * snprintf. */ int snprintf(char *str, size_t size, const char *format, ...); /* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ int vsnprintf(char *str, size_t size, const char *format, va_list ap); #endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ /* getopt - only used in main.c */ int getopt(int argc, char *const argv[], const char *optstring); extern char *optarg; extern int optind; #ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF #ifndef __socklen_t_defined typedef int socklen_t; #endif #endif /* inline - define as __inline or just define it to be empty, if needed */ #ifdef CONFIG_NO_INLINE #define inline #else #define inline __inline #endif #ifndef __func__ #define __func__ "__func__ not defined" #endif #ifndef bswap_16 #define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) #endif #ifndef bswap_32 #define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ (((u32) (a) << 8) & 0xff0000) | \ (((u32) (a) >> 8) & 0xff00) | \ (((u32) (a) >> 24) & 0xff)) #endif #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 #endif #ifdef _WIN32_WCE void perror(const char *s); #endif /* _WIN32_WCE */ #endif /* CONFIG_ANSI_C_EXTRA */ #ifndef MAC2STR #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" /* * Compact form for string representation of MAC address * To be used, e.g., for constructing dbus paths for P2P Devices */ #define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" #endif #ifndef BIT #define BIT(x) (1 << (x)) #endif /* * Definitions for sparse validation * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) */ #ifdef __CHECKER__ #define __force __attribute__((force)) #define __bitwise __attribute__((bitwise)) #else #define __force #define __bitwise #endif typedef u16 __bitwise be16; typedef u16 __bitwise le16; typedef u32 __bitwise be32; typedef u32 __bitwise le32; typedef u64 __bitwise be64; typedef u64 __bitwise le64; #ifndef __must_check #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) #define __must_check __attribute__((__warn_unused_result__)) #else #define __must_check #endif /* __GNUC__ */ #endif /* __must_check */ int hwaddr_aton(const char *txt, u8 * addr); int hwaddr_compact_aton(const char *txt, u8 * addr); int hwaddr_aton2(const char *txt, u8 * addr); int hex2byte(const char *hex); int hexstr2bin(const char *hex, u8 * buf, size_t len); void inc_byte_array(u8 * counter, size_t len); void wpa_get_ntp_timestamp(u8 * buf); int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 * data, size_t len); int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 * data, size_t len); #ifdef CONFIG_NATIVE_WINDOWS void wpa_unicode2ascii_inplace(TCHAR * str); TCHAR *wpa_strdup_tchar(const char *str); #else /* CONFIG_NATIVE_WINDOWS */ #define wpa_unicode2ascii_inplace(s) do { } while (0) #define wpa_strdup_tchar(s) strdup((s)) #endif /* CONFIG_NATIVE_WINDOWS */ const char *wpa_ssid_txt(const u8 * ssid, size_t ssid_len); static inline int is_zero_ether_addr(const u8 * a) { return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); } static inline int is_broadcast_ether_addr(const u8 * a) { return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; } #define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" //#include "wpa_debug.h" /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common * networking socket uses that do not really result in a real problem and * cannot be easily avoided with union-based type-punning due to struct * definitions including another struct in system header files. To avoid having * to fully disable strict-aliasing warnings, provide a mechanism to hide the * typecast from aliasing for now. A cleaner solution will hopefully be found * in the future to handle these cases. */ void *__hide_aliasing_typecast(void *foo); #define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) #ifdef CONFIG_VALGRIND #include #define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) #else /* CONFIG_VALGRIND */ #define WPA_MEM_DEFINED(ptr, len) do { } while (0) #endif /* CONFIG_VALGRIND */ #endif /* COMMON_H */ ================================================ FILE: config.ac ================================================ # Config File for AC. Lines beginning with # and blank lines will be ignored # HW version of the AC 1235656 # SW version of the AC 3256984 # Max number of mobile stations supported 200 # Max number of WTP supported 15 # Authentication mode for AC. Can be X509_CERTIFICATE or PRESHARED (for # preshared keys) # X509_CERTIFICATE PRESHARED # Can be IPv4 or IPv6. Of course the host must have IPv6 enabled to work with the # setting IPv6 IPv4 # Force MTU to 50 bytes, used to debug fragmentation ;-) If you don't need this, simply # comment the line by adding a #. 1420 My AC # The AC will join the Multicast Groups you add here #239.255.1.2 #239.255.1.3 1 30000000 ================================================ FILE: config.wtp ================================================ # Config File for WTP. Lines beginning with # and blank lines will be ignored # List of ACs' addresses for Discovery. They can be host names (e.g. "localhost", # IPv4 addresses if we are an IPv4 host or IPv6 addresses if we are an # IPv6Host. Wecan also add limited broadcast address (255.255.255.255) or # multicast addresses #255.255.255.255 #localhost #192.168.1.2 #192.168.1.8 #239.255.1.3 172.16.151.1 #127.0.0.1 #10.10.3.252 #1.1.1.2 #172.16.1.104 #localhost My WTP 1 Next to Fridge # Can be IPv4 or IPv6. Of course the host must have IPv6 enabled to work with the # setting IPv6 IPv4 # Force MTU to 50 bytes, used to debug fragmentation ;-) If you don't need this, simply # comment the line by adding a #. 1420 # If you uncomment the following line, the WTP will jump to Join State # (without doing Discovery) and the address will be considered the AC's address. # 192.168.1.2 # Usually the WTP knows if the AC supports Certificate or Preshared-keys authentication # from the Discovery Response. If we jump to the Join State using , # however, we must know how to behave. This setting can be X509_CERTIFICATE (default if you # leave the line commented) or PRESHARED. This setting is ignored if you don't use # . # PRESHARED X509_CERTIFICATE 1 8388608 ================================================ FILE: configure.ac ================================================ AC_INIT([opencapwap], [1.0], [info@travelping.com]) AM_INIT_AUTOMAKE([1.9 foreign silent-rules]) AC_CONFIG_MACRO_DIR([m4]) AC_USE_SYSTEM_EXTENSIONS LT_INIT AM_CONFIG_HEADER(config.h) AC_PREFIX_DEFAULT(/usr) AC_CANONICAL_HOST AC_USE_SYSTEM_EXTENSIONS AM_SILENT_RULES([yes]) AC_PROG_LIBTOOL AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_INSTALL AC_SET_MAKE AC_CHECK_HEADER([pthread.h], [], [AC_MSG_ERROR(You need the pthread headers)]) AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR(You need the pthread library)]) AC_CHECK_FUNC([sem_timedwait], [AC_DEFINE([HAVE_SEM_TIMEDWAIT], [1], [Define if sem_timedwait exists.])]) AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [enable debug]), [CFLAGS="$CFLAGS -DCW_DEBUGGING"], []) AC_ARG_ENABLE([dtls], AS_HELP_STRING([--disable-dtls], [disable DTLS support])) AM_CONDITIONAL([USE_SSL], [test "x$enable_dtls" != "xno"]) AS_IF([test "x$enable_dtls" != "xno"], [ AX_CHECK_OPENSSL([], [AC_MSG_ERROR(OpenSSL not found!)]) ], [ CFLAGS="$CFLAGS -DCW_NO_DTLS -DCW_NO_DTLSCWParseConfigurationUpdateRequest" ]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT ================================================ FILE: debian-install.sh ================================================ #!/bin/sh autoreconf -fi CFLAGS="-Os -pipe -fno-caller-saves -DCW_NO_DTLS -DWRITE_STD_OUTPUT -DCW_DEBUGGING -DNETUDP -DAC -fgnu89-inline" ./configure make cp AC /usr/sbin/AC mkdir /etc/capwap cp -f config.ac /etc/capwap cp -f settings.ac.txt /etc/capwap cd hostapd_wrapper/hostapd2 ./linux-ac.sh ================================================ FILE: hostapd_wrapper/README.rst ================================================ =================== WRAPPER FOR HOSTAPD =================== Requirements ------------ * patch * hostapd-1.1 Install ------- * copy content of src to hostapd-1.1/src * apply hostapd-capwap.patch Sample ------ cp hostapd-1.1 cp -a ../opencapwap.git/hostapd_wrapper/src . patch -p1 < ../opencapwap.git/hostapd_wrapper/hostapd-capwap.patch Build ----- You can either the build the AC wrapper or the WTP wrapper, but not both at the same time! Check hostapd's build instructions on how to configure and build it. Adjust hostapd-1.1/hostapd/.config and enable either CONFIG_DRIVER_CAPWAP_WTP or CONFIG_DRIVER_CAPWAP Running WTP ----------- * copy hostapd_wtp.conf to /etc/hostapd * copy hostapd.conf-wtp to /etc/hostapd/hostapd.conf * adjust above files for your setup * create an AP interface, e.g.: /usr/sbin/iw phy phy0 interface add wlan0 type managed * start WTP deamon *first* * start hostapd Running AP ----------- * copy hostapd_ap.conf to /etc/hostapd * copy hostapd.conf-ap to /etc/hostapd/hostapd.conf * adjust above files for your setup * start AP deamon *first* * start hostapd Known Problems -------------- The communication protocol between WTP/AC and hostapd is not stable. It does not detect communication failures and therefor has no reconnect behavior. A WTP/AC restart always requires a hostapd restart as well. It also does not handle delayed connects (i.e. hostapd started before WTP/AC is ready). Therefore make sure the WTP/AC deamons are always started before hostapd. The WTP does not handle AC connection lost and AC restart. The WTP needs to be restarted to recover from such a situation. ================================================ FILE: hostapd_wrapper/hostapd-capwap.patch ================================================ diff --git a/hostapd/Makefile b/hostapd/Makefile index e46561e..b027b43 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -765,6 +765,10 @@ ifdef CONFIG_DEBUG_FILE CFLAGS += -DCONFIG_DEBUG_FILE endif +ifdef CONFIG_DRIVER_CAPWAP_WTP +CFLAGS += -DCONFIG_DRIVER_CAPWAP_WTP +endif + ALL=hostapd hostapd_cli all: verify_config $(ALL) diff --git a/src/Makefile b/src/Makefile index d73a175..7c09a0d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps +SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps capwap all: for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index fe20fc2..3c65570 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -361,6 +361,9 @@ struct hostapd_bss_config { /* IEEE 802.11u - Roaming Consortium list */ unsigned int roaming_consortium_count; struct hostapd_roaming_consortium *roaming_consortium; +#ifdef CONFIG_DRIVER_CAPWAP_WTP + int mac_mode; +#endif }; diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 63b708a..bdba1da 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -621,6 +621,9 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) !is_zero_ether_addr(hapd->conf->hessid)) params.hessid = hapd->conf->hessid; params.access_network_type = hapd->conf->access_network_type; +#ifdef CONFIG_DRIVER_CAPWAP_WTP + params.mac_mode = hapd->conf->mac_mode; +#endif if (hostapd_drv_set_ap(hapd, ¶ms)) wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index c7b7363..a22a6c6 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -672,6 +672,13 @@ struct wpa_driver_ap_params { * enabled. */ u8 access_network_type; + +#ifdef CONFIG_DRIVER_CAPWAP_WTP + /** + * CAPWAP MAC Mode + */ + int mac_mode; +#endif }; /** diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index b710778..e8f9c26 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -21,6 +21,12 @@ extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ #ifdef CONFIG_DRIVER_NL80211 extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ #endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_CAPWAP_WTP +extern struct wpa_driver_ops wpa_driver_capwap_wtp_ops; /* driver_capwap_wtp.c */ +#endif /* CONFIG_DRIVER_CAPWAP_WTP */ +#ifdef CONFIG_DRIVER_CAPWAP +extern struct wpa_driver_ops wpa_driver_capwap_ops; /* driver_capwap.c */ +#endif /* CONFIG_DRIVER_CAPWAP */ #ifdef CONFIG_DRIVER_HOSTAP extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ #endif /* CONFIG_DRIVER_HOSTAP */ @@ -71,6 +77,12 @@ struct wpa_driver_ops *wpa_drivers[] = #ifdef CONFIG_DRIVER_NL80211 &wpa_driver_nl80211_ops, #endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_CAPWAP_WTP + &wpa_driver_capwap_wtp_ops, +#endif /* CONFIG_DRIVER_CAPWAP_WTP */ +#ifdef CONFIG_DRIVER_CAPWAP + &wpa_driver_capwap_ops, +#endif /* CONFIG_DRIVER_CAPWAP */ #ifdef CONFIG_DRIVER_HOSTAP &wpa_driver_hostap_ops, #endif /* CONFIG_DRIVER_HOSTAP */ diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index b1f70e0..eca1c7f 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -38,7 +38,7 @@ endif ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += ../src/drivers/driver_nl80211.o -DRV_OBJS += ../src/utils/radiotap.o +NEED_RADIOTAP=y NEED_SME=y NEED_AP_MLME=y NEED_NETLINK=y @@ -156,18 +156,110 @@ DRV_WPA_OBJS += ../src/drivers/driver_wext.o NEED_RFKILL=y endif +ifdef CONFIG_DRIVER_CAPWAP_WTP +DRV_CFLAGS += -DCONFIG_DRIVER_CAPWAP_WTP +DRV_OBJS += ../src/drivers/driver_capwap_wtp.o +NEED_RADIOTAP=y +NEED_SME=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +NEED_CAPWAP_MGMT_FRAME_WTP=y +NEED_CAPWAP_IPC_WTP=y +NEED_SWITCH_8023=y +NEED_RFKILL=y + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +else + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif + + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif +endif +endif + +ifdef CONFIG_DRIVER_CAPWAP +DRV_CFLAGS += -DCONFIG_DRIVER_CAPWAP +DRV_OBJS += ../src/drivers/driver_capwap.o +NEED_RADIOTAP=y +NEED_SME=y +NEED_AP_MLME=y +NEED_FAKE_NETLINK=y +NEED_LINUX_FAKE_IOCTL=y +NEED_CAPWAP_MGMT_FRAME_AC=y +NEED_CAPWAP_IPC_AC=y +NEED_RFKILL=y + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +else + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif + + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif +endif +endif + +ifdef NEED_RADIOTAP +DRV_OBJS += ../src/utils/radiotap.o +endif + ifdef NEED_NETLINK DRV_OBJS += ../src/drivers/netlink.o endif +ifdef NEED_FAKE_NETLINK +DRV_OBJS += ../src/drivers/netlink_fake.o +endif + ifdef NEED_LINUX_IOCTL DRV_OBJS += ../src/drivers/linux_ioctl.o endif +ifdef NEED_LINUX_FAKE_IOCTL +DRV_OBJS += ../src/drivers/linux_ioctl_fake.o +endif + ifdef NEED_RFKILL DRV_OBJS += ../src/drivers/rfkill.o endif +ifdef NEED_CAPWAP_MGMT_FRAME_WTP +DRV_OBJS += ../src/capwap/capwap_mgmt_frame_wtp.o +endif + +ifdef NEED_CAPWAP_MGMT_FRAME_AC +DRV_OBJS += ../src/capwap/capwap_mgmt_frame_ac.o +endif + +ifdef NEED_CAPWAP_IPC_WTP +DRV_OBJS += ../src/capwap/ipc_capwap_wtp.o +endif + +ifdef NEED_CAPWAP_IPC_AC +DRV_OBJS += ../src/capwap/ipc_capwap_ac.o +endif + +ifdef NEED_SWITCH_8023 +DRV_OBJS += ../src/capwap/switch_8023_80211.o +endif ##### COMMON VARS DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk index 2d1ad9d..d6a4c22 100644 --- a/src/drivers/drivers.mk +++ b/src/drivers/drivers.mk @@ -38,7 +38,7 @@ endif ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += src/drivers/driver_nl80211.c -DRV_OBJS += src/utils/radiotap.c +NEED_RADIOTAP=y NEED_SME=y NEED_AP_MLME=y NEED_NETLINK=y @@ -156,18 +156,111 @@ DRV_WPA_OBJS += src/drivers/driver_wext.c NEED_RFKILL=y endif +ifdef CONFIG_DRIVER_CAPWAP_WTP +DRV_CFLAGS += -DCONFIG_DRIVER_CAPWAP_WTP +DRV_OBJS += src/drivers/driver_capwap_wtp.c +NEED_RADIOTAP=y +NEED_SME=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +NEED_CAPWAP_MGMT_FRAME_WTP=y +NEED_CAPWAP_IPC_WTP=y +NEED_SWITCH_8023=y +NEED_RFKILL=y + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +else + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif + + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif +endif +endif + +ifdef CONFIG_DRIVER_CAPWAP +DRV_CFLAGS += -DCONFIG_DRIVER_CAPWAP +DRV_OBJS += src/drivers/driver_capwap.c +NEED_RADIOTAP=y +NEED_SME=y +NEED_AP_MLME=y +NEED_FAKE_NETLINK=y +NEED_LINUX_FAKE_IOCTL=y +NEED_CAPWAP_MGMT_FRAME_AC=y +NEED_CAPWAP_IPC_AC=y +NEED_RFKILL=y + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +else + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif + + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif +endif +endif + +ifdef NEED_RADIOTAP +DRV_OBJS += src/utils/radiotap.c +endif + ifdef NEED_NETLINK DRV_OBJS += src/drivers/netlink.c endif +ifdef NEED_FAKE_NETLINK +DRV_OBJS += src/drivers/netlink_fake.c +endif + ifdef NEED_LINUX_IOCTL DRV_OBJS += src/drivers/linux_ioctl.c endif +ifdef NEED_LINUX_FAKE_IOCTL +DRV_OBJS += src/drivers/linux_ioctl_fake.c +endif + ifdef NEED_RFKILL DRV_OBJS += src/drivers/rfkill.c endif +ifdef NEED_CAPWAP_MGMT_FRAME_WTP +DRV_OBJS += src/capwap/capwap_mgmt_frame_wtp.c +endif + +ifdef NEED_CAPWAP_MGMT_FRAME_AC +DRV_OBJS += src/capwap/capwap_mgmt_frame_ac.c +endif + +ifdef NEED_CAPWAP_IPC_WTP +DRV_OBJS += src/capwap/ipc_capwap_wtp.c +endif + +ifdef NEED_CAPWAP_IPC_AC +DRV_OBJS += src/capwap/ipc_capwap_ac.c +endif + +ifdef NEED_SWITCH_8023 +DRV_OBJS += src/capwap/switch_8023_80211.c +endif + ifdef CONFIG_DRIVER_CUSTOM DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM endif ================================================ FILE: hostapd_wrapper/hostapd.conf-ac ================================================ ##### hostapd configuration file ############################################## # Empty lines and lines starting with # are ignored # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for # management frames); ath0 for madwifi interface=wlan0 # In case of madwifi, atheros, and nl80211 driver interfaces, an additional # configuration parameter, bridge, may be used to notify hostapd if the # interface is included in a bridge. This parameter is not used with Host AP # driver. If the bridge parameter is not set, the drivers will automatically # figure out the bridge interface (assuming sysfs is enabled and mounted to # /sys) and this parameter may not be needed. # # For nl80211, this parameter can be used to request the AP interface to be # added to the bridge automatically (brctl may refuse to do this before hostapd # has been started to change the interface mode). If needed, the bridge # interface is also created. #bridge=br0 # Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd); # default: hostap). nl80211 is used with all Linux mac80211 drivers. # Use driver=none if building hostapd as a standalone RADIUS server that does # not control any wireless/wired driver. # driver=hostap driver=capwap # hostapd event logger configuration # # Two output method: syslog and stdout (only usable if not forking to # background). # # Module bitfield (ORed bitfield of modules that will be logged; -1 = all # modules): # bit 0 (1) = IEEE 802.11 # bit 1 (2) = IEEE 802.1X # bit 2 (4) = RADIUS # bit 3 (8) = WPA # bit 4 (16) = driver interface # bit 5 (32) = IAPP # bit 6 (64) = MLME # # Levels (minimum value for logged events): # 0 = verbose debugging # 1 = debugging # 2 = informational messages # 3 = notification # 4 = warning # logger_syslog=-1 logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 # Dump file for state information (on SIGUSR1) dump_file=/tmp/hostapd.dump # Interface for separate control program. If this is specified, hostapd # will create this directory and a UNIX domain socket for listening to requests # from external programs (CLI/GUI, etc.) for status information and # configuration. The socket file will be named based on the interface name, so # multiple hostapd processes/interfaces can be run at the same time if more # than one interface is used. # /var/run/hostapd is the recommended directory for sockets and by default, # hostapd_cli will use it when trying to connect with hostapd. ctrl_interface=/var/run/hostapd # Access control for the control interface can be configured by setting the # directory to allow only members of a group to use sockets. This way, it is # possible to run hostapd as root (since it needs to change network # configuration and open raw sockets) and still allow GUI/CLI components to be # run as non-root users. However, since the control interface can be used to # change the network configuration, this access needs to be protected in many # cases. By default, hostapd is configured to use gid 0 (root). If you # want to allow non-root users to use the contron interface, add a new group # and change this value to match with that group. Add users that should have # control interface access to this group. # # This variable can be a group name or gid. #ctrl_interface_group=wheel ctrl_interface_group=0 ##### IEEE 802.11 related configuration ####################################### # SSID to be used in IEEE 802.11 management frames ssid=test # Country code (ISO/IEC 3166-1). Used to set regulatory domain. # Set as needed to indicate country in which device is operating. # This can limit available channels and transmit power. #country_code=US # Enable IEEE 802.11d. This advertises the country_code and the set of allowed # channels and transmit power levels based on the regulatory limits. The # country_code setting must be configured with the correct country for # IEEE 802.11d functions. # (default: 0 = disabled) #ieee80211d=1 # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, # Default: IEEE 802.11b hw_mode=b # Channel number (IEEE 802.11) # (default: 0, i.e., not set) # Please note that some drivers do not use this value from hostapd and the # channel will need to be configured separately with iwconfig. channel=1 # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 # DTIM (delivery traffic information message) period (range 1..255): # number of beacons between DTIMs (1 = every beacon includes DTIM element) # (default: 2) dtim_period=2 # Maximum number of stations allowed in station table. New stations will be # rejected after the station table is full. IEEE 802.11 has a limit of 2007 # different association IDs, so this number should not be larger than that. # (default: 2007) max_num_sta=255 # RTS/CTS threshold; 2347 = disabled (default); range 0..2347 # If this field is not included in hostapd.conf, hostapd will not control # RTS threshold and 'iwconfig wlan# rts ' can be used to set it. rts_threshold=2347 # Fragmentation threshold; 2346 = disabled (default); range 256..2346 # If this field is not included in hostapd.conf, hostapd will not control # fragmentation threshold and 'iwconfig wlan# frag ' can be used to set # it. fragm_threshold=2346 # Rate configuration # Default is to enable all rates supported by the hardware. This configuration # item allows this list be filtered so that only the listed rates will be left # in the list. If the list is empty, all rates are used. This list can have # entries that are not in the list of rates the hardware supports (such entries # are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110. # If this item is present, at least one rate have to be matching with the rates # hardware supports. # default: use the most common supported rate setting for the selected # hw_mode (i.e., this line can be removed from configuration file in most # cases) #supported_rates=10 20 55 110 60 90 120 180 240 360 480 540 # Basic rate set configuration # List of rates (in 100 kbps) that are included in the basic rate set. # If this item is not included, usually reasonable default set is used. #basic_rates=10 20 #basic_rates=10 20 55 110 #basic_rates=60 120 240 # Short Preamble # This parameter can be used to enable optional use of short preamble for # frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance. # This applies only to IEEE 802.11b-compatible networks and this should only be # enabled if the local hardware supports use of short preamble. If any of the # associated STAs do not support short preamble, use of short preamble will be # disabled (and enabled when such STAs disassociate) dynamically. # 0 = do not allow use of short preamble (default) # 1 = allow use of short preamble #preamble=1 # Station MAC address -based authentication # Please note that this kind of access control requires a driver that uses # hostapd to take care of management frame processing and as such, this can be # used with driver=hostap or driver=nl80211, but not with driver=madwifi. # 0 = accept unless in deny list # 1 = deny unless in accept list # 2 = use external RADIUS server (accept/deny lists are searched first) macaddr_acl=0 # Accept/deny lists are read from separate files (containing list of # MAC addresses, one per line). Use absolute path name to make sure that the # files can be read on SIGHUP configuration reloads. #accept_mac_file=/etc/hostapd.accept #deny_mac_file=/etc/hostapd.deny # IEEE 802.11 specifies two authentication algorithms. hostapd can be # configured to allow both of these or only one. Open system authentication # should be used with IEEE 802.1X. # Bit fields of allowed authentication algorithms: # bit 0 = Open System Authentication # bit 1 = Shared Key Authentication (requires WEP) auth_algs=3 # Send empty SSID in beacons and ignore probe request frames that do not # specify full SSID, i.e., require stations to know SSID. # default: disabled (0) # 1 = send empty (length=0) SSID in beacon and ignore probe request for # broadcast SSID # 2 = clear SSID (ASCII 0), but keep the original length (this may be required # with some clients that do not support empty SSID) and ignore probe # requests for broadcast SSID ignore_broadcast_ssid=0 # TX queue parameters (EDCF / bursting) # tx_queue__ # queues: data0, data1, data2, data3, after_beacon, beacon # (data0 is the highest priority queue) # parameters: # aifs: AIFS (default 2) # cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023) # cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin # burst: maximum length (in milliseconds with precision of up to 0.1 ms) for # bursting # # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # These parameters are used by the access point when transmitting frames # to the clients. # # Low priority / AC_BK = background #tx_queue_data3_aifs=7 #tx_queue_data3_cwmin=15 #tx_queue_data3_cwmax=1023 #tx_queue_data3_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0 # # Normal priority / AC_BE = best effort #tx_queue_data2_aifs=3 #tx_queue_data2_cwmin=15 #tx_queue_data2_cwmax=63 #tx_queue_data2_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0 # # High priority / AC_VI = video #tx_queue_data1_aifs=1 #tx_queue_data1_cwmin=7 #tx_queue_data1_cwmax=15 #tx_queue_data1_burst=3.0 # Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0 # # Highest priority / AC_VO = voice #tx_queue_data0_aifs=1 #tx_queue_data0_cwmin=3 #tx_queue_data0_cwmax=7 #tx_queue_data0_burst=1.5 # Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3 # 802.1D Tag (= UP) to AC mappings # WMM specifies following mapping of data frames to different ACs. This mapping # can be configured using Linux QoS/tc and sch_pktpri.o module. # 802.1D Tag 802.1D Designation Access Category WMM Designation # 1 BK AC_BK Background # 2 - AC_BK Background # 0 BE AC_BE Best Effort # 3 EE AC_BE Best Effort # 4 CL AC_VI Video # 5 VI AC_VI Video # 6 VO AC_VO Voice # 7 NC AC_VO Voice # Data frames with no priority information: AC_BE # Management frames: AC_VO # PS-Poll frames: AC_BE # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # for 802.11a or 802.11g networks # These parameters are sent to WMM clients when they associate. # The parameters will be used by WMM clients for frames transmitted to the # access point. # # note - txop_limit is in units of 32microseconds # note - acm is admission control mandatory flag. 0 = admission control not # required, 1 = mandatory # note - here cwMin and cmMax are in exponent form. the actual cw value used # will be (2^n)-1 where n is the value given here # wmm_enabled=1 # # WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] # Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver) #uapsd_advertisement_enabled=1 # # Low priority / AC_BK = background wmm_ac_bk_cwmin=4 wmm_ac_bk_cwmax=10 wmm_ac_bk_aifs=7 wmm_ac_bk_txop_limit=0 wmm_ac_bk_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=10 # # Normal priority / AC_BE = best effort wmm_ac_be_aifs=3 wmm_ac_be_cwmin=4 wmm_ac_be_cwmax=10 wmm_ac_be_txop_limit=0 wmm_ac_be_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=7 # # High priority / AC_VI = video wmm_ac_vi_aifs=2 wmm_ac_vi_cwmin=3 wmm_ac_vi_cwmax=4 wmm_ac_vi_txop_limit=94 wmm_ac_vi_acm=0 # Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188 # # Highest priority / AC_VO = voice wmm_ac_vo_aifs=2 wmm_ac_vo_cwmin=2 wmm_ac_vo_cwmax=3 wmm_ac_vo_txop_limit=47 wmm_ac_vo_acm=0 # Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 # Static WEP key configuration # # The key number to use when transmitting. # It must be between 0 and 3, and the corresponding key must be set. # default: not set #wep_default_key=0 # The WEP keys to use. # A key may be a quoted string or unquoted hexadecimal digits. # The key length should be 5, 13, or 16 characters, or 10, 26, or 32 # digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or # 128-bit (152-bit) WEP is used. # Only the default key must be supplied; the others are optional. # default: not set #wep_key0=123456789a #wep_key1="vwxyz" #wep_key2=0102030405060708090a0b0c0d #wep_key3=".2.4.6.8.0.23" # Station inactivity limit # # If a station does not send anything in ap_max_inactivity seconds, an # empty data frame is sent to it in order to verify whether it is # still in range. If this frame is not ACKed, the station will be # disassociated and then deauthenticated. This feature is used to # clear station table of old entries when the STAs move out of the # range. # # The station can associate again with the AP if it is still in range; # this inactivity poll is just used as a nicer way of verifying # inactivity; i.e., client will not report broken connection because # disassociation frame is not sent immediately without first polling # the STA with a data frame. # default: 300 (i.e., 5 minutes) #ap_max_inactivity=300 # Disassociate stations based on excessive transmission failures or other # indications of connection loss. This depends on the driver capabilities and # may not be available with all drivers. #disassoc_low_ack=1 # Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to # remain asleep). Default: 65535 (no limit apart from field size) #max_listen_interval=100 # WDS (4-address frame) mode with per-station virtual interfaces # (only supported with driver=nl80211) # This mode allows associated stations to use 4-address frames to allow layer 2 # bridging to be used. #wds_sta=1 # If bridge parameter is set, the WDS STA interface will be added to the same # bridge by default. This can be overridden with the wds_bridge parameter to # use a separate bridge. #wds_bridge=wds-br0 # Client isolation can be used to prevent low-level bridging of frames between # associated stations in the BSS. By default, this bridging is allowed. #ap_isolate=1 ##### IEEE 802.11n related configuration ###################################### # ieee80211n: Whether IEEE 802.11n (HT) is enabled # 0 = disabled (default) # 1 = enabled # Note: You will also need to enable WMM for full HT functionality. #ieee80211n=1 # ht_capab: HT capabilities (list of flags) # LDPC coding capability: [LDPC] = supported # Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary # channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz # with secondary channel below the primary channel # (20 MHz only if neither is set) # Note: There are limits on which channels can be used with HT40- and # HT40+. Following table shows the channels that may be available for # HT40- and HT40+ use per IEEE 802.11n Annex J: # freq HT40- HT40+ # 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan) # 5 GHz 40,48,56,64 36,44,52,60 # (depending on the location, not all of these channels may be available # for use) # Please note that 40 MHz channels may switch their primary and secondary # channels if needed or creation of 40 MHz channel maybe rejected based # on overlapping BSSes. These changes are done automatically when hostapd # is setting up the 40 MHz channel. # Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC] # (SMPS disabled if neither is set) # HT-greenfield: [GF] (disabled if not set) # Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) # Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) # Tx STBC: [TX-STBC] (disabled if not set) # Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial # streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC # disabled if none of these set # HT-delayed Block Ack: [DELAYED-BA] (disabled if not set) # Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not # set) # DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) # PSMP support: [PSMP] (disabled if not set) # L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) #ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] # Require stations to support HT PHY (reject association if they do not) #require_ht=1 ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization #ieee8021x=1 # IEEE 802.1X/EAPOL version # hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL # version 2. However, there are many client implementations that do not handle # the new version number correctly (they seem to drop the frames completely). # In order to make hostapd interoperate with these clients, the version number # can be set to the older version (1) with this configuration value. #eapol_version=2 # Optional displayable message sent with EAP Request-Identity. The first \0 # in this string will be converted to ASCII-0 (nul). This can be used to # separate network info (comma separated list of attribute=value pairs); see, # e.g., RFC 4284. #eap_message=hello #eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com # WEP rekeying (disabled if key lengths are not set or are set to 0) # Key lengths for default/broadcast and individual/unicast keys: # 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits) # 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits) #wep_key_len_broadcast=5 #wep_key_len_unicast=5 # Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once) #wep_rekey_period=300 # EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if # only broadcast keys are used) eapol_key_index_workaround=0 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable # reauthentication). #eap_reauth_period=3600 # Use PAE group address (01:80:c2:00:00:03) instead of individual target # address when sending EAPOL frames with driver=wired. This is the most common # mechanism used in wired authentication, but it also requires that the port # is only used by one station. #use_pae_group_addr=1 ##### Integrated EAP server ################################################### # Optionally, hostapd can be configured to use an integrated EAP server # to process EAP authentication locally without need for an external RADIUS # server. This functionality can be used both as a local authentication server # for IEEE 802.1X/EAPOL and as a RADIUS server for other devices. # Use integrated EAP server instead of external RADIUS authentication # server. This is also needed if hostapd is configured to act as a RADIUS # authentication server. eap_server=0 # Path for EAP server user database #eap_user_file=/etc/hostapd.eap_user # CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS #ca_cert=/etc/hostapd.ca.pem # Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS #server_cert=/etc/hostapd.server.pem # Private key matching with the server certificate for EAP-TLS/PEAP/TTLS # This may point to the same file as server_cert if both certificate and key # are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be # used by commenting out server_cert and specifying the PFX file as the # private_key. #private_key=/etc/hostapd.server.prv # Passphrase for private key #private_key_passwd=secret passphrase # Enable CRL verification. # Note: hostapd does not yet support CRL downloading based on CDP. Thus, a # valid CRL signed by the CA is required to be included in the ca_cert file. # This can be done by using PEM format for CA certificate and CRL and # concatenating these into one file. Whenever CRL changes, hostapd needs to be # restarted to take the new CRL into use. # 0 = do not verify CRLs (default) # 1 = check the CRL of the user certificate # 2 = check all CRLs in the certificate path #check_crl=1 # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an # ephemeral DH key exchange. In most cases, the default RSA authentication does # not use this configuration. However, it is possible setup RSA to use # ephemeral DH key exchange. In addition, ciphers with DSA keys always use # ephemeral DH keys. This can be used to achieve forward secrecy. If the file # is in DSA parameters format, it will be automatically converted into DH # params. This parameter is required if anonymous EAP-FAST is used. # You can generate DH parameters file with OpenSSL, e.g., # "openssl dhparam -out /etc/hostapd.dh.pem 1024" #dh_file=/etc/hostapd.dh.pem # Fragment size for EAP methods #fragment_size=1400 # Configuration data for EAP-SIM database/authentication gateway interface. # This is a text string in implementation specific format. The example # implementation in eap_sim_db.c uses this as the UNIX domain socket name for # the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:" # prefix. #eap_sim_db=unix:/tmp/hlr_auc_gw.sock # Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, # random value. It is configured as a 16-octet value in hex format. It can be # generated, e.g., with the following command: # od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' ' #pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f # EAP-FAST authority identity (A-ID) # A-ID indicates the identity of the authority that issues PACs. The A-ID # should be unique across all issuing servers. In theory, this is a variable # length field, but due to some existing implementations requiring A-ID to be # 16 octets in length, it is strongly recommended to use that length for the # field to provid interoperability with deployed peer implementations. This # field is configured in hex format. #eap_fast_a_id=101112131415161718191a1b1c1d1e1f # EAP-FAST authority identifier information (A-ID-Info) # This is a user-friendly name for the A-ID. For example, the enterprise name # and server name in a human-readable format. This field is encoded as UTF-8. #eap_fast_a_id_info=test server # Enable/disable different EAP-FAST provisioning modes: #0 = provisioning disabled #1 = only anonymous provisioning allowed #2 = only authenticated provisioning allowed #3 = both provisioning modes allowed (default) #eap_fast_prov=3 # EAP-FAST PAC-Key lifetime in seconds (hard limit) #pac_key_lifetime=604800 # EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard # limit). The server will generate a new PAC-Key when this number of seconds # (or fewer) of the lifetime remains. #pac_key_refresh_time=86400 # EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND # (default: 0 = disabled). #eap_sim_aka_result_ind=1 # Trusted Network Connect (TNC) # If enabled, TNC validation will be required before the peer is allowed to # connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other # EAP method is enabled, the peer will be allowed to connect without TNC. #tnc=1 ##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) ####################### # Interface to be used for IAPP broadcast packets #iapp_interface=eth0 ##### RADIUS client configuration ############################################# # for IEEE 802.1X with external Authentication Server, IEEE 802.11 # authentication with external ACL for MAC addresses, and accounting # The own IP address of the access point (used as NAS-IP-Address) own_ip_addr=127.0.0.1 # Optional NAS-Identifier string for RADIUS messages. When used, this should be # a unique to the NAS within the scope of the RADIUS server. For example, a # fully qualified domain name can be used here. # When using IEEE 802.11r, nas_identifier must be set and must be between 1 and # 48 octets long. #nas_identifier=ap.example.com # RADIUS authentication server #auth_server_addr=127.0.0.1 #auth_server_port=1812 #auth_server_shared_secret=secret # RADIUS accounting server #acct_server_addr=127.0.0.1 #acct_server_port=1813 #acct_server_shared_secret=secret # Secondary RADIUS servers; to be used if primary one does not reply to # RADIUS packets. These are optional and there can be more than one secondary # server listed. #auth_server_addr=127.0.0.2 #auth_server_port=1812 #auth_server_shared_secret=secret2 # #acct_server_addr=127.0.0.2 #acct_server_port=1813 #acct_server_shared_secret=secret2 # Retry interval for trying to return to the primary RADIUS server (in # seconds). RADIUS client code will automatically try to use the next server # when the current server is not replying to requests. If this interval is set, # primary server will be retried after configured amount of time even if the # currently used secondary server is still working. #radius_retry_primary_interval=600 # Interim accounting update interval # If this is set (larger than 0) and acct_server is configured, hostapd will # send interim accounting updates every N seconds. Note: if set, this overrides # possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this # value should not be configured in hostapd.conf, if RADIUS server is used to # control the interim interval. # This value should not be less 600 (10 minutes) and must not be less than # 60 (1 minute). #radius_acct_interim_interval=600 # Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN # is used for the stations. This information is parsed from following RADIUS # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value # VLANID as a string). vlan_file option below must be configured if dynamic # VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be # used to set static client MAC address to VLAN ID mapping. # 0 = disabled (default) # 1 = option; use default interface if RADIUS server does not include VLAN ID # 2 = required; reject authentication if RADIUS server does not include VLAN ID #dynamic_vlan=0 # VLAN interface list for dynamic VLAN mode is read from a separate text file. # This list is used to map VLAN ID from the RADIUS server to a network # interface. Each station is bound to one interface in the same way as with # multiple BSSIDs or SSIDs. Each line in this text file is defining a new # interface and the line must include VLAN ID and interface name separated by # white space (space or tab). #vlan_file=/etc/hostapd.vlan # Interface where 802.1q tagged packets should appear when a RADIUS server is # used to determine which VLAN a station is on. hostapd creates a bridge for # each VLAN. Then hostapd adds a VLAN interface (associated with the interface # indicated by 'vlan_tagged_interface') and the appropriate wireless interface # to the bridge. #vlan_tagged_interface=eth0 ##### RADIUS authentication server configuration ############################## # hostapd can be used as a RADIUS authentication server for other hosts. This # requires that the integrated EAP server is also enabled and both # authentication services are sharing the same configuration. # File name of the RADIUS clients configuration for the RADIUS server. If this # commented out, RADIUS server is disabled. #radius_server_clients=/etc/hostapd.radius_clients # The UDP port number for the RADIUS authentication server #radius_server_auth_port=1812 # Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API) #radius_server_ipv6=1 ##### WPA/IEEE 802.11i configuration ########################################## # Enable WPA. Setting this variable configures the AP to require WPA (either # WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either # wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. # For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), # RADIUS authentication server must be configured, and WPA-EAP must be included # in wpa_key_mgmt. # This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) # and/or WPA2 (full IEEE 802.11i/RSN): # bit0 = WPA # bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) #wpa=1 # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase # (8..63 characters) that will be converted to PSK. This conversion uses SSID # so the PSK changes when ASCII passphrase is used and the SSID is changed. # wpa_psk (dot11RSNAConfigPSKValue) # wpa_passphrase (dot11RSNAConfigPSKPassPhrase) #wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef #wpa_passphrase=secret passphrase # Optionally, WPA PSKs can be read from a separate text file (containing list # of (PSK,MAC address) pairs. This allows more than one PSK to be configured. # Use absolute path name to make sure that the files can be read on SIGHUP # configuration reloads. #wpa_psk_file=/etc/hostapd.wpa_psk # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The # entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be # added to enable SHA256-based stronger algorithms. # (dot11RSNAConfigAuthenticationSuitesTable) #wpa_key_mgmt=WPA-PSK WPA-EAP # Set of accepted cipher suites (encryption algorithms) for pairwise keys # (unicast packets). This is a space separated list of algorithms: # CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] # TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] # Group cipher suite (encryption algorithm for broadcast and multicast frames) # is automatically selected based on this configuration. If only CCMP is # allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, # TKIP will be used as the group cipher. # (dot11RSNAConfigPairwiseCiphersTable) # Pairwise cipher for WPA (v1) (default: TKIP) #wpa_pairwise=TKIP CCMP # Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) #rsn_pairwise=CCMP # Time interval for rekeying GTK (broadcast/multicast encryption keys) in # seconds. (dot11RSNAConfigGroupRekeyTime) #wpa_group_rekey=600 # Rekey GTK when any STA that possesses the current GTK is leaving the BSS. # (dot11RSNAConfigGroupRekeyStrict) #wpa_strict_rekey=1 # Time interval for rekeying GMK (master key used internally to generate GTKs # (in seconds). #wpa_gmk_rekey=86400 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of # PTK to mitigate some attacks against TKIP deficiencies. #wpa_ptk_rekey=600 # Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up # roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN # authentication and key handshake before actually associating with a new AP. # (dot11RSNAPreauthenticationEnabled) #rsn_preauth=1 # # Space separated list of interfaces from which pre-authentication frames are # accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all # interface that are used for connections to other APs. This could include # wired interfaces and WDS links. The normal wireless data interface towards # associated stations (e.g., wlan0) should not be added, since # pre-authentication is only used with APs other than the currently associated # one. #rsn_preauth_interfaces=eth0 # peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is # allowed. This is only used with RSN/WPA2. # 0 = disabled (default) # 1 = enabled #peerkey=1 # ieee80211w: Whether management frame protection (MFP) is enabled # 0 = disabled (default) # 1 = optional # 2 = required #ieee80211w=0 # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) # (maximum time to wait for a SA Query response) # dot11AssociationSAQueryMaximumTimeout, 1...4294967295 #assoc_sa_query_max_timeout=1000 # Association SA Query retry timeout (in TU = 1.024 ms; for MFP) # (time between two subsequent SA Query requests) # dot11AssociationSAQueryRetryTimeout, 1...4294967295 #assoc_sa_query_retry_timeout=201 # disable_pmksa_caching: Disable PMKSA caching # This parameter can be used to disable caching of PMKSA created through EAP # authentication. RSN preauthentication may still end up using PMKSA caching if # it is enabled (rsn_preauth=1). # 0 = PMKSA caching enabled (default) # 1 = PMKSA caching disabled #disable_pmksa_caching=0 # okc: Opportunistic Key Caching (aka Proactive Key Caching) # Allow PMK cache to be shared opportunistically among configured interfaces # and BSSes (i.e., all configurations within a single hostapd process). # 0 = disabled (default) # 1 = enabled #okc=1 ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) # MDID is used to indicate a group of APs (within an ESS, i.e., sharing the # same SSID) between which a STA can use Fast BSS Transition. # 2-octet identifier as a hex string. #mobility_domain=a1b2 # PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID) # 1 to 48 octet identifier. # This is configured with nas_identifier (see RADIUS client section above). # Default lifetime of the PMK-RO in minutes; range 1..65535 # (dot11FTR0KeyLifetime) #r0_key_lifetime=10000 # PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID) # 6-octet identifier as a hex string. #r1_key_holder=000102030405 # Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535) # (dot11FTReassociationDeadline) #reassociation_deadline=1000 # List of R0KHs in the same Mobility Domain # format: <128-bit key as hex string> # This list is used to map R0KH-ID (NAS Identifier) to a destination MAC # address when requesting PMK-R1 key from the R0KH that the STA used during the # Initial Mobility Domain Association. #r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f #r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff # And so on.. One line per R0KH. # List of R1KHs in the same Mobility Domain # format: <128-bit key as hex string> # This list is used to map R1KH-ID to a destination MAC address when sending # PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD # that can request PMK-R1 keys. #r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f #r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff # And so on.. One line per R1KH. # Whether PMK-R1 push is enabled at R0KH # 0 = do not push PMK-R1 to all configured R1KHs (default) # 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived #pmk_r1_push=1 ##### Neighbor table ########################################################## # Maximum number of entries kept in AP table (either for neigbor table or for # detecting Overlapping Legacy BSS Condition). The oldest entry will be # removed when adding a new entry that would make the list grow over this # limit. Note! WFA certification for IEEE 802.11g requires that OLBC is # enabled, so this field should not be set to 0 when using IEEE 802.11g. # default: 255 #ap_table_max_size=255 # Number of seconds of no frames received after which entries may be deleted # from the AP table. Since passive scanning is not usually performed frequently # this should not be set to very small value. In addition, there is no # guarantee that every scan cycle will receive beacon frames from the # neighboring APs. # default: 60 #ap_table_expiration_time=3600 ##### Wi-Fi Protected Setup (WPS) ############################################# # WPS state # 0 = WPS disabled (default) # 1 = WPS enabled, not configured # 2 = WPS enabled, configured #wps_state=2 # AP can be configured into a locked state where new WPS Registrar are not # accepted, but previously authorized Registrars (including the internal one) # can continue to add new Enrollees. #ap_setup_locked=1 # Universally Unique IDentifier (UUID; see RFC 4122) of the device # This value is used as the UUID for the internal WPS Registrar. If the AP # is also using UPnP, this value should be set to the device's UPnP UUID. # If not configured, UUID will be generated based on the local MAC address. #uuid=12345678-9abc-def0-1234-56789abcdef0 # Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs # that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the # default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of # per-device PSKs is recommended as the more secure option (i.e., make sure to # set wpa_psk_file when using WPS with WPA-PSK). # When an Enrollee requests access to the network with PIN method, the Enrollee # PIN will need to be entered for the Registrar. PIN request notifications are # sent to hostapd ctrl_iface monitor. In addition, they can be written to a # text file that could be used, e.g., to populate the AP administration UI with # pending PIN requests. If the following variable is set, the PIN requests will # be written to the configured file. #wps_pin_requests=/var/run/hostapd_wps_pin_requests # Device Name # User-friendly description of device; up to 32 octets encoded in UTF-8 #device_name=Wireless AP # Manufacturer # The manufacturer of the device (up to 64 ASCII characters) #manufacturer=Company # Model Name # Model of the device (up to 32 ASCII characters) #model_name=WAP # Model Number # Additional device description (up to 32 ASCII characters) #model_number=123 # Serial Number # Serial number of the device (up to 32 characters) #serial_number=12345 # Primary Device Type # Used format: -- # categ = Category as an integer value # OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for # default WPS OUI # subcateg = OUI-specific Sub Category as an integer value # Examples: # 1-0050F204-1 (Computer / PC) # 1-0050F204-2 (Computer / Server) # 5-0050F204-1 (Storage / NAS) # 6-0050F204-1 (Network Infrastructure / AP) #device_type=6-0050F204-1 # OS Version # 4-octet operating system version number (hex string) #os_version=01020300 # Config Methods # List of the supported configuration methods # Available methods: usba ethernet label display ext_nfc_token int_nfc_token # nfc_interface push_button keypad virtual_display physical_display # virtual_push_button physical_push_button #config_methods=label virtual_display virtual_push_button keypad # WPS capability discovery workaround for PBC with Windows 7 # Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting # as a Registrar and using M1 from the AP. The config methods attribute in that # message is supposed to indicate only the configuration method supported by # the AP in Enrollee role, i.e., to add an external Registrar. For that case, # PBC shall not be used and as such, the PushButton config method is removed # from M1 by default. If pbc_in_m1=1 is included in the configuration file, # the PushButton config method is left in M1 (if included in config_methods # parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label # in the AP). #pbc_in_m1=1 # Static access point PIN for initial configuration and adding Registrars # If not set, hostapd will not allow external WPS Registrars to control the # access point. The AP PIN can also be set at runtime with hostapd_cli # wps_ap_pin command. Use of temporary (enabled by user action) and random # AP PIN is much more secure than configuring a static AP PIN here. As such, # use of the ap_pin parameter is not recommended if the AP device has means for # displaying a random PIN. #ap_pin=12345670 # Skip building of automatic WPS credential # This can be used to allow the automatically generated Credential attribute to # be replaced with pre-configured Credential(s). #skip_cred_build=1 # Additional Credential attribute(s) # This option can be used to add pre-configured Credential attributes into M8 # message when acting as a Registrar. If skip_cred_build=1, this data will also # be able to override the Credential attribute that would have otherwise been # automatically generated based on network configuration. This configuration # option points to an external file that much contain the WPS Credential # attribute(s) as binary data. #extra_cred=hostapd.cred # Credential processing # 0 = process received credentials internally (default) # 1 = do not process received credentials; just pass them over ctrl_iface to # external program(s) # 2 = process received credentials internally and pass them over ctrl_iface # to external program(s) # Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and # extra_cred be used to provide the Credential data for Enrollees. # # wps_cred_processing=1 will disabled automatic updates of hostapd.conf file # both for Credential processing and for marking AP Setup Locked based on # validation failures of AP PIN. An external program is responsible on updating # the configuration appropriately in this case. #wps_cred_processing=0 # AP Settings Attributes for M7 # By default, hostapd generates the AP Settings Attributes for M7 based on the # current configuration. It is possible to override this by providing a file # with pre-configured attributes. This is similar to extra_cred file format, # but the AP Settings attributes are not encapsulated in a Credential # attribute. #ap_settings=hostapd.ap_settings # WPS UPnP interface # If set, support for external Registrars is enabled. #upnp_iface=br0 # Friendly Name (required for UPnP) # Short description for end use. Should be less than 64 characters. #friendly_name=WPS Access Point # Manufacturer URL (optional for UPnP) #manufacturer_url=http://www.example.com/ # Model Description (recommended for UPnP) # Long description for end user. Should be less than 128 characters. #model_description=Wireless Access Point # Model URL (optional for UPnP) #model_url=http://www.example.com/model/ # Universal Product Code (optional for UPnP) # 12-digit, all-numeric code that identifies the consumer package. #upc=123456789012 ##### Wi-Fi Direct (P2P) ###################################################### # Enable P2P Device management #manage_p2p=1 # Allow cross connection #allow_cross_connection=1 #### TDLS (IEEE 802.11z-2010) ################################################# # Prohibit use of TDLS in this BSS #tdls_prohibit=1 # Prohibit use of TDLS Channel Switching in this BSS #tdls_prohibit_chan_switch=1 ##### IEEE 802.11v-2011 ####################################################### # Time advertisement # 0 = disabled (default) # 2 = UTC time at which the TSF timer is 0 #time_advertisement=2 # Local time zone as specified in 8.3 of IEEE Std 1003.1-2004: # stdoffset[dst[offset][,start[/time],end[/time]]] #time_zone=EST5 ##### IEEE 802.11u-2011 ####################################################### # Enable Interworking service #interworking=1 # Access Network Type # 0 = Private network # 1 = Private network with guest access # 2 = Chargeable public network # 3 = Free public network # 4 = Personal device network # 5 = Emergency services only network # 14 = Test or experimental # 15 = Wildcard #access_network_type=0 # Whether the network provides connectivity to the Internet # 0 = Unspecified # 1 = Network provides connectivity to the Internet #internet=1 # Additional Step Required for Access # Note: This is only used with open network, i.e., ASRA shall ne set to 0 if # RSN is used. #asra=0 # Emergency services reachable #esr=0 # Unauthenticated emergency service accessible #uesa=0 # Venue Info (optional) # The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34. # Example values (group,type): # 0,0 = Unspecified # 1,7 = Convention Center # 1,13 = Coffee Shop # 2,0 = Unspecified Business # 7,1 Private Residence #venue_group=7 #venue_type=1 # Homogeneous ESS identifier (optional; dot11HESSID) # If set, this shall be identifical to one of the BSSIDs in the homogeneous # ESS and this shall be set to the same value across all BSSs in homogeneous # ESS. #hessid=02:03:04:05:06:07 # Roaming Consortium List # Arbitrary number of Roaming Consortium OIs can be configured with each line # adding a new OI to the list. The first three entries are available through # Beacon and Probe Response frames. Any additional entry will be available only # through ANQP queries. Each OI is between 3 and 15 octets and is configured a # a hexstring. #roaming_consortium=021122 #roaming_consortium=2233445566 ##### Multiple BSSID support ################################################## # # Above configuration is using the default interface (wlan#, or multi-SSID VLAN # interfaces). Other BSSIDs can be added by using separator 'bss' with # default interface name to be allocated for the data packets of the new BSS. # # hostapd will generate BSSID mask based on the BSSIDs that are # configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is # not the case, the MAC address of the radio must be changed before starting # hostapd (ifconfig wlan0 hw ether ). If a BSSID is configured for # every secondary BSS, this limitation is not applied at hostapd and other # masks may be used if the driver supports them (e.g., swap the locally # administered bit) # # BSSIDs are assigned in order to each BSS, unless an explicit BSSID is # specified using the 'bssid' parameter. # If an explicit BSSID is specified, it must be chosen such that it: # - results in a valid MASK that covers it and the dev_addr # - is not the same as the MAC address of the radio # - is not the same as any other explicitly specified BSSID # # Please note that hostapd uses some of the values configured for the first BSS # as the defaults for the following BSSes. However, it is recommended that all # BSSes include explicit configuration of all relevant configuration items. # #bss=wlan0_0 #ssid=test2 # most of the above items can be used here (apart from radio interface specific # items, like channel) #bss=wlan0_1 #bssid=00:13:10:95:fe:0b # ... ================================================ FILE: hostapd_wrapper/hostapd.conf-wtp ================================================ ##### hostapd configuration file ############################################## # Empty lines and lines starting with # are ignored # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for # management frames); ath0 for madwifi interface=wlan0 # In case of madwifi, atheros, and nl80211 driver interfaces, an additional # configuration parameter, bridge, may be used to notify hostapd if the # interface is included in a bridge. This parameter is not used with Host AP # driver. If the bridge parameter is not set, the drivers will automatically # figure out the bridge interface (assuming sysfs is enabled and mounted to # /sys) and this parameter may not be needed. # # For nl80211, this parameter can be used to request the AP interface to be # added to the bridge automatically (brctl may refuse to do this before hostapd # has been started to change the interface mode). If needed, the bridge # interface is also created. #bridge=br0 # Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd); # default: hostap). nl80211 is used with all Linux mac80211 drivers. # Use driver=none if building hostapd as a standalone RADIUS server that does # not control any wireless/wired driver. # driver=hostap driver=capwap_wtp # hostapd event logger configuration # # Two output method: syslog and stdout (only usable if not forking to # background). # # Module bitfield (ORed bitfield of modules that will be logged; -1 = all # modules): # bit 0 (1) = IEEE 802.11 # bit 1 (2) = IEEE 802.1X # bit 2 (4) = RADIUS # bit 3 (8) = WPA # bit 4 (16) = driver interface # bit 5 (32) = IAPP # bit 6 (64) = MLME # # Levels (minimum value for logged events): # 0 = verbose debugging # 1 = debugging # 2 = informational messages # 3 = notification # 4 = warning # logger_syslog=-1 logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 # Dump file for state information (on SIGUSR1) dump_file=/tmp/hostapd.dump # Interface for separate control program. If this is specified, hostapd # will create this directory and a UNIX domain socket for listening to requests # from external programs (CLI/GUI, etc.) for status information and # configuration. The socket file will be named based on the interface name, so # multiple hostapd processes/interfaces can be run at the same time if more # than one interface is used. # /var/run/hostapd is the recommended directory for sockets and by default, # hostapd_cli will use it when trying to connect with hostapd. ctrl_interface=/var/run/hostapd # Access control for the control interface can be configured by setting the # directory to allow only members of a group to use sockets. This way, it is # possible to run hostapd as root (since it needs to change network # configuration and open raw sockets) and still allow GUI/CLI components to be # run as non-root users. However, since the control interface can be used to # change the network configuration, this access needs to be protected in many # cases. By default, hostapd is configured to use gid 0 (root). If you # want to allow non-root users to use the contron interface, add a new group # and change this value to match with that group. Add users that should have # control interface access to this group. # # This variable can be a group name or gid. #ctrl_interface_group=wheel ctrl_interface_group=0 ##### IEEE 802.11 related configuration ####################################### # SSID to be used in IEEE 802.11 management frames ssid=test # Country code (ISO/IEC 3166-1). Used to set regulatory domain. # Set as needed to indicate country in which device is operating. # This can limit available channels and transmit power. #country_code=US # Enable IEEE 802.11d. This advertises the country_code and the set of allowed # channels and transmit power levels based on the regulatory limits. The # country_code setting must be configured with the correct country for # IEEE 802.11d functions. # (default: 0 = disabled) #ieee80211d=1 # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, # Default: IEEE 802.11b hw_mode=g # Channel number (IEEE 802.11) # (default: 0, i.e., not set) # Please note that some drivers do not use this value from hostapd and the # channel will need to be configured separately with iwconfig. channel=1 # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 # DTIM (delivery traffic information message) period (range 1..255): # number of beacons between DTIMs (1 = every beacon includes DTIM element) # (default: 2) dtim_period=2 # Maximum number of stations allowed in station table. New stations will be # rejected after the station table is full. IEEE 802.11 has a limit of 2007 # different association IDs, so this number should not be larger than that. # (default: 2007) max_num_sta=255 # RTS/CTS threshold; 2347 = disabled (default); range 0..2347 # If this field is not included in hostapd.conf, hostapd will not control # RTS threshold and 'iwconfig wlan# rts ' can be used to set it. rts_threshold=2347 # Fragmentation threshold; 2346 = disabled (default); range 256..2346 # If this field is not included in hostapd.conf, hostapd will not control # fragmentation threshold and 'iwconfig wlan# frag ' can be used to set # it. fragm_threshold=2346 # Rate configuration # Default is to enable all rates supported by the hardware. This configuration # item allows this list be filtered so that only the listed rates will be left # in the list. If the list is empty, all rates are used. This list can have # entries that are not in the list of rates the hardware supports (such entries # are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110. # If this item is present, at least one rate have to be matching with the rates # hardware supports. # default: use the most common supported rate setting for the selected # hw_mode (i.e., this line can be removed from configuration file in most # cases) #supported_rates=10 20 55 110 60 90 120 180 240 360 480 540 # Basic rate set configuration # List of rates (in 100 kbps) that are included in the basic rate set. # If this item is not included, usually reasonable default set is used. #basic_rates=10 20 #basic_rates=10 20 55 110 #basic_rates=60 120 240 # Short Preamble # This parameter can be used to enable optional use of short preamble for # frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance. # This applies only to IEEE 802.11b-compatible networks and this should only be # enabled if the local hardware supports use of short preamble. If any of the # associated STAs do not support short preamble, use of short preamble will be # disabled (and enabled when such STAs disassociate) dynamically. # 0 = do not allow use of short preamble (default) # 1 = allow use of short preamble #preamble=1 # Station MAC address -based authentication # Please note that this kind of access control requires a driver that uses # hostapd to take care of management frame processing and as such, this can be # used with driver=hostap or driver=nl80211, but not with driver=madwifi. # 0 = accept unless in deny list # 1 = deny unless in accept list # 2 = use external RADIUS server (accept/deny lists are searched first) macaddr_acl=0 # Accept/deny lists are read from separate files (containing list of # MAC addresses, one per line). Use absolute path name to make sure that the # files can be read on SIGHUP configuration reloads. #accept_mac_file=/etc/hostapd.accept #deny_mac_file=/etc/hostapd.deny # IEEE 802.11 specifies two authentication algorithms. hostapd can be # configured to allow both of these or only one. Open system authentication # should be used with IEEE 802.1X. # Bit fields of allowed authentication algorithms: # bit 0 = Open System Authentication # bit 1 = Shared Key Authentication (requires WEP) auth_algs=3 # Send empty SSID in beacons and ignore probe request frames that do not # specify full SSID, i.e., require stations to know SSID. # default: disabled (0) # 1 = send empty (length=0) SSID in beacon and ignore probe request for # broadcast SSID # 2 = clear SSID (ASCII 0), but keep the original length (this may be required # with some clients that do not support empty SSID) and ignore probe # requests for broadcast SSID ignore_broadcast_ssid=0 # TX queue parameters (EDCF / bursting) # tx_queue__ # queues: data0, data1, data2, data3, after_beacon, beacon # (data0 is the highest priority queue) # parameters: # aifs: AIFS (default 2) # cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023) # cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin # burst: maximum length (in milliseconds with precision of up to 0.1 ms) for # bursting # # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # These parameters are used by the access point when transmitting frames # to the clients. # # Low priority / AC_BK = background #tx_queue_data3_aifs=7 #tx_queue_data3_cwmin=15 #tx_queue_data3_cwmax=1023 #tx_queue_data3_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0 # # Normal priority / AC_BE = best effort #tx_queue_data2_aifs=3 #tx_queue_data2_cwmin=15 #tx_queue_data2_cwmax=63 #tx_queue_data2_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0 # # High priority / AC_VI = video #tx_queue_data1_aifs=1 #tx_queue_data1_cwmin=7 #tx_queue_data1_cwmax=15 #tx_queue_data1_burst=3.0 # Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0 # # Highest priority / AC_VO = voice #tx_queue_data0_aifs=1 #tx_queue_data0_cwmin=3 #tx_queue_data0_cwmax=7 #tx_queue_data0_burst=1.5 # Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3 # 802.1D Tag (= UP) to AC mappings # WMM specifies following mapping of data frames to different ACs. This mapping # can be configured using Linux QoS/tc and sch_pktpri.o module. # 802.1D Tag 802.1D Designation Access Category WMM Designation # 1 BK AC_BK Background # 2 - AC_BK Background # 0 BE AC_BE Best Effort # 3 EE AC_BE Best Effort # 4 CL AC_VI Video # 5 VI AC_VI Video # 6 VO AC_VO Voice # 7 NC AC_VO Voice # Data frames with no priority information: AC_BE # Management frames: AC_VO # PS-Poll frames: AC_BE # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # for 802.11a or 802.11g networks # These parameters are sent to WMM clients when they associate. # The parameters will be used by WMM clients for frames transmitted to the # access point. # # note - txop_limit is in units of 32microseconds # note - acm is admission control mandatory flag. 0 = admission control not # required, 1 = mandatory # note - here cwMin and cmMax are in exponent form. the actual cw value used # will be (2^n)-1 where n is the value given here # wmm_enabled=1 # # WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] # Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver) #uapsd_advertisement_enabled=1 # # Low priority / AC_BK = background wmm_ac_bk_cwmin=4 wmm_ac_bk_cwmax=10 wmm_ac_bk_aifs=7 wmm_ac_bk_txop_limit=0 wmm_ac_bk_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=10 # # Normal priority / AC_BE = best effort wmm_ac_be_aifs=3 wmm_ac_be_cwmin=4 wmm_ac_be_cwmax=10 wmm_ac_be_txop_limit=0 wmm_ac_be_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=7 # # High priority / AC_VI = video wmm_ac_vi_aifs=2 wmm_ac_vi_cwmin=3 wmm_ac_vi_cwmax=4 wmm_ac_vi_txop_limit=94 wmm_ac_vi_acm=0 # Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188 # # Highest priority / AC_VO = voice wmm_ac_vo_aifs=2 wmm_ac_vo_cwmin=2 wmm_ac_vo_cwmax=3 wmm_ac_vo_txop_limit=47 wmm_ac_vo_acm=0 # Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 # Static WEP key configuration # # The key number to use when transmitting. # It must be between 0 and 3, and the corresponding key must be set. # default: not set #wep_default_key=0 # The WEP keys to use. # A key may be a quoted string or unquoted hexadecimal digits. # The key length should be 5, 13, or 16 characters, or 10, 26, or 32 # digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or # 128-bit (152-bit) WEP is used. # Only the default key must be supplied; the others are optional. # default: not set #wep_key0=123456789a #wep_key1="vwxyz" #wep_key2=0102030405060708090a0b0c0d #wep_key3=".2.4.6.8.0.23" # Station inactivity limit # # If a station does not send anything in ap_max_inactivity seconds, an # empty data frame is sent to it in order to verify whether it is # still in range. If this frame is not ACKed, the station will be # disassociated and then deauthenticated. This feature is used to # clear station table of old entries when the STAs move out of the # range. # # The station can associate again with the AP if it is still in range; # this inactivity poll is just used as a nicer way of verifying # inactivity; i.e., client will not report broken connection because # disassociation frame is not sent immediately without first polling # the STA with a data frame. # default: 300 (i.e., 5 minutes) #ap_max_inactivity=300 # Disassociate stations based on excessive transmission failures or other # indications of connection loss. This depends on the driver capabilities and # may not be available with all drivers. #disassoc_low_ack=1 # Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to # remain asleep). Default: 65535 (no limit apart from field size) #max_listen_interval=100 # WDS (4-address frame) mode with per-station virtual interfaces # (only supported with driver=nl80211) # This mode allows associated stations to use 4-address frames to allow layer 2 # bridging to be used. #wds_sta=1 # If bridge parameter is set, the WDS STA interface will be added to the same # bridge by default. This can be overridden with the wds_bridge parameter to # use a separate bridge. #wds_bridge=wds-br0 # Client isolation can be used to prevent low-level bridging of frames between # associated stations in the BSS. By default, this bridging is allowed. #ap_isolate=1 ##### IEEE 802.11n related configuration ###################################### # ieee80211n: Whether IEEE 802.11n (HT) is enabled # 0 = disabled (default) # 1 = enabled # Note: You will also need to enable WMM for full HT functionality. #ieee80211n=1 # ht_capab: HT capabilities (list of flags) # LDPC coding capability: [LDPC] = supported # Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary # channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz # with secondary channel below the primary channel # (20 MHz only if neither is set) # Note: There are limits on which channels can be used with HT40- and # HT40+. Following table shows the channels that may be available for # HT40- and HT40+ use per IEEE 802.11n Annex J: # freq HT40- HT40+ # 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan) # 5 GHz 40,48,56,64 36,44,52,60 # (depending on the location, not all of these channels may be available # for use) # Please note that 40 MHz channels may switch their primary and secondary # channels if needed or creation of 40 MHz channel maybe rejected based # on overlapping BSSes. These changes are done automatically when hostapd # is setting up the 40 MHz channel. # Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC] # (SMPS disabled if neither is set) # HT-greenfield: [GF] (disabled if not set) # Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) # Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) # Tx STBC: [TX-STBC] (disabled if not set) # Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial # streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC # disabled if none of these set # HT-delayed Block Ack: [DELAYED-BA] (disabled if not set) # Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not # set) # DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) # PSMP support: [PSMP] (disabled if not set) # L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) #ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] # Require stations to support HT PHY (reject association if they do not) #require_ht=1 ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization #ieee8021x=1 # IEEE 802.1X/EAPOL version # hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL # version 2. However, there are many client implementations that do not handle # the new version number correctly (they seem to drop the frames completely). # In order to make hostapd interoperate with these clients, the version number # can be set to the older version (1) with this configuration value. #eapol_version=2 # Optional displayable message sent with EAP Request-Identity. The first \0 # in this string will be converted to ASCII-0 (nul). This can be used to # separate network info (comma separated list of attribute=value pairs); see, # e.g., RFC 4284. #eap_message=hello #eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com # WEP rekeying (disabled if key lengths are not set or are set to 0) # Key lengths for default/broadcast and individual/unicast keys: # 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits) # 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits) #wep_key_len_broadcast=5 #wep_key_len_unicast=5 # Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once) #wep_rekey_period=300 # EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if # only broadcast keys are used) eapol_key_index_workaround=0 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable # reauthentication). #eap_reauth_period=3600 # Use PAE group address (01:80:c2:00:00:03) instead of individual target # address when sending EAPOL frames with driver=wired. This is the most common # mechanism used in wired authentication, but it also requires that the port # is only used by one station. #use_pae_group_addr=1 ##### Integrated EAP server ################################################### # Optionally, hostapd can be configured to use an integrated EAP server # to process EAP authentication locally without need for an external RADIUS # server. This functionality can be used both as a local authentication server # for IEEE 802.1X/EAPOL and as a RADIUS server for other devices. # Use integrated EAP server instead of external RADIUS authentication # server. This is also needed if hostapd is configured to act as a RADIUS # authentication server. eap_server=0 # Path for EAP server user database #eap_user_file=/etc/hostapd.eap_user # CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS #ca_cert=/etc/hostapd.ca.pem # Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS #server_cert=/etc/hostapd.server.pem # Private key matching with the server certificate for EAP-TLS/PEAP/TTLS # This may point to the same file as server_cert if both certificate and key # are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be # used by commenting out server_cert and specifying the PFX file as the # private_key. #private_key=/etc/hostapd.server.prv # Passphrase for private key #private_key_passwd=secret passphrase # Enable CRL verification. # Note: hostapd does not yet support CRL downloading based on CDP. Thus, a # valid CRL signed by the CA is required to be included in the ca_cert file. # This can be done by using PEM format for CA certificate and CRL and # concatenating these into one file. Whenever CRL changes, hostapd needs to be # restarted to take the new CRL into use. # 0 = do not verify CRLs (default) # 1 = check the CRL of the user certificate # 2 = check all CRLs in the certificate path #check_crl=1 # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an # ephemeral DH key exchange. In most cases, the default RSA authentication does # not use this configuration. However, it is possible setup RSA to use # ephemeral DH key exchange. In addition, ciphers with DSA keys always use # ephemeral DH keys. This can be used to achieve forward secrecy. If the file # is in DSA parameters format, it will be automatically converted into DH # params. This parameter is required if anonymous EAP-FAST is used. # You can generate DH parameters file with OpenSSL, e.g., # "openssl dhparam -out /etc/hostapd.dh.pem 1024" #dh_file=/etc/hostapd.dh.pem # Fragment size for EAP methods #fragment_size=1400 # Configuration data for EAP-SIM database/authentication gateway interface. # This is a text string in implementation specific format. The example # implementation in eap_sim_db.c uses this as the UNIX domain socket name for # the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:" # prefix. #eap_sim_db=unix:/tmp/hlr_auc_gw.sock # Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, # random value. It is configured as a 16-octet value in hex format. It can be # generated, e.g., with the following command: # od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' ' #pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f # EAP-FAST authority identity (A-ID) # A-ID indicates the identity of the authority that issues PACs. The A-ID # should be unique across all issuing servers. In theory, this is a variable # length field, but due to some existing implementations requiring A-ID to be # 16 octets in length, it is strongly recommended to use that length for the # field to provid interoperability with deployed peer implementations. This # field is configured in hex format. #eap_fast_a_id=101112131415161718191a1b1c1d1e1f # EAP-FAST authority identifier information (A-ID-Info) # This is a user-friendly name for the A-ID. For example, the enterprise name # and server name in a human-readable format. This field is encoded as UTF-8. #eap_fast_a_id_info=test server # Enable/disable different EAP-FAST provisioning modes: #0 = provisioning disabled #1 = only anonymous provisioning allowed #2 = only authenticated provisioning allowed #3 = both provisioning modes allowed (default) #eap_fast_prov=3 # EAP-FAST PAC-Key lifetime in seconds (hard limit) #pac_key_lifetime=604800 # EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard # limit). The server will generate a new PAC-Key when this number of seconds # (or fewer) of the lifetime remains. #pac_key_refresh_time=86400 # EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND # (default: 0 = disabled). #eap_sim_aka_result_ind=1 # Trusted Network Connect (TNC) # If enabled, TNC validation will be required before the peer is allowed to # connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other # EAP method is enabled, the peer will be allowed to connect without TNC. #tnc=1 ##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) ####################### # Interface to be used for IAPP broadcast packets #iapp_interface=eth0 ##### RADIUS client configuration ############################################# # for IEEE 802.1X with external Authentication Server, IEEE 802.11 # authentication with external ACL for MAC addresses, and accounting # The own IP address of the access point (used as NAS-IP-Address) own_ip_addr=127.0.0.1 # Optional NAS-Identifier string for RADIUS messages. When used, this should be # a unique to the NAS within the scope of the RADIUS server. For example, a # fully qualified domain name can be used here. # When using IEEE 802.11r, nas_identifier must be set and must be between 1 and # 48 octets long. #nas_identifier=ap.example.com # RADIUS authentication server #auth_server_addr=127.0.0.1 #auth_server_port=1812 #auth_server_shared_secret=secret # RADIUS accounting server #acct_server_addr=127.0.0.1 #acct_server_port=1813 #acct_server_shared_secret=secret # Secondary RADIUS servers; to be used if primary one does not reply to # RADIUS packets. These are optional and there can be more than one secondary # server listed. #auth_server_addr=127.0.0.2 #auth_server_port=1812 #auth_server_shared_secret=secret2 # #acct_server_addr=127.0.0.2 #acct_server_port=1813 #acct_server_shared_secret=secret2 # Retry interval for trying to return to the primary RADIUS server (in # seconds). RADIUS client code will automatically try to use the next server # when the current server is not replying to requests. If this interval is set, # primary server will be retried after configured amount of time even if the # currently used secondary server is still working. #radius_retry_primary_interval=600 # Interim accounting update interval # If this is set (larger than 0) and acct_server is configured, hostapd will # send interim accounting updates every N seconds. Note: if set, this overrides # possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this # value should not be configured in hostapd.conf, if RADIUS server is used to # control the interim interval. # This value should not be less 600 (10 minutes) and must not be less than # 60 (1 minute). #radius_acct_interim_interval=600 # Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN # is used for the stations. This information is parsed from following RADIUS # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value # VLANID as a string). vlan_file option below must be configured if dynamic # VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be # used to set static client MAC address to VLAN ID mapping. # 0 = disabled (default) # 1 = option; use default interface if RADIUS server does not include VLAN ID # 2 = required; reject authentication if RADIUS server does not include VLAN ID #dynamic_vlan=0 # VLAN interface list for dynamic VLAN mode is read from a separate text file. # This list is used to map VLAN ID from the RADIUS server to a network # interface. Each station is bound to one interface in the same way as with # multiple BSSIDs or SSIDs. Each line in this text file is defining a new # interface and the line must include VLAN ID and interface name separated by # white space (space or tab). #vlan_file=/etc/hostapd.vlan # Interface where 802.1q tagged packets should appear when a RADIUS server is # used to determine which VLAN a station is on. hostapd creates a bridge for # each VLAN. Then hostapd adds a VLAN interface (associated with the interface # indicated by 'vlan_tagged_interface') and the appropriate wireless interface # to the bridge. #vlan_tagged_interface=eth0 ##### RADIUS authentication server configuration ############################## # hostapd can be used as a RADIUS authentication server for other hosts. This # requires that the integrated EAP server is also enabled and both # authentication services are sharing the same configuration. # File name of the RADIUS clients configuration for the RADIUS server. If this # commented out, RADIUS server is disabled. #radius_server_clients=/etc/hostapd.radius_clients # The UDP port number for the RADIUS authentication server #radius_server_auth_port=1812 # Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API) #radius_server_ipv6=1 ##### WPA/IEEE 802.11i configuration ########################################## # Enable WPA. Setting this variable configures the AP to require WPA (either # WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either # wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. # For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), # RADIUS authentication server must be configured, and WPA-EAP must be included # in wpa_key_mgmt. # This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) # and/or WPA2 (full IEEE 802.11i/RSN): # bit0 = WPA # bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) #wpa=1 # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase # (8..63 characters) that will be converted to PSK. This conversion uses SSID # so the PSK changes when ASCII passphrase is used and the SSID is changed. # wpa_psk (dot11RSNAConfigPSKValue) # wpa_passphrase (dot11RSNAConfigPSKPassPhrase) #wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef #wpa_passphrase=secret passphrase # Optionally, WPA PSKs can be read from a separate text file (containing list # of (PSK,MAC address) pairs. This allows more than one PSK to be configured. # Use absolute path name to make sure that the files can be read on SIGHUP # configuration reloads. #wpa_psk_file=/etc/hostapd.wpa_psk # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The # entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be # added to enable SHA256-based stronger algorithms. # (dot11RSNAConfigAuthenticationSuitesTable) #wpa_key_mgmt=WPA-PSK WPA-EAP # Set of accepted cipher suites (encryption algorithms) for pairwise keys # (unicast packets). This is a space separated list of algorithms: # CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] # TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] # Group cipher suite (encryption algorithm for broadcast and multicast frames) # is automatically selected based on this configuration. If only CCMP is # allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, # TKIP will be used as the group cipher. # (dot11RSNAConfigPairwiseCiphersTable) # Pairwise cipher for WPA (v1) (default: TKIP) #wpa_pairwise=TKIP CCMP # Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) #rsn_pairwise=CCMP # Time interval for rekeying GTK (broadcast/multicast encryption keys) in # seconds. (dot11RSNAConfigGroupRekeyTime) #wpa_group_rekey=600 # Rekey GTK when any STA that possesses the current GTK is leaving the BSS. # (dot11RSNAConfigGroupRekeyStrict) #wpa_strict_rekey=1 # Time interval for rekeying GMK (master key used internally to generate GTKs # (in seconds). #wpa_gmk_rekey=86400 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of # PTK to mitigate some attacks against TKIP deficiencies. #wpa_ptk_rekey=600 # Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up # roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN # authentication and key handshake before actually associating with a new AP. # (dot11RSNAPreauthenticationEnabled) #rsn_preauth=1 # # Space separated list of interfaces from which pre-authentication frames are # accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all # interface that are used for connections to other APs. This could include # wired interfaces and WDS links. The normal wireless data interface towards # associated stations (e.g., wlan0) should not be added, since # pre-authentication is only used with APs other than the currently associated # one. #rsn_preauth_interfaces=eth0 # peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is # allowed. This is only used with RSN/WPA2. # 0 = disabled (default) # 1 = enabled #peerkey=1 # ieee80211w: Whether management frame protection (MFP) is enabled # 0 = disabled (default) # 1 = optional # 2 = required #ieee80211w=0 # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) # (maximum time to wait for a SA Query response) # dot11AssociationSAQueryMaximumTimeout, 1...4294967295 #assoc_sa_query_max_timeout=1000 # Association SA Query retry timeout (in TU = 1.024 ms; for MFP) # (time between two subsequent SA Query requests) # dot11AssociationSAQueryRetryTimeout, 1...4294967295 #assoc_sa_query_retry_timeout=201 # disable_pmksa_caching: Disable PMKSA caching # This parameter can be used to disable caching of PMKSA created through EAP # authentication. RSN preauthentication may still end up using PMKSA caching if # it is enabled (rsn_preauth=1). # 0 = PMKSA caching enabled (default) # 1 = PMKSA caching disabled #disable_pmksa_caching=0 # okc: Opportunistic Key Caching (aka Proactive Key Caching) # Allow PMK cache to be shared opportunistically among configured interfaces # and BSSes (i.e., all configurations within a single hostapd process). # 0 = disabled (default) # 1 = enabled #okc=1 ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) # MDID is used to indicate a group of APs (within an ESS, i.e., sharing the # same SSID) between which a STA can use Fast BSS Transition. # 2-octet identifier as a hex string. #mobility_domain=a1b2 # PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID) # 1 to 48 octet identifier. # This is configured with nas_identifier (see RADIUS client section above). # Default lifetime of the PMK-RO in minutes; range 1..65535 # (dot11FTR0KeyLifetime) #r0_key_lifetime=10000 # PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID) # 6-octet identifier as a hex string. #r1_key_holder=000102030405 # Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535) # (dot11FTReassociationDeadline) #reassociation_deadline=1000 # List of R0KHs in the same Mobility Domain # format: <128-bit key as hex string> # This list is used to map R0KH-ID (NAS Identifier) to a destination MAC # address when requesting PMK-R1 key from the R0KH that the STA used during the # Initial Mobility Domain Association. #r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f #r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff # And so on.. One line per R0KH. # List of R1KHs in the same Mobility Domain # format: <128-bit key as hex string> # This list is used to map R1KH-ID to a destination MAC address when sending # PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD # that can request PMK-R1 keys. #r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f #r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff # And so on.. One line per R1KH. # Whether PMK-R1 push is enabled at R0KH # 0 = do not push PMK-R1 to all configured R1KHs (default) # 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived #pmk_r1_push=1 ##### Neighbor table ########################################################## # Maximum number of entries kept in AP table (either for neigbor table or for # detecting Overlapping Legacy BSS Condition). The oldest entry will be # removed when adding a new entry that would make the list grow over this # limit. Note! WFA certification for IEEE 802.11g requires that OLBC is # enabled, so this field should not be set to 0 when using IEEE 802.11g. # default: 255 #ap_table_max_size=255 # Number of seconds of no frames received after which entries may be deleted # from the AP table. Since passive scanning is not usually performed frequently # this should not be set to very small value. In addition, there is no # guarantee that every scan cycle will receive beacon frames from the # neighboring APs. # default: 60 #ap_table_expiration_time=3600 ##### Wi-Fi Protected Setup (WPS) ############################################# # WPS state # 0 = WPS disabled (default) # 1 = WPS enabled, not configured # 2 = WPS enabled, configured #wps_state=2 # AP can be configured into a locked state where new WPS Registrar are not # accepted, but previously authorized Registrars (including the internal one) # can continue to add new Enrollees. #ap_setup_locked=1 # Universally Unique IDentifier (UUID; see RFC 4122) of the device # This value is used as the UUID for the internal WPS Registrar. If the AP # is also using UPnP, this value should be set to the device's UPnP UUID. # If not configured, UUID will be generated based on the local MAC address. #uuid=12345678-9abc-def0-1234-56789abcdef0 # Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs # that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the # default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of # per-device PSKs is recommended as the more secure option (i.e., make sure to # set wpa_psk_file when using WPS with WPA-PSK). # When an Enrollee requests access to the network with PIN method, the Enrollee # PIN will need to be entered for the Registrar. PIN request notifications are # sent to hostapd ctrl_iface monitor. In addition, they can be written to a # text file that could be used, e.g., to populate the AP administration UI with # pending PIN requests. If the following variable is set, the PIN requests will # be written to the configured file. #wps_pin_requests=/var/run/hostapd_wps_pin_requests # Device Name # User-friendly description of device; up to 32 octets encoded in UTF-8 #device_name=Wireless AP # Manufacturer # The manufacturer of the device (up to 64 ASCII characters) #manufacturer=Company # Model Name # Model of the device (up to 32 ASCII characters) #model_name=WAP # Model Number # Additional device description (up to 32 ASCII characters) #model_number=123 # Serial Number # Serial number of the device (up to 32 characters) #serial_number=12345 # Primary Device Type # Used format: -- # categ = Category as an integer value # OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for # default WPS OUI # subcateg = OUI-specific Sub Category as an integer value # Examples: # 1-0050F204-1 (Computer / PC) # 1-0050F204-2 (Computer / Server) # 5-0050F204-1 (Storage / NAS) # 6-0050F204-1 (Network Infrastructure / AP) #device_type=6-0050F204-1 # OS Version # 4-octet operating system version number (hex string) #os_version=01020300 # Config Methods # List of the supported configuration methods # Available methods: usba ethernet label display ext_nfc_token int_nfc_token # nfc_interface push_button keypad virtual_display physical_display # virtual_push_button physical_push_button #config_methods=label virtual_display virtual_push_button keypad # WPS capability discovery workaround for PBC with Windows 7 # Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting # as a Registrar and using M1 from the AP. The config methods attribute in that # message is supposed to indicate only the configuration method supported by # the AP in Enrollee role, i.e., to add an external Registrar. For that case, # PBC shall not be used and as such, the PushButton config method is removed # from M1 by default. If pbc_in_m1=1 is included in the configuration file, # the PushButton config method is left in M1 (if included in config_methods # parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label # in the AP). #pbc_in_m1=1 # Static access point PIN for initial configuration and adding Registrars # If not set, hostapd will not allow external WPS Registrars to control the # access point. The AP PIN can also be set at runtime with hostapd_cli # wps_ap_pin command. Use of temporary (enabled by user action) and random # AP PIN is much more secure than configuring a static AP PIN here. As such, # use of the ap_pin parameter is not recommended if the AP device has means for # displaying a random PIN. #ap_pin=12345670 # Skip building of automatic WPS credential # This can be used to allow the automatically generated Credential attribute to # be replaced with pre-configured Credential(s). #skip_cred_build=1 # Additional Credential attribute(s) # This option can be used to add pre-configured Credential attributes into M8 # message when acting as a Registrar. If skip_cred_build=1, this data will also # be able to override the Credential attribute that would have otherwise been # automatically generated based on network configuration. This configuration # option points to an external file that much contain the WPS Credential # attribute(s) as binary data. #extra_cred=hostapd.cred # Credential processing # 0 = process received credentials internally (default) # 1 = do not process received credentials; just pass them over ctrl_iface to # external program(s) # 2 = process received credentials internally and pass them over ctrl_iface # to external program(s) # Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and # extra_cred be used to provide the Credential data for Enrollees. # # wps_cred_processing=1 will disabled automatic updates of hostapd.conf file # both for Credential processing and for marking AP Setup Locked based on # validation failures of AP PIN. An external program is responsible on updating # the configuration appropriately in this case. #wps_cred_processing=0 # AP Settings Attributes for M7 # By default, hostapd generates the AP Settings Attributes for M7 based on the # current configuration. It is possible to override this by providing a file # with pre-configured attributes. This is similar to extra_cred file format, # but the AP Settings attributes are not encapsulated in a Credential # attribute. #ap_settings=hostapd.ap_settings # WPS UPnP interface # If set, support for external Registrars is enabled. #upnp_iface=br0 # Friendly Name (required for UPnP) # Short description for end use. Should be less than 64 characters. #friendly_name=WPS Access Point # Manufacturer URL (optional for UPnP) #manufacturer_url=http://www.example.com/ # Model Description (recommended for UPnP) # Long description for end user. Should be less than 128 characters. #model_description=Wireless Access Point # Model URL (optional for UPnP) #model_url=http://www.example.com/model/ # Universal Product Code (optional for UPnP) # 12-digit, all-numeric code that identifies the consumer package. #upc=123456789012 ##### Wi-Fi Direct (P2P) ###################################################### # Enable P2P Device management #manage_p2p=1 # Allow cross connection #allow_cross_connection=1 #### TDLS (IEEE 802.11z-2010) ################################################# # Prohibit use of TDLS in this BSS #tdls_prohibit=1 # Prohibit use of TDLS Channel Switching in this BSS #tdls_prohibit_chan_switch=1 ##### IEEE 802.11v-2011 ####################################################### # Time advertisement # 0 = disabled (default) # 2 = UTC time at which the TSF timer is 0 #time_advertisement=2 # Local time zone as specified in 8.3 of IEEE Std 1003.1-2004: # stdoffset[dst[offset][,start[/time],end[/time]]] #time_zone=EST5 ##### IEEE 802.11u-2011 ####################################################### # Enable Interworking service #interworking=1 # Access Network Type # 0 = Private network # 1 = Private network with guest access # 2 = Chargeable public network # 3 = Free public network # 4 = Personal device network # 5 = Emergency services only network # 14 = Test or experimental # 15 = Wildcard #access_network_type=0 # Whether the network provides connectivity to the Internet # 0 = Unspecified # 1 = Network provides connectivity to the Internet #internet=1 # Additional Step Required for Access # Note: This is only used with open network, i.e., ASRA shall ne set to 0 if # RSN is used. #asra=0 # Emergency services reachable #esr=0 # Unauthenticated emergency service accessible #uesa=0 # Venue Info (optional) # The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34. # Example values (group,type): # 0,0 = Unspecified # 1,7 = Convention Center # 1,13 = Coffee Shop # 2,0 = Unspecified Business # 7,1 Private Residence #venue_group=7 #venue_type=1 # Homogeneous ESS identifier (optional; dot11HESSID) # If set, this shall be identifical to one of the BSSIDs in the homogeneous # ESS and this shall be set to the same value across all BSSs in homogeneous # ESS. #hessid=02:03:04:05:06:07 # Roaming Consortium List # Arbitrary number of Roaming Consortium OIs can be configured with each line # adding a new OI to the list. The first three entries are available through # Beacon and Probe Response frames. Any additional entry will be available only # through ANQP queries. Each OI is between 3 and 15 octets and is configured a # a hexstring. #roaming_consortium=021122 #roaming_consortium=2233445566 ##### Multiple BSSID support ################################################## # # Above configuration is using the default interface (wlan#, or multi-SSID VLAN # interfaces). Other BSSIDs can be added by using separator 'bss' with # default interface name to be allocated for the data packets of the new BSS. # # hostapd will generate BSSID mask based on the BSSIDs that are # configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is # not the case, the MAC address of the radio must be changed before starting # hostapd (ifconfig wlan0 hw ether ). If a BSSID is configured for # every secondary BSS, this limitation is not applied at hostapd and other # masks may be used if the driver supports them (e.g., swap the locally # administered bit) # # BSSIDs are assigned in order to each BSS, unless an explicit BSSID is # specified using the 'bssid' parameter. # If an explicit BSSID is specified, it must be chosen such that it: # - results in a valid MASK that covers it and the dev_addr # - is not the same as the MAC address of the radio # - is not the same as any other explicitly specified BSSID # # Please note that hostapd uses some of the values configured for the first BSS # as the defaults for the following BSSes. However, it is recommended that all # BSSes include explicit configuration of all relevant configuration items. # #bss=wlan0_0 #ssid=test2 # most of the above items can be used here (apart from radio interface specific # items, like channel) #bss=wlan0_1 #bssid=00:13:10:95:fe:0b # ... ================================================ FILE: hostapd_wrapper/hostapd2/README.Debian ================================================ Installation steps: 1. Flash a firmware with the hostapd-capwap package on a OpenWRT compatible router. 2. Setup a Debian box where you want to run AC. 3. On the Debian box : - Run ./debian-install.sh - Edit /etc/hostapd.conf - Run AC; hostapd /etc/hostapd.conf 4. On the OpenWRT router : - Run killall -9 hostapd - Copy /tmp/run/hostapd-phy0.conf to /etc/capwap/hostapd.conf - Edit the driver in /etc/capwap/hostapd.conf line and set it to capwap_wtp - Run cd /etc/capwap; WTP; hostapd hostapd.conf 9. Enjoy the RX_MGMT events flowing trough the radiotap tunnel. Notes: - Always run AC first and WTP after. - When hostapd on AC is closed also the hostapd on WTP is closed. - When you want to restart allways kill hostapd, AC and WTP processes. ================================================ FILE: hostapd_wrapper/hostapd2/hostapd-20130302-linux.patch ================================================ diff -purN hostapd-20130302/hostapd/.config hostapd-20130302-linux/hostapd/.config --- hostapd-20130302/hostapd/.config 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/hostapd/.config 2013-07-06 06:07:21.000000000 -0400 @@ -0,0 +1,169 @@ +# Example hostapd build time configuration +# +# This file lists the configuration options that are used when building the +# hostapd binary. All lines starting with # are ignored. Configuration option +# lines must be commented out complete, if they are not to be included, i.e., +# just setting VARIABLE=n is not disabling that variable. +# +# This file is included in Makefile, so variables like CFLAGS and LIBS can also +# be modified from here. In most cass, these lines should use += in order not +# to override previous values of the variables. + +# Driver interface for Host AP driver +CONFIG_DRIVER_HOSTAP=y + +CONFIG_LIBNL_TINY=y + +# Driver interface for wired authenticator +CONFIG_DRIVER_WIRED=y + +# Driver interface for madwifi driver +#CONFIG_DRIVER_MADWIFI=y +#CFLAGS += -I../../madwifi # change to the madwifi source directory + +# Driver interface for Prism54 driver +#CONFIG_DRIVER_PRISM54=y + +# Driver interface for drivers using the nl80211 kernel interface +CONFIG_DRIVER_NL80211=y +# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be +# shipped with your distribution yet. If that is the case, you need to build +# newer libnl version and point the hostapd build to use it. +#LIBNL=/usr/src/libnl +#CFLAGS += -I$(LIBNL)/include +#LIBS += -L$(LIBNL)/lib + +# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) +#CONFIG_DRIVER_BSD=y +#CFLAGS += -I/usr/local/include +#LIBS += -L/usr/local/lib + +# Driver interface for no driver (e.g., RADIUS server only) +#CONFIG_DRIVER_NONE=y + +# IEEE 802.11F/IAPP +CONFIG_IAPP=y + +# WPA2/IEEE 802.11i RSN pre-authentication +CONFIG_RSN_PREAUTH=y + +# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) +CONFIG_PEERKEY=y + +# IEEE 802.11w (management frame protection) +# This version is an experimental implementation based on IEEE 802.11w/D1.0 +# draft and is subject to change since the standard has not yet been finalized. +# Driver support is also needed for IEEE 802.11w. +#CONFIG_IEEE80211W=y + +# Integrated EAP server +CONFIG_EAP=y + +# EAP-MD5 for the integrated EAP server +CONFIG_EAP_MD5=y + +# EAP-TLS for the integrated EAP server +CONFIG_EAP_TLS=y + +# EAP-MSCHAPv2 for the integrated EAP server +CONFIG_EAP_MSCHAPV2=y + +# EAP-PEAP for the integrated EAP server +CONFIG_EAP_PEAP=y + +# EAP-GTC for the integrated EAP server +CONFIG_EAP_GTC=y + +# EAP-TTLS for the integrated EAP server +CONFIG_EAP_TTLS=y + +# EAP-SIM for the integrated EAP server +#CONFIG_EAP_SIM=y + +# EAP-AKA for the integrated EAP server +#CONFIG_EAP_AKA=y + +# EAP-AKA' for the integrated EAP server +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# EAP-PAX for the integrated EAP server +#CONFIG_EAP_PAX=y + +# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK) +#CONFIG_EAP_PSK=y + +# EAP-SAKE for the integrated EAP server +#CONFIG_EAP_SAKE=y + +# EAP-GPSK for the integrated EAP server +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-FAST for the integrated EAP server +# Note: Default OpenSSL package does not include support for all the +# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, +# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch) +# to add the needed functions. +#CONFIG_EAP_FAST=y + +# Wi-Fi Protected Setup (WPS) +#CONFIG_WPS=y +# Enable UPnP support for external WPS Registrars +#CONFIG_WPS_UPNP=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# Trusted Network Connect (EAP-TNC) +#CONFIG_EAP_TNC=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +CONFIG_PKCS12=y + +# RADIUS authentication server. This provides access to the integrated EAP +# server from external hosts using RADIUS. +#CONFIG_RADIUS_SERVER=y + +# Build IPv6 support for RADIUS operations +CONFIG_IPV6=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) +#CONFIG_IEEE80211R=y + +# Use the hostapd's IEEE 802.11 authentication (ACL), but without +# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211) +#CONFIG_DRIVER_RADIUS_ACL=y + +# IEEE 802.11n (High Throughput) support +CONFIG_IEEE80211N=y + +# Remove debugging code that is printing out debug messages to stdout. +# This can be used to reduce the size of the hostapd considerably if debugging +# code is not needed. +#CONFIG_NO_STDOUT_DEBUG=y + +# Remove support for RADIUS accounting +#CONFIG_NO_ACCOUNTING=y + +# Remove support for RADIUS +#CONFIG_NO_RADIUS=y + +# Remove support for VLANs +#CONFIG_NO_VLAN=y + +CONFIG_TLS=internal +CONFIG_INTERNAL_LIBTOMMATH=y +CONFIG_INTERNAL_AES=y +NEED_AES_DEC=y + +CONFIG_NO_DUMP_STATE=y + +CONFIG_WPS=y +CONFIG_FULL_DYNAMIC_VLAN=y + +CONFIG_UBUS=y + +CONFIG_DRIVER_CAPWAP=y diff -purN hostapd-20130302/hostapd/config_file.c hostapd-20130302-linux/hostapd/config_file.c --- hostapd-20130302/hostapd/config_file.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/config_file.c 2013-07-04 11:17:51.000000000 -0400 @@ -2464,6 +2464,8 @@ static int hostapd_config_fill(struct ho } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211N + } else if (os_strcmp(buf, "noscan") == 0) { + conf->noscan = atoi(pos); } else if (os_strcmp(buf, "ieee80211n") == 0) { conf->ieee80211n = atoi(pos); } else if (os_strcmp(buf, "ht_capab") == 0) { @@ -2472,6 +2474,10 @@ static int hostapd_config_fill(struct ho "ht_capab", line); errors++; } + } else if (os_strcmp(buf, "dynamic_ht40") == 0) { + conf->dynamic_ht40 = atoi(pos); + if (conf->dynamic_ht40 == 1) + conf->dynamic_ht40 = 1500; } else if (os_strcmp(buf, "require_ht") == 0) { conf->require_ht = atoi(pos); #endif /* CONFIG_IEEE80211N */ diff -purN hostapd-20130302/hostapd/ctrl_iface.c hostapd-20130302-linux/hostapd/ctrl_iface.c --- hostapd-20130302/hostapd/ctrl_iface.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/ctrl_iface.c 2013-07-04 11:17:51.000000000 -0400 @@ -33,6 +33,7 @@ #include "wps/wps.h" #include "config_file.h" #include "ctrl_iface.h" +#include "config_file.h" struct wpa_ctrl_dst { @@ -43,6 +44,7 @@ struct wpa_ctrl_dst { int errors; }; +static char *reload_opts = NULL; static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, const char *buf, size_t len); @@ -152,6 +154,68 @@ static int hostapd_ctrl_iface_new_sta(st return 0; } +static int hostapd_ctrl_iface_set_down(struct hostapd_data *hapd) +{ + if (hapd->driver->stop_ap) + hapd->driver->stop_ap(hapd->drv_priv); + return 0; +} + +static char *get_option(char *opt, char *str) +{ + int len = strlen(str); + + if (!strncmp(opt, str, len)) + return opt + len; + else + return NULL; +} + +static struct hostapd_config *hostapd_ctrl_iface_config_read(const char *fname) +{ + struct hostapd_config *conf; + char *opt, *val; + + conf = hostapd_config_read(fname); + if (!conf) + return NULL; + + for (opt = strtok(reload_opts, " "); + opt; + opt = strtok(NULL, " ")) { + + if ((val = get_option(opt, "channel="))) + conf->channel = atoi(val); + else if ((val = get_option(opt, "ht_capab="))) + conf->ht_capab = atoi(val); + else if ((val = get_option(opt, "ht_capab_mask="))) + conf->ht_capab &= atoi(val); + else if ((val = get_option(opt, "sec_chan="))) + conf->secondary_channel = atoi(val); + else if ((val = get_option(opt, "hw_mode="))) + conf->hw_mode = atoi(val); + else if ((val = get_option(opt, "ieee80211n="))) + conf->ieee80211n = atoi(val); + else + break; + } + + return conf; +} + +static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt) +{ + struct hostapd_config * (*config_read_cb)(const char *config_fname); + struct hostapd_iface *iface = hapd->iface; + + config_read_cb = iface->interfaces->config_read_cb; + iface->interfaces->config_read_cb = hostapd_ctrl_iface_config_read; + reload_opts = txt; + + hostapd_reload_config(iface); + + iface->interfaces->config_read_cb = config_read_cb; +} #ifdef CONFIG_IEEE80211W #ifdef NEED_AP_MLME @@ -415,6 +479,9 @@ static int hostapd_ctrl_iface_wps_ap_pin char *pos; const char *pin_txt; + if (!hapd->wps) + return -1; + pos = os_strchr(txt, ' '); if (pos) *pos++ = '\0'; @@ -873,6 +940,7 @@ static void hostapd_ctrl_iface_receive(i } else if (os_strncmp(buf, "RELOG", 5) == 0) { if (wpa_debug_reopen_file() < 0) reply_len = -1; +#ifdef CONFIG_CTRL_IFACE_MIB } else if (os_strcmp(buf, "MIB") == 0) { reply_len = ieee802_11_get_mib(hapd, reply, reply_size); if (reply_len >= 0) { @@ -902,6 +970,12 @@ static void hostapd_ctrl_iface_receive(i reply_len += res; } #endif /* CONFIG_NO_RADIUS */ +#endif + } else if (os_strcmp(buf, "DOWN") == 0) { + hostapd_ctrl_iface_set_down(hapd); + } else if (os_strncmp(buf, "UPDATE ", 7) == 0) { + hostapd_ctrl_iface_update(hapd, buf + 7); +#ifdef CONFIG_CTRL_IFACE_MIB } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, reply_size); @@ -911,6 +985,7 @@ static void hostapd_ctrl_iface_receive(i } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, reply_size); +#endif } else if (os_strcmp(buf, "ATTACH") == 0) { if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) reply_len = -1; diff -purN hostapd-20130302/hostapd/defconfig hostapd-20130302-linux/hostapd/defconfig --- hostapd-20130302/hostapd/defconfig 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/defconfig 2013-07-04 11:17:51.000000000 -0400 @@ -267,3 +267,5 @@ CONFIG_IPV6=y # Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file #CONFIG_SQLITE=y + +CONFIG_DRIVER_CAPWAP_WTP=y diff -purN hostapd-20130302/hostapd/hostapd_ac.conf hostapd-20130302-linux/hostapd/hostapd_ac.conf --- hostapd-20130302/hostapd/hostapd_ac.conf 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/hostapd/hostapd_ac.conf 2013-07-06 06:07:33.000000000 -0400 @@ -0,0 +1,3 @@ +ip_daemon_ac=127.0.0.1 +sock_path_ac=/tmp/ac_ipc_hostapd +port_daemon_ac=5543 diff -purN hostapd-20130302/hostapd/hostapd_cli.c hostapd-20130302-linux/hostapd/hostapd_cli.c --- hostapd-20130302/hostapd/hostapd_cli.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/hostapd_cli.c 2013-07-04 11:17:51.000000000 -0400 @@ -67,7 +67,6 @@ static const char *commands_help = #ifdef CONFIG_IEEE80211W " sa_query send SA Query to a station\n" #endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS " wps_pin [timeout] [addr] add WPS Enrollee PIN\n" " wps_check_pin verify PIN checksum\n" " wps_pbc indicate button pushed to initiate PBC\n" @@ -79,7 +78,6 @@ static const char *commands_help = #endif /* CONFIG_WPS_NFC */ " wps_ap_pin [params..] enable/disable AP PIN\n" " wps_config configure AP\n" -#endif /* CONFIG_WPS */ " get_config show current configuration\n" " help show this usage help\n" " interface [ifname] show interfaces/select interface\n" @@ -340,7 +338,6 @@ static int hostapd_cli_cmd_sa_query(stru #endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -559,7 +556,6 @@ static int hostapd_cli_cmd_wps_config(st ssid_hex, argv[1]); return wpa_ctrl_command(ctrl, buf); } -#endif /* CONFIG_WPS */ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, @@ -805,7 +801,6 @@ static struct hostapd_cli_cmd hostapd_cl #ifdef CONFIG_IEEE80211W { "sa_query", hostapd_cli_cmd_sa_query }, #endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS { "wps_pin", hostapd_cli_cmd_wps_pin }, { "wps_check_pin", hostapd_cli_cmd_wps_check_pin }, { "wps_pbc", hostapd_cli_cmd_wps_pbc }, @@ -818,7 +813,6 @@ static struct hostapd_cli_cmd hostapd_cl #endif /* CONFIG_WPS_NFC */ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, { "wps_config", hostapd_cli_cmd_wps_config }, -#endif /* CONFIG_WPS */ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent }, { "ess_disassoc", hostapd_cli_cmd_ess_disassoc }, { "get_config", hostapd_cli_cmd_get_config }, diff -purN hostapd-20130302/hostapd/hostapd.conf hostapd-20130302-linux/hostapd/hostapd.conf --- hostapd-20130302/hostapd/hostapd.conf 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/hostapd.conf 2013-07-07 01:29:44.000000000 -0400 @@ -23,6 +23,7 @@ interface=wlan0 # Use driver=none if building hostapd as a standalone RADIUS server that does # not control any wireless/wired driver. # driver=hostap +driver=capwap # hostapd event logger configuration # @@ -83,15 +84,7 @@ ctrl_interface_group=0 ##### IEEE 802.11 related configuration ####################################### # SSID to be used in IEEE 802.11 management frames -ssid=test -# Alternative formats for configuring SSID -# (double quoted string, hexdump, printf-escaped string) -#ssid2="test" -#ssid2=74657374 -#ssid2=P"hello\nthere" - -# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding -#utf8_ssid=1 +ssid=OpenWRT # Country code (ISO/IEC 3166-1). Used to set regulatory domain. # Set as needed to indicate country in which device is operating. @@ -106,10 +99,8 @@ ssid=test #ieee80211d=1 # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, -# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to -# specify band) # Default: IEEE 802.11b -hw_mode=g +hw_mode=b # Channel number (IEEE 802.11) # (default: 0, i.e., not set) @@ -171,7 +162,7 @@ fragm_threshold=2346 # disabled (and enabled when such STAs disassociate) dynamically. # 0 = do not allow use of short preamble (default) # 1 = allow use of short preamble -#preamble=1 +preamble=1 # Station MAC address -based authentication # Please note that this kind of access control requires a driver that uses @@ -194,7 +185,7 @@ macaddr_acl=0 # Bit fields of allowed authentication algorithms: # bit 0 = Open System Authentication # bit 1 = Shared Key Authentication (requires WEP) -auth_algs=3 +auth_algs=1 # Send empty SSID in beacons and ignore probe request frames that do not # specify full SSID, i.e., require stations to know SSID. @@ -206,13 +197,6 @@ auth_algs=3 # requests for broadcast SSID ignore_broadcast_ssid=0 -# Additional vendor specfic elements for Beacon and Probe Response frames -# This parameter can be used to add additional vendor specific element(s) into -# the end of the Beacon and Probe Response frames. The format for these -# element(s) is a hexdump of the raw information elements (id+len+payload for -# one or more elements) -#vendor_elements=dd0411223301 - # TX queue parameters (EDCF / bursting) # tx_queue__ # queues: data0, data1, data2, data3, after_beacon, beacon @@ -356,17 +340,11 @@ wmm_ac_vo_acm=0 # the STA with a data frame. # default: 300 (i.e., 5 minutes) #ap_max_inactivity=300 -# -# The inactivity polling can be disabled to disconnect stations based on -# inactivity timeout so that idle stations are more likely to be disconnected -# even if they are still in range of the AP. This can be done by setting -# skip_inactivity_poll to 1 (default 0). -#skip_inactivity_poll=0 # Disassociate stations based on excessive transmission failures or other # indications of connection loss. This depends on the driver capabilities and # may not be available with all drivers. -#disassoc_low_ack=1 +disassoc_low_ack=1 # Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to # remain asleep). Default: 65535 (no limit apart from field size) @@ -433,161 +411,10 @@ wmm_ac_vo_acm=0 # Require stations to support HT PHY (reject association if they do not) #require_ht=1 -##### IEEE 802.11ac related configuration ##################################### - -# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled -# 0 = disabled (default) -# 1 = enabled -# Note: You will also need to enable WMM for full VHT functionality. -#ieee80211ac=1 - -# vht_capab: VHT capabilities (list of flags) -# -# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454] -# Indicates maximum MPDU length -# 0 = 3895 octets (default) -# 1 = 7991 octets -# 2 = 11454 octets -# 3 = reserved -# -# supported_chan_width: [VHT160] [VHT160-80PLUS80] -# Indicates supported Channel widths -# 0 = 160 MHz & 80+80 channel widths are not supported (default) -# 1 = 160 MHz channel width is supported -# 2 = 160 MHz & 80+80 channel widths are supported -# 3 = reserved -# -# Rx LDPC coding capability: [RXLDPC] -# Indicates support for receiving LDPC coded pkts -# 0 = Not supported (default) -# 1 = Supported -# -# Short GI for 80 MHz: [SHORT-GI-80] -# Indicates short GI support for reception of packets transmitted with TXVECTOR -# params format equal to VHT and CBW = 80Mhz -# 0 = Not supported (default) -# 1 = Supported -# -# Short GI for 160 MHz: [SHORT-GI-160] -# Indicates short GI support for reception of packets transmitted with TXVECTOR -# params format equal to VHT and CBW = 160Mhz -# 0 = Not supported (default) -# 1 = Supported -# -# Tx STBC: [TX-STBC-2BY1] -# Indicates support for the transmission of at least 2x1 STBC -# 0 = Not supported (default) -# 1 = Supported -# -# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234] -# Indicates support for the reception of PPDUs using STBC -# 0 = Not supported (default) -# 1 = support of one spatial stream -# 2 = support of one and two spatial streams -# 3 = support of one, two and three spatial streams -# 4 = support of one, two, three and four spatial streams -# 5,6,7 = reserved -# -# SU Beamformer Capable: [SU-BEAMFORMER] -# Indicates support for operation as a single user beamformer -# 0 = Not supported (default) -# 1 = Supported -# -# SU Beamformee Capable: [SU-BEAMFORMEE] -# Indicates support for operation as a single user beamformee -# 0 = Not supported (default) -# 1 = Supported -# -# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2] -# Beamformee's capability indicating the maximum number of beamformer -# antennas the beamformee can support when sending compressed beamforming -# feedback -# If SU beamformer capable, set to maximum value minus 1 -# else reserved (default) -# -# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2] -# Beamformer's capability indicating the maximum value of the NUM_STS parameter -# in the TXVECTOR of a VHT NDP -# If SU beamformer capable, set to maximum value minus 1 -# else reserved (default) -# -# MU Beamformer Capable: [MU-BEAMFORMER] -# Indicates support for operation as an MU beamformer -# 0 = Not supported or sent by Non-AP STA (default) -# 1 = Supported -# -# MU Beamformee Capable: [MU-BEAMFORMEE] -# Indicates support for operation as an MU beamformee -# 0 = Not supported or sent by AP (default) -# 1 = Supported -# -# VHT TXOP PS: [VHT-TXOP-PS] -# Indicates whether or not the AP supports VHT TXOP Power Save Mode -# or whether or not the STA is in VHT TXOP Power Save mode -# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS -# mode -# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save -# mode -# -# +HTC-VHT Capable: [HTC-VHT] -# Indicates whether or not the STA supports receiving a VHT variant HT Control -# field. -# 0 = Not supported (default) -# 1 = supported -# -# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7] -# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv -# This field is an integer in the range of 0 to 7. -# The length defined by this field is equal to -# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets -# -# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3] -# Indicates whether or not the STA supports link adaptation using VHT variant -# HT Control field -# If +HTC-VHTcapable is 1 -# 0 = (no feedback) if the STA does not provide VHT MFB (default) -# 1 = reserved -# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB -# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the -# STA provides unsolicited VHT MFB -# Reserved if +HTC-VHTcapable is 0 -# -# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN] -# Indicates the possibility of Rx antenna pattern change -# 0 = Rx antenna pattern might change during the lifetime of an association -# 1 = Rx antenna pattern does not change during the lifetime of an association -# -# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN] -# Indicates the possibility of Tx antenna pattern change -# 0 = Tx antenna pattern might change during the lifetime of an association -# 1 = Tx antenna pattern does not change during the lifetime of an association -#vht_capab=[SHORT-GI-80][HTC-VHT] -# -# Require stations to support VHT PHY (reject association if they do not) -#require_vht=1 - -# 0 = 20 or 40 MHz operating Channel width -# 1 = 80 MHz channel width -# 2 = 160 MHz channel width -# 3 = 80+80 MHz channel width -#vht_oper_chwidth=1 -# -# center freq = 5 GHz + (5 * index) -# So index 42 gives center freq 5.210 GHz -# which is channel 42 in 5G band -# -#vht_oper_centr_freq_seg0_idx=42 -# -# center freq = 5 GHz + (5 * index) -# So index 159 gives center freq 5.795 GHz -# which is channel 159 in 5G band -# -#vht_oper_centr_freq_seg1_idx=159 - ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization -#ieee8021x=1 +ieee8021x=1 # IEEE 802.1X/EAPOL version # hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL @@ -615,7 +442,7 @@ wmm_ac_vo_acm=0 # EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if # only broadcast keys are used) -eapol_key_index_workaround=0 +eapol_key_index_workaround=1 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable # reauthentication). @@ -640,8 +467,6 @@ eapol_key_index_workaround=0 eap_server=0 # Path for EAP server user database -# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db" -# to use SQLite database instead of a text file. #eap_user_file=/etc/hostapd.eap_user # CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS @@ -686,18 +511,12 @@ eap_server=0 # Fragment size for EAP methods #fragment_size=1400 -# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters -# using the IANA repository for IKE (RFC 2409). -#pwd_group=19 - # Configuration data for EAP-SIM database/authentication gateway interface. # This is a text string in implementation specific format. The example # implementation in eap_sim_db.c uses this as the UNIX domain socket name for # the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:" -# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config), -# database file can be described with an optional db= parameter. +# prefix. #eap_sim_db=unix:/tmp/hlr_auc_gw.sock -#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db # Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, # random value. It is configured as a 16-octet value in hex format. It can be @@ -763,12 +582,12 @@ own_ip_addr=127.0.0.1 # fully qualified domain name can be used here. # When using IEEE 802.11r, nas_identifier must be set and must be between 1 and # 48 octets long. -#nas_identifier=ap.example.com +nas_identifier=OpenWrt # RADIUS authentication server -#auth_server_addr=127.0.0.1 -#auth_server_port=1812 -#auth_server_shared_secret=secret +auth_server_addr=31.1.1.1 +auth_server_port=1812 +auth_server_shared_secret=SharedSecret # RADIUS accounting server #acct_server_addr=127.0.0.1 @@ -804,12 +623,6 @@ own_ip_addr=127.0.0.1 # 60 (1 minute). #radius_acct_interim_interval=600 -# Request Chargeable-User-Identity (RFC 4372) -# This parameter can be used to configure hostapd to request CUI from the -# RADIUS server by including Chargeable-User-Identity attribute into -# Access-Request packets. -#radius_request_cui=1 - # Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN # is used for the stations. This information is parsed from following RADIUS # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), @@ -837,61 +650,6 @@ own_ip_addr=127.0.0.1 # to the bridge. #vlan_tagged_interface=eth0 -# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs -# to know how to name it. -# 0 = vlan, e.g., vlan1 -# 1 = ., e.g. eth0.1 -#vlan_naming=0 - -# Arbitrary RADIUS attributes can be added into Access-Request and -# Accounting-Request packets by specifying the contents of the attributes with -# the following configuration parameters. There can be multiple of these to -# add multiple attributes. These parameters can also be used to override some -# of the attributes added automatically by hostapd. -# Format: [:] -# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific) -# syntax: s = string (UTF-8), d = integer, x = octet string -# value: attribute value in format indicated by the syntax -# If syntax and value parts are omitted, a null value (single 0x00 octet) is -# used. -# -# Additional Access-Request attributes -# radius_auth_req_attr=[:] -# Examples: -# Operator-Name = "Operator" -#radius_auth_req_attr=126:s:Operator -# Service-Type = Framed (2) -#radius_auth_req_attr=6:d:2 -# Connect-Info = "testing" (this overrides the automatically generated value) -#radius_auth_req_attr=77:s:testing -# Same Connect-Info value set as a hexdump -#radius_auth_req_attr=77:x:74657374696e67 - -# -# Additional Accounting-Request attributes -# radius_acct_req_attr=[:] -# Examples: -# Operator-Name = "Operator" -#radius_acct_req_attr=126:s:Operator - -# Dynamic Authorization Extensions (RFC 5176) -# This mechanism can be used to allow dynamic changes to user session based on -# commands from a RADIUS server (or some other disconnect client that has the -# needed session information). For example, Disconnect message can be used to -# request an associated station to be disconnected. -# -# This is disabled by default. Set radius_das_port to non-zero UDP port -# number to enable. -#radius_das_port=3799 -# -# DAS client (the host that can send Disconnect/CoA requests) and shared secret -#radius_das_client=192.168.1.123 shared secret here -# -# DAS Event-Timestamp time window in seconds -#radius_das_time_window=300 -# -# DAS require Event-Timestamp -#radius_das_require_event_timestamp=1 ##### RADIUS authentication server configuration ############################## @@ -915,7 +673,6 @@ own_ip_addr=127.0.0.1 # Enable WPA. Setting this variable configures the AP to require WPA (either # WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either # wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. -# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice. # For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), # RADIUS authentication server must be configured, and WPA-EAP must be included # in wpa_key_mgmt. @@ -923,7 +680,7 @@ own_ip_addr=127.0.0.1 # and/or WPA2 (full IEEE 802.11i/RSN): # bit0 = WPA # bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) -#wpa=1 +wpa=2 # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase @@ -940,20 +697,11 @@ own_ip_addr=127.0.0.1 # configuration reloads. #wpa_psk_file=/etc/hostapd.wpa_psk -# Optionally, WPA passphrase can be received from RADIUS authentication server -# This requires macaddr_acl to be set to 2 (RADIUS) -# 0 = disabled (default) -# 1 = optional; use default passphrase/psk if RADIUS server does not include -# Tunnel-Password -# 2 = required; reject authentication if RADIUS server does not include -# Tunnel-Password -#wpa_psk_radius=0 - # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The # entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be # added to enable SHA256-based stronger algorithms. # (dot11RSNAConfigAuthenticationSuitesTable) -#wpa_key_mgmt=WPA-PSK WPA-EAP +wpa_key_mgmt=WPA-EAP # Set of accepted cipher suites (encryption algorithms) for pairwise keys # (unicast packets). This is a space separated list of algorithms: @@ -965,7 +713,7 @@ own_ip_addr=127.0.0.1 # TKIP will be used as the group cipher. # (dot11RSNAConfigPairwiseCiphersTable) # Pairwise cipher for WPA (v1) (default: TKIP) -#wpa_pairwise=TKIP CCMP +wpa_pairwise=CCMP # Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) #rsn_pairwise=CCMP @@ -1028,28 +776,15 @@ own_ip_addr=127.0.0.1 # it is enabled (rsn_preauth=1). # 0 = PMKSA caching enabled (default) # 1 = PMKSA caching disabled -#disable_pmksa_caching=0 +disable_pmksa_caching=0 # okc: Opportunistic Key Caching (aka Proactive Key Caching) # Allow PMK cache to be shared opportunistically among configured interfaces # and BSSes (i.e., all configurations within a single hostapd process). # 0 = disabled (default) # 1 = enabled -#okc=1 +okc=0 -# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold) -# This parameter defines how many open SAE instances can be in progress at the -# same time before the anti-clogging mechanism is taken into use. -#sae_anti_clogging_threshold=5 - -# Enabled SAE finite cyclic groups -# SAE implementation are required to support group 19 (ECC group defined over a -# 256-bit prime order field). All groups that are supported by the -# implementation are enabled by default. This configuration parameter can be -# used to specify a limited set of allowed groups. The group values are listed -# in the IANA registry: -# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9 -#sae_groups=19 20 21 25 26 ##### IEEE 802.11r configuration ############################################## @@ -1273,24 +1008,6 @@ own_ip_addr=127.0.0.1 # 12-digit, all-numeric code that identifies the consumer package. #upc=123456789012 -# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band) -# This value should be set according to RF band(s) supported by the AP if -# hw_mode is not set. For dual band dual concurrent devices, this needs to be -# set to ag to allow both RF bands to be advertized. -#wps_rf_bands=ag - -# NFC password token for WPS -# These parameters can be used to configure a fixed NFC password token for the -# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When -# these parameters are used, the AP is assumed to be deployed with a NFC tag -# that includes the matching NFC password token (e.g., written based on the -# NDEF record from nfc_pw_token). -# -#wps_nfc_dev_pw_id: Device Password ID (16..65535) -#wps_nfc_dh_pubkey: Hexdump of DH Public Key -#wps_nfc_dh_privkey: Hexdump of DH Private Key -#wps_nfc_dev_pw: Hexdump of Device Password - ##### Wi-Fi Direct (P2P) ###################################################### # Enable P2P Device management @@ -1318,16 +1035,6 @@ own_ip_addr=127.0.0.1 # stdoffset[dst[offset][,start[/time],end[/time]]] #time_zone=EST5 -# WNM-Sleep Mode (extended sleep mode for stations) -# 0 = disabled (default) -# 1 = enabled (allow stations to use WNM-Sleep Mode) -#wnm_sleep_mode=1 - -# BSS Transition Management -# 0 = disabled (default) -# 1 = enabled -#bss_transition=1 - ##### IEEE 802.11u-2011 ####################################################### # Enable Interworking service @@ -1381,138 +1088,11 @@ own_ip_addr=127.0.0.1 # Arbitrary number of Roaming Consortium OIs can be configured with each line # adding a new OI to the list. The first three entries are available through # Beacon and Probe Response frames. Any additional entry will be available only -# through ANQP queries. Each OI is between 3 and 15 octets and is configured as +# through ANQP queries. Each OI is between 3 and 15 octets and is configured a # a hexstring. #roaming_consortium=021122 #roaming_consortium=2233445566 -# Venue Name information -# This parameter can be used to configure one or more Venue Name Duples for -# Venue Name ANQP information. Each entry has a two or three character language -# code (ISO-639) separated by colon from the venue name string. -# Note that venue_group and venue_type have to be set for Venue Name -# information to be complete. -#venue_name=eng:Example venue -#venue_name=fin:Esimerkkipaikka - -# Network Authentication Type -# This parameter indicates what type of network authentication is used in the -# network. -# format: [redirect URL] -# Network Authentication Type Indicator values: -# 00 = Acceptance of terms and conditions -# 01 = On-line enrollment supported -# 02 = http/https redirection -# 03 = DNS redirection -#network_auth_type=00 -#network_auth_type=02http://www.example.com/redirect/me/here/ - -# IP Address Type Availability -# format: <1-octet encoded value as hex str> -# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3) -# ipv4_type: -# 0 = Address type not available -# 1 = Public IPv4 address available -# 2 = Port-restricted IPv4 address available -# 3 = Single NATed private IPv4 address available -# 4 = Double NATed private IPv4 address available -# 5 = Port-restricted IPv4 address and single NATed IPv4 address available -# 6 = Port-restricted IPv4 address and double NATed IPv4 address available -# 7 = Availability of the address type is not known -# ipv6_type: -# 0 = Address type not available -# 1 = Address type available -# 2 = Availability of the address type not known -#ipaddr_type_availability=14 - -# Domain Name -# format: [,] -#domain_name=example.com,another.example.com,yet-another.example.com - -# 3GPP Cellular Network information -# format: [;][;...] -#anqp_3gpp_cell_net=244,91;310,026;234,56 - -# NAI Realm information -# One or more realm can be advertised. Each nai_realm line adds a new realm to -# the set. These parameters provide information for stations using Interworking -# network selection to allow automatic connection to a network based on -# credentials. -# format: ,[,][,][,...] -# encoding: -# 0 = Realm formatted in accordance with IETF RFC 4282 -# 1 = UTF-8 formatted character string that is not formatted in -# accordance with IETF RFC 4282 -# NAI Realm(s): Semi-colon delimited NAI Realm(s) -# EAP Method: [:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...] -# AuthParam (Table 8-188 in IEEE Std 802.11-2012): -# ID 2 = Non-EAP Inner Authentication Type -# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2 -# ID 3 = Inner authentication EAP Method Type -# ID 5 = Credential Type -# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token, -# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous, -# 10 = Vendor Specific -#nai_realm=0,example.com;example.net -# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with -# username/password -#nai_realm=0,example.org,13[5:6],21[2:4][5:7] - -##### Hotspot 2.0 ############################################################# - -# Enable Hotspot 2.0 support -#hs20=1 - -# Disable Downstream Group-Addressed Forwarding (DGAF) -# This can be used to configure a network where no group-addressed frames are -# allowed. The AP will not forward any group-address frames to the stations and -# random GTKs are issued for each station to prevent associated stations from -# forging such frames to other stations in the BSS. -#disable_dgaf=1 - -# Operator Friendly Name -# This parameter can be used to configure one or more Operator Friendly Name -# Duples. Each entry has a two or three character language code (ISO-639) -# separated by colon from the operator friendly name string. -#hs20_oper_friendly_name=eng:Example operator -#hs20_oper_friendly_name=fin:Esimerkkioperaattori - -# Connection Capability -# This can be used to advertise what type of IP traffic can be sent through the -# hotspot (e.g., due to firewall allowing/blocking protocols/ports). -# format: :: -# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP -# Port Number: 0..65535 -# Status: 0 = Closed, 1 = Open, 2 = Unknown -# Each hs20_conn_capab line is added to the list of advertised tuples. -#hs20_conn_capab=1:0:2 -#hs20_conn_capab=6:22:1 -#hs20_conn_capab=17:5060:0 - -# WAN Metrics -# format: :
:
    :
    :
      : -# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity -# (encoded as two hex digits) -# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state -# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps; -# 1..4294967295; 0 = unknown -# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps -# 1..4294967295; 0 = unknown -# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%) -# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%) -# Load Measurement Duration: Duration for measuring downlink/uplink load in -# tenths of a second (1..65535); 0 if load cannot be determined -#hs20_wan_metrics=01:8000:1000:80:240:3000 - -# Operating Class Indication -# List of operating classes the BSSes in this ESS use. The Global operating -# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that -# can be used in this. -# format: hexdump of operating class octets -# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz -# channels 36-48): -#hs20_operating_class=5173 - ##### Multiple BSSID support ################################################## # # Above configuration is using the default interface (wlan#, or multi-SSID VLAN diff -purN hostapd-20130302/hostapd/main.c hostapd-20130302-linux/hostapd/main.c --- hostapd-20130302/hostapd/main.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/main.c 2013-07-04 11:17:51.000000000 -0400 @@ -13,6 +13,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "utils/build_features.h" #include "crypto/random.h" #include "crypto/tls.h" #include "common/version.h" @@ -31,6 +32,8 @@ extern int wpa_debug_level; extern int wpa_debug_show_keys; extern int wpa_debug_timestamp; +static int daemonize = 0; +static char *pid_file = NULL; extern struct wpa_driver_ops *wpa_drivers[]; @@ -145,6 +148,14 @@ static void hostapd_logger_cb(void *ctx, } #endif /* CONFIG_NO_HOSTAPD_LOGGER */ +static void hostapd_setup_complete_cb(void *ctx) +{ + if (daemonize && os_daemonize(pid_file)) { + perror("daemon"); + return; + } + daemonize = 0; +} /** * hostapd_init - Allocate and initialize per-interface data @@ -188,6 +199,7 @@ static struct hostapd_iface * hostapd_in if (hapd == NULL) goto fail; hapd->msg_ctx = hapd; + hapd->setup_complete_cb = hostapd_setup_complete_cb; } return hapd_iface; @@ -424,8 +436,6 @@ static void hostapd_global_deinit(const #endif /* CONFIG_NATIVE_WINDOWS */ eap_server_unregister_methods(); - - os_daemonize_terminate(pid_file); } @@ -451,11 +461,6 @@ static int hostapd_global_run(struct hap } #endif /* EAP_SERVER_TNC */ - if (daemonize && os_daemonize(pid_file)) { - perror("daemon"); - return -1; - } - eloop_run(); return 0; @@ -530,14 +535,16 @@ static int hostapd_get_global_ctrl_iface return 0; } +void hostapd_wpa_event(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); + int main(int argc, char *argv[]) { struct hapd_interfaces interfaces; int ret = 1; size_t i; - int c, debug = 0, daemonize = 0; - char *pid_file = NULL; + int c, debug = 0; const char *log_file = NULL; const char *entropy_file = NULL; @@ -555,8 +562,9 @@ int main(int argc, char *argv[]) interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; + wpa_supplicant_event = hostapd_wpa_event; for (;;) { - c = getopt(argc, argv, "Bde:f:hKP:tvg:"); + c = getopt(argc, argv, "Bde:f:hKP:tg:v::"); if (c < 0) break; switch (c) { @@ -588,6 +596,8 @@ int main(int argc, char *argv[]) wpa_debug_timestamp++; break; case 'v': + if (optarg) + exit(!has_feature(optarg)); show_version(); exit(1); break; diff -purN hostapd-20130302/hostapd/Makefile hostapd-20130302-linux/hostapd/Makefile --- hostapd-20130302/hostapd/Makefile 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/hostapd/Makefile 2013-07-06 06:13:59.000000000 -0400 @@ -6,7 +6,7 @@ ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif -CFLAGS += -I../src +CFLAGS += -I../src -D__USE_GNU CFLAGS += -I../src/utils # Uncomment following line and set the path to your kernel tree include @@ -14,6 +14,7 @@ CFLAGS += -I../src/utils # CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include -include .config +-include $(if $(MULTICALL), ../wpa_supplicant/.config) ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS @@ -135,6 +136,9 @@ endif ifdef CONFIG_NO_CTRL_IFACE CFLAGS += -DCONFIG_NO_CTRL_IFACE else +ifdef CONFIG_CTRL_IFACE_MIB +CFLAGS += -DCONFIG_CTRL_IFACE_MIB +endif OBJS += ctrl_iface.o OBJS += ../src/ap/ctrl_iface_ap.o endif @@ -192,10 +196,14 @@ ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif +ifndef MULTICALL +CFLAGS += -DNO_SUPPLICANT +endif + include ../src/drivers/drivers.mak -OBJS += $(DRV_AP_OBJS) -CFLAGS += $(DRV_AP_CFLAGS) -LDFLAGS += $(DRV_AP_LDFLAGS) +OBJS += $(sort $(DRV_AP_OBJS) $(if $(MULTICALL),$(DRV_WPA_OBJS))) +CFLAGS += $(DRV_AP_CFLAGS) $(if $(MULTICALL),$(DRV_WPA_CFLAGS)) +LDFLAGS += $(DRV_AP_LDFLAGS) $(if $(MULTICALL),$(DRV_WPA_LDFLAGS)) LIBS += $(DRV_AP_LIBS) ifdef CONFIG_L2_PACKET @@ -860,6 +868,12 @@ install: all BCHECK=../src/drivers/build.hostapd +hostapd_multi.a: $(BCHECK) $(OBJS) + $(Q)$(CC) -c -o hostapd_multi.o -Dmain=hostapd_main $(CFLAGS) main.c + @$(E) " CC " $< + @rm -f $@ + @$(AR) cr $@ hostapd_multi.o $(OBJS) + hostapd: $(BCHECK) $(OBJS) $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS) @$(E) " LD " $@ @@ -898,6 +912,12 @@ HOBJS += ../src/crypto/aes-internal.o HOBJS += ../src/crypto/aes-internal-enc.o endif +dump_cflags: + @echo -n $(CFLAGS) " " + +dump_ldflags: + @echo -n $(LDFLAGS) $(LIBS) $(EXTRALIBS) " " + nt_password_hash: $(NOBJS) $(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n) @$(E) " LD " $@ diff -purN hostapd-20130302/src/ap/ap_config.h hostapd-20130302-linux/src/ap/ap_config.h --- hostapd-20130302/src/ap/ap_config.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/ap_config.h 2013-07-04 11:17:51.000000000 -0400 @@ -510,9 +510,11 @@ struct hostapd_config { int ht_op_mode_fixed; u16 ht_capab; + int noscan; int ieee80211n; int secondary_channel; int require_ht; + int dynamic_ht40; u32 vht_capab; int ieee80211ac; int require_vht; diff -purN hostapd-20130302/src/ap/beacon.c hostapd-20130302-linux/src/ap/beacon.c --- hostapd-20130302/src/ap/beacon.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/beacon.c 2013-07-06 06:11:10.000000000 -0400 @@ -455,6 +455,10 @@ void handle_probe_req(struct hostapd_dat return; } + if (!sta && hapd->num_sta >= hapd->conf->max_num_sta) + wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " ignored," + " too many connected stations.", MAC2STR(mgmt->sa)); + #ifdef CONFIG_INTERWORKING if (elems.interworking && elems.interworking_len >= 1) { u8 ant = elems.interworking[0] & 0x0f; diff -purN hostapd-20130302/src/ap/ctrl_iface_ap.c hostapd-20130302-linux/src/ap/ctrl_iface_ap.c --- hostapd-20130302/src/ap/ctrl_iface_ap.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/ctrl_iface_ap.c 2013-07-04 11:17:51.000000000 -0400 @@ -20,6 +20,7 @@ #include "ctrl_iface_ap.h" #include "ap_drv_ops.h" +#ifdef CONFIG_CTRL_IFACE_MIB static int hostapd_get_sta_conn_time(struct sta_info *sta, char *buf, size_t buflen) @@ -129,6 +130,7 @@ int hostapd_ctrl_iface_sta_next(struct h return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); } +#endif #ifdef CONFIG_P2P_MANAGER static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, @@ -303,3 +305,4 @@ int hostapd_ctrl_iface_disassociate(stru return 0; } + diff -purN hostapd-20130302/src/ap/drv_callbacks.c hostapd-20130302-linux/src/ap/drv_callbacks.c --- hostapd-20130302/src/ap/drv_callbacks.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/drv_callbacks.c 2013-07-04 11:17:51.000000000 -0400 @@ -714,8 +714,8 @@ static void hostapd_event_eapol_rx(struc } -void wpa_supplicant_event(void *ctx, enum wpa_event_type event, - union wpa_event_data *data) +void hostapd_wpa_event(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) { struct hostapd_data *hapd = ctx; #ifndef CONFIG_NO_STDOUT_DEBUG diff -purN hostapd-20130302/src/ap/hostapd.c hostapd-20130302-linux/src/ap/hostapd.c --- hostapd-20130302/src/ap/hostapd.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/hostapd.c 2013-07-06 06:11:10.000000000 -0400 @@ -22,6 +22,7 @@ #include "beacon.h" #include "iapp.h" #include "ieee802_1x.h" +#include "ieee802_11.h" #include "ieee802_11_auth.h" #include "vlan_init.h" #include "wpa_auth.h" @@ -140,6 +141,24 @@ int hostapd_reload_config(struct hostapd oldconf = hapd->iconf; iface->conf = newconf; + hostapd_select_hw_mode(iface); + iface->freq = hostapd_hw_get_freq(hapd, newconf->channel); + + if (hostapd_set_freq(hapd, newconf->hw_mode, iface->freq, + newconf->channel, + newconf->ieee80211n, + newconf->ieee80211ac, + newconf->secondary_channel, + newconf->vht_oper_chwidth, + newconf->vht_oper_centr_freq_seg0_idx, + newconf->vht_oper_centr_freq_seg1_idx)) { + wpa_printf(MSG_ERROR, "Could not set channel for " + "kernel driver"); + } + + if (iface->current_mode) + hostapd_prepare_rates(iface, iface->current_mode); + for (j = 0; j < iface->num_bss; j++) { hapd = iface->bss[j]; hapd->iconf = newconf; @@ -314,6 +333,7 @@ static void hostapd_cleanup_iface_pre(st static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) { + hostapd_deinit_ht(iface); hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); iface->hw_features = NULL; os_free(iface->current_rates); @@ -877,11 +897,8 @@ int hostapd_setup_interface_complete(str size_t j; u8 *prev_addr; - if (err) { - wpa_printf(MSG_ERROR, "Interface initialization failed"); - eloop_terminate(); - return -1; - } + if (err) + goto error; wpa_printf(MSG_DEBUG, "Completing interface initialization"); if (hapd->iconf->channel) { @@ -901,7 +918,7 @@ int hostapd_setup_interface_complete(str hapd->iconf->vht_oper_centr_freq_seg1_idx)) { wpa_printf(MSG_ERROR, "Could not set channel for " "kernel driver"); - return -1; + goto error; } } @@ -912,7 +929,7 @@ int hostapd_setup_interface_complete(str hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, "Failed to prepare rates table."); - return -1; + goto error; } } @@ -920,14 +937,14 @@ int hostapd_setup_interface_complete(str hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { wpa_printf(MSG_ERROR, "Could not set RTS threshold for " "kernel driver"); - return -1; + goto error; } if (hapd->iconf->fragm_threshold > -1 && hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " "for kernel driver"); - return -1; + goto error; } prev_addr = hapd->own_addr; @@ -937,7 +954,7 @@ int hostapd_setup_interface_complete(str if (j) os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); if (hostapd_setup_bss(hapd, j == 0)) - return -1; + goto error; if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) prev_addr = hapd->own_addr; } @@ -949,7 +966,7 @@ int hostapd_setup_interface_complete(str if (hostapd_driver_commit(hapd) < 0) { wpa_printf(MSG_ERROR, "%s: Failed to commit driver " "configuration", __func__); - return -1; + goto error; } /* @@ -970,6 +987,11 @@ int hostapd_setup_interface_complete(str iface->bss[0]->conf->iface); return 0; + +error: + wpa_printf(MSG_ERROR, "Interface initialization failed"); + eloop_terminate(); + return -1; } diff -purN hostapd-20130302/src/ap/hostapd.h hostapd-20130302-linux/src/ap/hostapd.h --- hostapd-20130302/src/ap/hostapd.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/hostapd.h 2013-07-06 06:11:10.000000000 -0400 @@ -265,6 +265,9 @@ struct hostapd_iface { /* Overlapping BSS information */ int olbc_ht; + int force_20mhz; + struct os_time last_20mhz_trigger; + u16 ht_op_mode; void (*scan_cb)(struct hostapd_iface *iface); }; diff -purN hostapd-20130302/src/ap/hw_features.c hostapd-20130302-linux/src/ap/hw_features.c --- hostapd-20130302/src/ap/hw_features.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/hw_features.c 2013-07-04 11:17:51.000000000 -0400 @@ -494,7 +494,7 @@ static int ieee80211n_check_40mhz(struct { struct wpa_driver_scan_params params; - if (!iface->conf->secondary_channel) + if (!iface->conf->secondary_channel || iface->conf->noscan) return 0; /* HT40 not used */ wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " diff -purN hostapd-20130302/src/ap/ieee802_11.c hostapd-20130302-linux/src/ap/ieee802_11.c --- hostapd-20130302/src/ap/ieee802_11.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/ieee802_11.c 2013-07-06 06:11:10.000000000 -0400 @@ -1484,6 +1484,9 @@ static void handle_beacon(struct hostapd sizeof(mgmt->u.beacon)), &elems, 0); + if (!elems.ht_capabilities) + hostapd_trigger_20mhz(hapd->iface); + ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); } diff -purN hostapd-20130302/src/ap/ieee802_11.h hostapd-20130302-linux/src/ap/ieee802_11.h --- hostapd-20130302/src/ap/ieee802_11.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/ieee802_11.h 2013-07-04 11:17:51.000000000 -0400 @@ -81,4 +81,17 @@ int hostapd_update_time_adv(struct hosta void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr); u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid); +#ifdef CONFIG_IEEE80211N +void hostapd_trigger_20mhz(struct hostapd_iface *iface); +void hostapd_deinit_ht(struct hostapd_iface *iface); + +#else +static inline void hostapd_deinit_ht(struct hostapd_iface *iface) +{ +} +static inline void hostapd_trigger_20mhz(struct hostapd_iface *iface) +{ +} +#endif /* CONFIG_IEEE80211N */ + #endif /* IEEE802_11_H */ diff -purN hostapd-20130302/src/ap/ieee802_11_ht.c hostapd-20130302-linux/src/ap/ieee802_11_ht.c --- hostapd-20130302/src/ap/ieee802_11_ht.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/ieee802_11_ht.c 2013-07-04 11:17:51.000000000 -0400 @@ -20,9 +20,11 @@ #include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" +#include "ap_drv_ops.h" #include "sta_info.h" #include "beacon.h" #include "ieee802_11.h" +#include "utils/eloop.h" u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) @@ -70,12 +72,15 @@ u8 * hostapd_eid_ht_operation(struct hos oper->control_chan = hapd->iconf->channel; oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode); - if (hapd->iconf->secondary_channel == 1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | - HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; - if (hapd->iconf->secondary_channel == -1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | - HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; + + if (!hapd->iface->force_20mhz) { + if (hapd->iconf->secondary_channel == 1) + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | + HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; + if (hapd->iconf->secondary_channel == -1) + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | + HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; + } pos += sizeof(*oper); @@ -270,3 +275,84 @@ void hostapd_get_ht_capab(struct hostapd neg_ht_cap->ht_capabilities_info = host_to_le16(cap); } + +static void hostapd_set_force_20mhz(struct hostapd_iface *iface); + +static void hostapd_restore_40mhz(void *eloop_data, void *user_ctx) +{ + struct hostapd_iface *iface = eloop_data; + struct os_time time; + int timeout; + + if (!iface->last_20mhz_trigger.sec) + return; + + os_get_time(&time); + timeout = iface->last_20mhz_trigger.sec + iface->conf->dynamic_ht40 - + time.sec; + + if (timeout > 0) { + eloop_register_timeout(timeout, 0, hostapd_restore_40mhz, + iface, NULL); + return; + } + + iface->last_20mhz_trigger.sec = 0; + iface->last_20mhz_trigger.usec = 0; + + iface->force_20mhz = 0; + hostapd_set_force_20mhz(iface); +} + +static void hostapd_set_force_20mhz(struct hostapd_iface *iface) +{ + int secondary_channel; + int i; + + ieee802_11_set_beacons(iface); + + for (i = 0; i < iface->num_bss; i++) { + struct hostapd_data *hapd = iface->bss[i]; + + if (iface->force_20mhz) + secondary_channel = 0; + else + secondary_channel = hapd->iconf->secondary_channel; + + if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, + hapd->iconf->channel, + hapd->iconf->ieee80211n, + hapd->iconf->ieee80211ac, + secondary_channel, + hapd->iconf->vht_oper_chwidth, + hapd->iconf->vht_oper_centr_freq_seg0_idx, + hapd->iconf->vht_oper_centr_freq_seg1_idx)) { + wpa_printf(MSG_ERROR, "Could not set channel for " + "kernel driver"); + } + } +} + +void hostapd_deinit_ht(struct hostapd_iface *iface) +{ + eloop_cancel_timeout(hostapd_restore_40mhz, iface, NULL); +} + +void hostapd_trigger_20mhz(struct hostapd_iface *iface) +{ + if (!iface->conf->dynamic_ht40) + return; + + if (!iface->force_20mhz) { + iface->force_20mhz = 1; + hostapd_set_force_20mhz(iface); + } + + if (!iface->last_20mhz_trigger.sec) { + eloop_cancel_timeout(hostapd_restore_40mhz, iface, NULL); + eloop_register_timeout(iface->conf->dynamic_ht40, 0, + hostapd_restore_40mhz, iface, NULL); + } + + os_get_time(&iface->last_20mhz_trigger); +} diff -purN hostapd-20130302/src/ap/ieee802_1x.c hostapd-20130302-linux/src/ap/ieee802_1x.c --- hostapd-20130302/src/ap/ieee802_1x.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/ieee802_1x.c 2013-07-04 11:17:51.000000000 -0400 @@ -2043,11 +2043,12 @@ void ieee802_1x_notify_pre_auth(struct e } -static const char * bool_txt(Boolean bool) +static const char * bool_txt(Boolean bool_val) { - return bool ? "TRUE" : "FALSE"; + return bool_val ? "TRUE" : "FALSE"; } +#ifdef CONFIG_CTRL_IFACE_MIB int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) { @@ -2200,6 +2201,7 @@ int ieee802_1x_get_mib_sta(struct hostap return len; } +#endif static void ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, int success) diff -purN hostapd-20130302/src/ap/sta_info.c hostapd-20130302-linux/src/ap/sta_info.c --- hostapd-20130302/src/ap/sta_info.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/sta_info.c 2013-07-04 11:17:51.000000000 -0400 @@ -576,7 +576,7 @@ void ap_sta_disassociate(struct hostapd_ { wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); - sta->flags &= ~WLAN_STA_ASSOC; + sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); ap_sta_set_authorized(hapd, sta, 0); sta->timeout_next = STA_DEAUTH; wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " diff -purN hostapd-20130302/src/ap/wpa_auth.c hostapd-20130302-linux/src/ap/wpa_auth.c --- hostapd-20130302/src/ap/wpa_auth.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/wpa_auth.c 2013-07-04 11:17:51.000000000 -0400 @@ -2687,6 +2687,7 @@ static const char * wpa_bool_txt(int boo return bool ? "TRUE" : "FALSE"; } +#ifdef CONFIG_CTRL_IFACE_MIB #define RSN_SUITE "%02x-%02x-%02x-%d" #define RSN_SUITE_ARG(s) \ @@ -2831,7 +2832,7 @@ int wpa_get_mib_sta(struct wpa_state_mac return len; } - +#endif void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth) { diff -purN hostapd-20130302/src/ap/wps_hostapd.c hostapd-20130302-linux/src/ap/wps_hostapd.c --- hostapd-20130302/src/ap/wps_hostapd.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/ap/wps_hostapd.c 2013-07-04 11:17:51.000000000 -0400 @@ -871,11 +871,9 @@ int hostapd_init_wps(struct hostapd_data if (conf->rsn_pairwise & WPA_CIPHER_CCMP) wps->encr_types |= WPS_ENCR_AES; - if (conf->rsn_pairwise & WPA_CIPHER_TKIP) + else if (conf->rsn_pairwise & WPA_CIPHER_TKIP) wps->encr_types |= WPS_ENCR_TKIP; - } - - if (conf->wpa & WPA_PROTO_WPA) { + } else if (conf->wpa & WPA_PROTO_WPA) { if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) wps->auth_types |= WPS_AUTH_WPAPSK; if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) @@ -883,7 +881,7 @@ int hostapd_init_wps(struct hostapd_data if (conf->wpa_pairwise & WPA_CIPHER_CCMP) wps->encr_types |= WPS_ENCR_AES; - if (conf->wpa_pairwise & WPA_CIPHER_TKIP) + else if (conf->wpa_pairwise & WPA_CIPHER_TKIP) wps->encr_types |= WPS_ENCR_TKIP; } diff -purN hostapd-20130302/src/capwap/capwap_mgmt_frame_ac.c hostapd-20130302-linux/src/capwap/capwap_mgmt_frame_ac.c --- hostapd-20130302/src/capwap/capwap_mgmt_frame_ac.c 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/capwap_mgmt_frame_ac.c 2013-07-06 06:07:00.000000000 -0400 @@ -0,0 +1,87 @@ +#include "utils/includes.h" + +#include "utils/common.h" +#include "radius/radius.h" +#include "drivers/driver.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" +#include "crypto/random.h" + + +#define MAC_LENGTH 6 +#define HLEN_80211 24 +#define HLEN_LLC 8 + +int same_mac( unsigned char *mac1, unsigned char *mac2){// return 0 + int i; + for(i=0;iaddr2, MAC_LENGTH); + return HLEN_80211 + HLEN_LLC; +} + +int isEAPOL_Frame( unsigned char *buf, int len){ + unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + int i; + + for(i=0; i<6; i++)if(rfc1042_header[i]!=buf[i + HLEN_80211])return 0; + return 1; +} + +void stampa_mac(char *s, unsigned char *mac){ + int i; + wpa_printf(MSG_DEBUG,"%s",s); + for(i=0; i<6; i++)wpa_printf(MSG_DEBUG,"%02X ",mac[i]); + wpa_printf(MSG_DEBUG,"\n"); +} + +void stamp_all_max( unsigned char *buf, unsigned char *own_mac){ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *) buf; + + stampa_mac("addr1 ",hdr->addr1); + stampa_mac("addr2 ",hdr->addr2); + stampa_mac("addr3 ",hdr->addr3); + stampa_mac("own_mac ", own_mac); +} + +int isCallBackFrame( unsigned char *buf, int len, unsigned char *own_mac){ + // return 1 if is it CALL Back Frame + // return 0 if is NOT CALL Back Frame + struct ieee80211_hdr *hdr; + u16 fc; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + if( same_mac(hdr->addr2,own_mac)==0 && same_mac(hdr->addr3,own_mac)==0 )return 1; + return 0; +} + +int AC_get_SubType( unsigned char *buf, int len){ + struct ieee80211_hdr *hdr; + u16 fc; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + return WLAN_FC_GET_STYPE(fc); +} + +int AC_get_Type( unsigned char *buf, int len){ + struct ieee80211_hdr *hdr; + u16 fc; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + return WLAN_FC_GET_TYPE(fc); +} + diff -purN hostapd-20130302/src/capwap/capwap_mgmt_frame.h hostapd-20130302-linux/src/capwap/capwap_mgmt_frame.h --- hostapd-20130302/src/capwap/capwap_mgmt_frame.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/capwap_mgmt_frame.h 2013-07-06 06:07:00.000000000 -0400 @@ -0,0 +1,11 @@ +#include "drivers/driver.h" + +int GetEapol_Frame( unsigned char *sa, unsigned char *buf, int len); + +int isEAPOL_Frame( unsigned char *buf, int len); + +int isCallBackFrame( unsigned char *buf, int len, unsigned char *own_mac); + +int AC_get_SubType( unsigned char *buf, int len); + +int AC_get_Type( unsigned char *buf, int len); diff -purN hostapd-20130302/src/capwap/file_conf.h hostapd-20130302-linux/src/capwap/file_conf.h --- hostapd-20130302/src/capwap/file_conf.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/file_conf.h 2013-07-07 13:07:40.000000000 -0400 @@ -0,0 +1,121 @@ +#define CONFIGFILE "/etc/hostapd_ac.conf" +#define VARLENGTH 1024 + +struct config_ac { + int ac_port; + char ip_ac[50]; + char path_unix_socket[50]; +}config_ac; + +int max_(int integer1,int integer2){ + if(integer1>integer2)return integer1; + return integer2; +} + +int countString(char string[]){ + int cnt=0; + for(cnt=0;string[cnt]!=0;cnt++); + return cnt; +} + +int isEqualString(char String1[],char String2[]){ + int len1=countString(String1); + int len2=countString(String2); + int i; + for( i=0;i=1)b=1; + for(j=0;j<=strlen(rep)-1;j++){ + if(String1[i+j]!=rep[j]){ + b=0; + break; + } + } + if(b){ + for(k=0;k0){ + for(m=0;m<=strlen(String2)-1;++m,k++)tmp[k]=String2[m]; + } + for(l=i+j;l<=strlen(String1)-1;l++,k++)tmp[k]=String1[l]; + tmp[k]=0; + + for(k=0;kip_ac,""); + sprintf(con_ac->path_unix_socket,""); + con_ac->ac_port=0; + + while(1){ + if (fgets(ss,VARLENGTH,file)==NULL)break; + if(ss[0]=='\r' || ss[0]=='\n' || ss[0]=='#')continue; + + if(StartWith(ss,"ip_daemon_ac")){ + ReplaceString(ss, "ip_daemon_ac", ""); + ReplaceString(ss, "=", ""); + ReplaceString(ss, "\n", ""); + ReplaceString(ss, " ", ""); + sprintf(con_ac->ip_ac, "%s", ss); + + }else if(StartWith(ss,"sock_path_ac")){ + ReplaceString(ss, "sock_path_ac", ""); + ReplaceString(ss, "=", ""); + ReplaceString(ss, "\n", ""); + ReplaceString(ss, " ", ""); + sprintf(con_ac->path_unix_socket, "%s", ss); + + }else if(StartWith(ss,"port_daemon_ac")){ + ReplaceString(ss, "port_daemon_ac",""); + ReplaceString(ss, "\n", ""); + ReplaceString(ss, " ", ""); + ReplaceString(ss, "=", ""); + con_ac->ac_port = atoi(ss); + } + + } + fclose(file); + return; +} + + diff -purN hostapd-20130302/src/capwap/ipc_capwap_ac.c hostapd-20130302-linux/src/capwap/ipc_capwap_ac.c --- hostapd-20130302/src/capwap/ipc_capwap_ac.c 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/ipc_capwap_ac.c 2013-07-07 03:52:10.000000000 -0400 @@ -0,0 +1,597 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "eloop.h" +#include "utils/includes.h" + + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "drivers/driver.h" +#include "ap/hostapd.h" +#include "ap/ap_config.h" +#include "ap/ap_drv_ops.h" + +#include "file_conf.h" +#include "smac_code.h" +#include "ipc_capwap_ac.h" + +#define MAX_BUF 3000 + +//#define LOCALUDP +//#define NETUDP +//#define USEIPV6 + +struct config_ac con_ac; +unsigned char wlan0_capa[21]; + +int fd_con; + + +#if defined(LOCALUDP) + struct sockaddr_un addr; + struct sockaddr_un local; + int rn; + +#else + #if defined(USEIPV6) + struct sockaddr_in6 client; + struct sockaddr_in6 addr; + #else + struct sockaddr_in client; + struct sockaddr_in addr; + #endif +#endif + +#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<conf->ssid.ssid_len; + short key_len = (short) h->conf->ssid.wep.len[h->conf->ssid.wep.idx]; + + + wpa_printf(MSG_DEBUG,"SSID: %s ssid_len:%d\n",h->conf->ssid.ssid,ssid_len); + wpa_printf(MSG_DEBUG,"IDX:%d key_len:%d key:%s \n",h->conf->ssid.wep.idx,key_len,h->conf->ssid.wep.key[h->conf->ssid.wep.idx]); + + unsigned char A1 = 0; + unsigned char A2 = 0; + + SETBIT(A1,7); //E (ESS) + CLEARBIT(A1,6); //I (IBSS) + CLEARBIT(A1,5); //C (CF Pollable) + CLEARBIT(A1,4); //F (CF Pollable Request) + if(params->privacy) SETBIT(A1,3); //P (Privacy) + else CLEARBIT(A1,3); //P (Privacy) + if(params->preamble) SETBIT(A1,2); //S (Sort Preamble) + else CLEARBIT(A1,2); //S (Sort Preamble) + CLEARBIT(A1,1); //B (PBCC) + CLEARBIT(A1,0); //A (Channel Agility) + + CLEARBIT(A2,7); //I (IBSS) + CLEARBIT(A2,6); //I (IBSS) + if(params->short_slot_time) SETBIT(A2,5); //I (IBSS) + else CLEARBIT(A2,5); //I (IBSS) + CLEARBIT(A2,4); //I (IBSS) + CLEARBIT(A2,3); //I (IBSS) + CLEARBIT(A2,2); //I (IBSS) + CLEARBIT(A2,1); //I (IBSS) + CLEARBIT(A2,0); //I (IBSS) + + + + int tot_len = 19 + ssid_len + key_len; + + + unsigned char buf[tot_len]; + + wpa_printf(MSG_DEBUG,"Tot Len:%d \n",tot_len); + + buf[0] = 0; // Radio ID + buf[1] = 0; // WLAN ID + buf[2] = A1; // Flags Part1 + buf[3] = A2; // Flags Part2 + + buf[4] = h->conf->ssid.wep.idx; // Key Index + + if(params->privacy) buf[5] = 1; // Key Status + else buf[5] = 0; // Key Status + + wpa_printf(MSG_DEBUG,"keylen: %d \n",key_len); + + + //memcpy(buf+6, &key_len, 1); + //memcpy(buf+7, &key_len, 1); + if (key_len > 0){ + buf[6] = *(&key_len + 1); // Key Length Part1 + buf[7] = *(&key_len + 0); // Key Length Part2 + } + else { + buf[6] = *(&key_len + 0); + buf[7] = *(&key_len + 0); + } + + wpa_printf(MSG_DEBUG,"keylen: %d %02X %02X \n",key_len,buf[6],buf[7]); + + if( key_len ) memcpy( buf + 8, h->conf->ssid.wep.key[h->conf->ssid.wep.idx], key_len); + + buf[8+key_len] = 0; // Group TSC Part1 + buf[9+key_len] = 0; // Group TSC Part2 + buf[10+key_len] = 0; // Group TSC Part3 + buf[11+key_len] = 0; // Group TSC Part4 + + buf[12+key_len] = 0; // Group TSC Part5 + buf[13+key_len] = 0; // Group TSC Part6 + buf[14+key_len] = 0; // QoS + + if(params->privacy) buf[15+key_len] = 1; // Auth Type + else buf[15+key_len] = 0; // Auth Type + + buf[16+key_len] = 1; // Mac Mode + buf[17+key_len] = 2; // Tunnel Mode + buf[18+key_len] = 1; // Suppress SSID + + memcpy(buf + key_len + 19, h->conf->ssid.ssid, ssid_len); + + int i; + for(i=0; iframe_control); + + if( WLAN_FC_GET_STYPE(fc)==WLAN_FC_STYPE_ASSOC_RESP ){ + status = le_to_host16(mgmt->u.assoc_resp.status_code); + + }else if( WLAN_FC_GET_STYPE(fc)==WLAN_FC_STYPE_REASSOC_RESP){ + status = le_to_host16(mgmt->u.reassoc_resp.status_code); + + }else{ + wpa_printf(MSG_ERROR, "Error: ipc_send_add_station\n"); + return; + } + + if(status == 0){ + memcpy(cmd,mgmt->da,6); + send_response(fd, SET_ADDR, cmd, 6); + } + + +} + +void ipc_send_del_station(int fd, u8 *buf, int len){ + u16 fc; + unsigned char cmd[6]; + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *) buf; + + fc = le_to_host16(hdr->frame_control); + + if( WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_DISASSOC ){ + wpa_printf(MSG_DEBUG,"Il pacchetto non e' di tipo DISASSOC\n"); + return; + } + + wpa_printf(MSG_DEBUG,"DEL ADDR: %02X %02X %02X %02X %02X %02X \n",hdr->addr2[0],hdr->addr2[1],hdr->addr2[2],hdr->addr2[3],hdr->addr2[4],hdr->addr2[5]); + + memcpy(cmd,hdr->addr2,6); + send_response(fd, DEL_ADDR, cmd, 6); + +} + +void ipc_send_80211_to_wtp(int fd, u8 *buf, int len){ + + send_response(fd, DATE_TO_WTP, buf, len); +} + +void send_response(int fd, u8 code, u8 *buf, int len){ + u8 tmp_buf[MAX_BUF]; + tmp_buf[0] = code; + + int n; + + #if defined(LOCALUDP) + sprintf(tmp_buf + 1, "%05d", rn); + memcpy(tmp_buf + 6, buf, len); + n = sendto(fd, tmp_buf, len + 6, 0, (struct sockaddr *)&addr, address_size); + #else + memcpy(tmp_buf + 1, buf, len); + n = sendto(fd, tmp_buf, len + 1, 0, (struct sockaddr *)&addr, address_size); + #endif + + + if ( n < 0 ) { + perror("send"); + return; + } + +} + + +void management_recv(int fd, u8 code, u8 *buf, int len, void *hapd, void *inject_func){ + + if(code == PING){ + send_response(fd, PONG, buf, len); + + }else if( code==DATE_TO_AC ){ + struct hostapd_data *h = hapd; + void (*pointer_inject_frame_in_hostapd) (void*,unsigned char*,int); + pointer_inject_frame_in_hostapd = inject_func; + pointer_inject_frame_in_hostapd(h->drv_priv, buf, len); + //hostapd_inject_frame_in_hostapd(h, buf, len); + + }else{ + wpa_printf(MSG_DEBUG,"ERROR IPC: received unrecognizedcode: %d\n",code); + } + +} + +void recv_request(int fd,void *hapd, void *inject_func){ + char str[MAX_BUF]; + + int n; + + #if defined(LOCALUDP) + n = recvfrom(fd, str, MAX_BUF, 0, (struct sockaddr *)&local, &address_size); + #else + n = recvfrom(fd, str, MAX_BUF, 0, (struct sockaddr *)&addr, &address_size); + #endif + + + if(n<=0){ + end_ipc(fd); + return; + } + + + management_recv(fd, str[0], str + 1, n -1, hapd, inject_func); +} + + + +int open_socket(){ + + + int fd_ac, n, con_res; + + char buffer[100]; + + #if defined(LOCALUDP) + srand((unsigned)time(0)); + fd_ac = socket(AF_UNIX, SOCK_DGRAM, 0); + + #elif defined(NETUDP) + #if defined(USEIPV6) + fd_ac = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + #else + fd_ac = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + #endif + + #else + #if defined(USEIPV6) + fd_ac = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); + #else + fd_ac = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); + #endif + + #endif + + #if defined(LOCALUDP) + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, con_ac.path_unix_socket); + local.sun_family = AF_UNIX; + + while(1){ + rn = rand()%100000; + sprintf(local.sun_path, "%s%05d", con_ac.path_unix_socket, rn); + if( bind(fd_ac, (struct sockaddr *)&local, strlen(local.sun_path) + sizeof(local.sun_family))==-1){ + sleep(1); + continue; + } + break; + } + wpa_printf(MSG_DEBUG,"Connect to %s from %s\n",addr.sun_path, local.sun_path); + + #else + #if defined(USEIPV6) + addr.sin6_family = AF_INET6; + addr.sin6_port = con_ac.ac_port; + inet_pton(AF_INET6, con_ac.ip_ac, &addr.sin6_addr); + #else + addr.sin_family = AF_INET; + addr.sin_port = htons(con_ac.ac_port); + addr.sin_addr.s_addr = inet_addr(con_ac.ip_ac); + + #endif + + wpa_printf(MSG_DEBUG,"Try connecting to %s:%d\n",con_ac.ip_ac, con_ac.ac_port); + + #endif + + address_size = sizeof(addr); + + + + while(1){ + #if defined(LOCALUDP) + sprintf(buffer,"Z%05dconnect",rn); + #else + sprintf(buffer,"Zconnect"); + #endif + + buffer[0] = CONNECT; + + n = sendto(fd_ac, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, address_size); + + #if defined(LOCALUDP) + n = recvfrom(fd_ac, buffer, sizeof(buffer), 0, (struct sockaddr *)&local, &address_size); + #else + n = recvfrom(fd_ac, buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &address_size); + #endif + if(buffer[0] == CONNECT_R){ + wpa_printf(MSG_DEBUG,"CONNECTED!!!"); + break; + + }else{ + sleep(3); + + } + } + + return fd_ac; +} + + +void wait_capability_from_AC(int fd, void *hapd){ + unsigned char buffer[10]; + int n; + + sleep(0.5); + + while(1){ + + #if defined(LOCALUDP) + sprintf(buffer,"X%05d",rn); + #else + sprintf(buffer,"X"); + #endif + + buffer[0] = WANT_GOLIVE; + n = sendto(fd, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, address_size); + + + + #if defined(LOCALUDP) + n = recvfrom(fd, buffer, 10, 0, (struct sockaddr *)&local, &address_size); + #else + n = recvfrom(fd, buffer, 10, 0, (struct sockaddr *)&addr, &address_size); + #endif + + if(n<=0){ + end_ipc(fd); + return; + } + + if(buffer[0] == SET_WTPRINFO){ + wpa_printf(MSG_DEBUG,"SET_WTPRINFO: %02X\n",buffer[1]); + memcpy( wlan0_capa+8, buffer+1, 1); + send_response(fd, SET_WTPRINFO_R, NULL, 0); + + }else if(buffer[0] == SET_RATES){ + wpa_printf(MSG_DEBUG,"SET_RATES: %02X %02X %02X %02X %02X %02X %02X %02X\n",buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8]); + memcpy( wlan0_capa, buffer+1, 8); + send_response(fd, SET_RATES_R, NULL, 0); + + }else if(buffer[0] == SET_MDC){ + wpa_printf(MSG_DEBUG,"SET_MDC: %02X %02X %02X %02X %02X %02X\n",buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]); + memcpy( wlan0_capa+9, buffer+1, 6); + send_response(fd, SET_MDC_R, NULL, 0); + + }else if(buffer[0] == SET_MAC){ + wpa_printf(MSG_DEBUG,"SET_MAC: %02X %02X %02X %02X %02X %02X\n",buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]); + memcpy( wlan0_capa+15, buffer+1, 6); + send_response(fd, SET_MAC_R, NULL, 0); + + }else if(buffer[0] == GOLIVE){ + wpa_printf(MSG_DEBUG,"GOLIVE:\n"); + send_response(fd, GOLIVE_R, NULL, 0); + break; + + }else if(buffer[0] == HAVE_TO_WAIT){ + wpa_printf(MSG_DEBUG,"WAIT"); + sleep(1); + + }else if(buffer[0] == CLOSE){ + wpa_printf(MSG_DEBUG,"CLOSE"); + end_ipc(fd); + + }else{ + wpa_printf(MSG_DEBUG,"Unknow code (%d) received in CONNECTed Fase\n",buffer[0]); + } + } + +} + +int end_ipc(int fd){ + + ipc_send_CLOSE_to_AC(fd); + if(fd>=0){ + eloop_unregister_read_sock(fd); + if(close(fd)<0 ){ + + return -1; + } + } + + if( fd_con>=0 ){ + if(close(fd_con)<0 ){ + + } + } + + return 0; +} + +int start_ipc(void *hapd,void *inject_func){ + ReadConfiguration(&con_ac); + wpa_printf(MSG_DEBUG,"< DISCONNECTED >\n"); + + int sockfd = open_socket(); + wpa_printf(MSG_DEBUG,"< CONNECTED >\n"); + + wait_capability_from_AC(sockfd, hapd); + wpa_printf(MSG_DEBUG,"< LIVE >\n"); + + + if(sockfd){ + if (eloop_register_read_sock(sockfd, recv_request, hapd, inject_func)) { + wpa_printf(MSG_ERROR, "Clould not register IPC socket start_ipc"); + return 0; + } + } + + return sockfd; +} + + diff -purN hostapd-20130302/src/capwap/ipc_capwap_ac.h hostapd-20130302-linux/src/capwap/ipc_capwap_ac.h --- hostapd-20130302/src/capwap/ipc_capwap_ac.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/ipc_capwap_ac.h 2013-07-07 03:54:59.000000000 -0400 @@ -0,0 +1,7 @@ +void ipc_send_80211_to_wtp(int fd, u8 *buf, int len); + +int start_ipc(void *hapd,void *inject_func); + +int end_ipc(int fd); + +void send_response(int fd, u8 code, u8 *buf, int len); diff -purN hostapd-20130302/src/capwap/Makefile hostapd-20130302-linux/src/capwap/Makefile --- hostapd-20130302/src/capwap/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/Makefile 2013-07-06 07:04:12.000000000 -0400 @@ -0,0 +1,8 @@ +all: + @echo Nothing to be made. + +clean: + rm -f *~ *.o *.d + +install: + @echo Nothing to be made. diff -purN hostapd-20130302/src/capwap/smac_code.h hostapd-20130302-linux/src/capwap/smac_code.h --- hostapd-20130302/src/capwap/smac_code.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/capwap/smac_code.h 2013-07-06 06:07:00.000000000 -0400 @@ -0,0 +1,107 @@ +#include + +unsigned char ERROR = 0; + +unsigned char CLOSE = 1; + +unsigned char PING = 2; // [2]ping +unsigned char PONG = 3;// [3]pong + +unsigned char START_WLAN = 4; +unsigned char START_WLAN_R = 5; + +unsigned char STOP_WLAN = 6; +unsigned char STOP_WLAN_R = 7; + +unsigned char SET_FREQ = 8; // FREQ sec_channel_offset ht_enabled channel MODE ex. "[8]2462 0 0 11 0" +unsigned char SET_FREQ_R = 9; // 0 or 1 ex. "[9]0" + +unsigned char GET_FREQ = 10; // ex. "[10]" +unsigned char GET_FREQ_R = 11; // ex. "[11]2462 0 0 11 0" + +unsigned char SET_FRAG = 12; // Typically the range used for fragmentation threshold is 256-2346 (-1 == off) ex. "[12]2000" +unsigned char SET_FRAG_R = 13;// ex. "[13]0" + +unsigned char GET_FRAG = 14; // ex. "[14]" (-1 == off) +unsigned char GET_FRAG_R = 15; // ex. "[15]2000" + +unsigned char SET_BITRATE = 16; +unsigned char SET_BITRATE_R = 17; + +unsigned char GET_BITRATE = 18; +unsigned char GET_BITRATE_R = 19; + +unsigned char SET_RTS = 20; // 0-2347 (-1 == off) ex. "[20]100" (-1 == off) +unsigned char SET_RTS_R = 21;// ex. "[21]0" + +unsigned char GET_RTS = 22; // ex. "]22]" (-1 == off) +unsigned char GET_RTS_R = 23; // ex. "[23]100" + +unsigned char SET_TXPOWER = 24; +unsigned char SET_TXPOWER_R = 25; + +unsigned char GET_TXPOWER = 26; +unsigned char GET_TXPOWER_R = 27; + +/* + * VO - 0 CWMIN:3 CWMAX:7 AIFS:2 + * VI - 1 CWMIN:7 CWMAX:15 AIFS:2 + * BE - 2 CWMIN:15 CWMAX:1023 AIFS:3 + * BK - 3 CWMIN:15 CWMAX:1023 AIFS:7 + */ +unsigned char SET_TXQ = 28; +unsigned char SET_TXQ_R = 29; + +unsigned char GET_TXQ = 30; +unsigned char GET_TXQ_R = 31; + +unsigned char SET_ADDR = 32; +unsigned char SET_ADDR_R = 33; + +unsigned char DEL_ADDR = 34; +unsigned char DEL_ADDR_R = 35; + +unsigned char ADD_WLAN = 36; +unsigned char ADD_WLAN_R = 37; + +unsigned char DEL_WLAN = 38; +unsigned char DEL_WLAN_R = 39; + +unsigned char WTPRINFO = 40; +unsigned char WTPRINFO_R = 41; + +unsigned char GET_RATES = 42; +unsigned char GET_RATES_R = 43; + +unsigned char GET_MDC = 44; +unsigned char GET_MDC_R = 45; + +unsigned char SET_WTPRINFO = 46; +unsigned char SET_WTPRINFO_R = 47; + +unsigned char SET_RATES = 48; +unsigned char SET_RATES_R = 49; + +unsigned char SET_MDC = 50; +unsigned char SET_MDC_R = 51; + +unsigned char GOLIVE = 52; +unsigned char GOLIVE_R = 53; + +unsigned char WANT_GOLIVE = 54; +unsigned char HAVE_TO_WAIT = 55; + +unsigned char GET_MAC = 56; +unsigned char GET_MAC_R = 57; + +unsigned char SET_MAC = 58; +unsigned char SET_MAC_R = 59; + +unsigned char DATE_TO_WTP = 100; +unsigned char DATE_TO_AC = 101; + +unsigned char CONNECT = 102; +unsigned char CONNECT_R = 103; + +unsigned char GOWAITWLAN = 104; +unsigned char GOWAITWLAN_R = 105; diff -purN hostapd-20130302/src/common/wpa_common.c hostapd-20130302-linux/src/common/wpa_common.c --- hostapd-20130302/src/common/wpa_common.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/common/wpa_common.c 2013-07-04 11:17:51.000000000 -0400 @@ -965,6 +965,31 @@ const char * wpa_key_mgmt_txt(int key_mg } +static void wpa_fixup_wpa_ie_rsn(u8 *assoc_ie, const u8 *wpa_msg_ie, + size_t rsn_ie_len) +{ + int pos, count; + + pos = sizeof(struct rsn_ie_hdr) + RSN_SELECTOR_LEN; + if (rsn_ie_len < pos + 2) + return; + + count = WPA_GET_LE16(wpa_msg_ie + pos); + pos += 2 + count * RSN_SELECTOR_LEN; + if (rsn_ie_len < pos + 2) + return; + + count = WPA_GET_LE16(wpa_msg_ie + pos); + pos += 2 + count * RSN_SELECTOR_LEN; + if (rsn_ie_len < pos + 2) + return; + + if (!assoc_ie[pos] && !assoc_ie[pos + 1] && + (wpa_msg_ie[pos] || wpa_msg_ie[pos + 1])) + memcpy(&assoc_ie[pos], &wpa_msg_ie[pos], 2); +} + + int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) @@ -972,8 +997,19 @@ int wpa_compare_rsn_ie(int ft_initial_as if (ie1 == NULL || ie2 == NULL) return -1; - if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) - return 0; /* identical IEs */ + if (ie1len == ie2len) { + u8 *ie_tmp; + + if (os_memcmp(ie1, ie2, ie1len) == 0) + return 0; /* identical IEs */ + + ie_tmp = alloca(ie1len); + memcpy(ie_tmp, ie1, ie1len); + wpa_fixup_wpa_ie_rsn(ie_tmp, ie2, ie1len); + + if (os_memcmp(ie_tmp, ie2, ie1len) == 0) + return 0; /* only mismatch in RSN capabilties */ + } #ifdef CONFIG_IEEE80211R if (ft_initial_assoc) { diff -purN hostapd-20130302/src/drivers/capwap_copy.h hostapd-20130302-linux/src/drivers/capwap_copy.h --- hostapd-20130302/src/drivers/capwap_copy.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/capwap_copy.h 2013-07-06 06:06:45.000000000 -0400 @@ -0,0 +1,9 @@ +enum capwap_iftype { + ADHOC, + STATION, + AP, + MONITOR, + P2P_CLIENT, + P2P_GO +}; + diff -purN hostapd-20130302/src/drivers/driver_capwap.c hostapd-20130302-linux/src/drivers/driver_capwap.c --- hostapd-20130302/src/drivers/driver_capwap.c 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/driver_capwap.c 2013-07-07 03:56:47.000000000 -0400 @@ -0,0 +1,9603 @@ +/* + * Driver interaction with Linux capwap/cfg80211 + * Copyright (c) 2002-2012, Jouni Malinen + * Copyright (c) 2003-2004, Instant802 Networks, Inc. + * Copyright (c) 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2007, Johannes Berg + * Copyright (c) 2009-2010, Atheros Communications + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nl80211_copy.h" +#include "capwap_copy.h" + +#include "common.h" +#include "eloop.h" +#include "utils/list.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "l2_packet/l2_packet.h" +#include "capwap/capwap_mgmt_frame.h" +#include "capwap/ipc_capwap_ac.h" +#include "netlink_fake.h" +#include "linux_ioctl_fake.h" +#include "radiotap.h" +#include "radiotap_iter.h" +#include "rfkill.h" +#include "driver.h" + +#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<>= 22; + port_bitmap[port / 32] &= ~(1 << (port % 32)); + + nl_handle_destroy(handle); +} +#endif /* CONFIG_LIBNL20 */ + + +static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg) +{ + struct nl_handle *handle; + handle = capwap_handle_alloc(cb); + if (handle == NULL) { + wpa_printf(MSG_ERROR, "capwap: Failed to allocate netlink " + "callbacks (%s)", dbg); + return NULL; + } + + if (genl_connect(handle)) { + wpa_printf(MSG_DEBUG, "capwap: Failed to connect to generic " + "netlink (%s)", dbg); + capwap_handle_destroy(handle); + return NULL; + } + + return handle; +} + +static struct nl_cache * nl_create_cache(struct nl_handle *handle) +{ + struct nl_cache *cache; + wpa_printf(MSG_ERROR, "nl_create_cache()"); + if (genl_ctrl_alloc_cache(handle, &cache) < 0) { + wpa_printf(MSG_ERROR, "capwap: Failed to allocate generic " + "netlink cache"); + return NULL; + } + + return cache; +} + + + +static void nl_destroy_handles(struct nl_handle **handle) +{ + if (*handle == NULL) + return; + capwap_handle_destroy(*handle); + *handle = NULL; +} + +static void nl_destroy_cache(struct nl_cache **cache) +{ + if (*cache == NULL) + return; + nl_cache_free(*cache); + *cache = NULL; +} + + +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ +#endif +#ifndef IFF_DORMANT +#define IFF_DORMANT 0x20000 /* driver signals dormant */ +#endif + +#ifndef IF_OPER_DORMANT +#define IF_OPER_DORMANT 5 +#endif +#ifndef IF_OPER_UP +#define IF_OPER_UP 6 +#endif + +struct capwap_global { + struct dl_list interfaces; + int if_add_ifindex; + struct netlink_data *netlink; + struct nl_cb *nl_cb; + struct nl_handle *nl; + struct genl_family *capwap; + int ioctl_sock; /* socket for ioctl() use */ + struct nl_cache *nl_cache; + struct nl_cache *nl_event_cache; + struct nl_handle *nl_event; +}; + +struct capwap_wiphy_data { + struct dl_list list; + struct dl_list bsss; + struct dl_list drvs; + + struct nl_handle *nl_beacons; + struct nl_cb *nl_cb; + struct nl_cache *nl_beacons_cache; + int wiphy_idx; +}; + +static void capwap_global_deinit(void *priv); + +struct i802_bss { + struct wpa_driver_capwap_data *drv; + struct i802_bss *next; + int ifindex; + char ifname[IFNAMSIZ + 1]; + char brname[IFNAMSIZ]; + unsigned int beacon_set:1; + unsigned int added_if_into_bridge:1; + unsigned int added_bridge:1; + unsigned int in_deinit:1; + struct nl_cache *nl_mgmt_cache; + struct nl_cache *nl_preq_cache; + u8 addr[ETH_ALEN]; + + int freq; + + void *ctx; + struct nl_handle *nl_preq, *nl_mgmt; + struct nl_cb *nl_cb; + + struct capwap_wiphy_data *wiphy_data; + struct dl_list wiphy_list; +}; + +struct wpa_driver_capwap_data { + struct capwap_global *global; + struct dl_list list; + struct dl_list wiphy_list; + u8 addr[ETH_ALEN]; + char phyname[32]; + void *ctx; + int ifindex; + int if_removed; + int if_disabled; + int ignore_if_down_event; +#ifdef CONFIG_RFKILL + struct rfkill_data *rfkill; +#endif + struct wpa_driver_capa capa; + int has_capability; + + int operstate; + + int scan_complete_events; + + struct nl_cb *nl_cb; + + u8 auth_bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + int associated; + u8 ssid[32]; + size_t ssid_len; + enum nl80211_iftype nlmode; + enum nl80211_iftype ap_scan_as_station; + unsigned int assoc_freq; + + int monitor_sock; + int monitor_ifidx; + int monitor_refcount; + + unsigned int disabled_11b_rates:1; + unsigned int pending_remain_on_chan:1; + unsigned int in_interface_list:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int scan_for_auth:1; + unsigned int retry_auth:1; + unsigned int use_monitor:1; + unsigned int ignore_next_local_disconnect:1; + + u64 remain_on_chan_cookie; + u64 send_action_cookie; + + unsigned int last_mgmt_freq; + + struct wpa_driver_scan_filter *filter_ssids; + size_t num_filter_ssids; + + struct i802_bss first_bss; + + int eapol_tx_sock; + +#ifdef HOSTAPD + int eapol_sock; /* socket for EAPOL frames */ + + int default_if_indices[16]; + int *if_indices; + int num_if_indices; + + int last_freq; + int last_freq_ht; +#endif /* HOSTAPD */ + + /* From failed authentication command */ + int auth_freq; + u8 auth_bssid_[ETH_ALEN]; + u8 auth_ssid[32]; + size_t auth_ssid_len; + int auth_alg; + u8 *auth_ie; + size_t auth_ie_len; + u8 auth_wep_key[4][16]; + size_t auth_wep_key_len[4]; + int auth_wep_tx_keyidx; + int auth_local_state_change; + int auth_p2p; +}; + + +static void wpa_driver_capwap_deinit(struct i802_bss *bss); +static void wpa_driver_capwap_scan_timeout(void *eloop_ctx, + void *timeout_ctx); +static int wpa_driver_capwap_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode); +static int +wpa_driver_capwap_finish_drv_init(struct wpa_driver_capwap_data *drv); +static int wpa_driver_capwap_mlme(struct wpa_driver_capwap_data *drv, + const u8 *addr, int cmd, u16 reason_code, + int local_state_change); +static void capwap_remove_monitor_interface( + struct wpa_driver_capwap_data *drv); +static int capwap_send_frame_cmd(struct i802_bss *bss, + unsigned int freq, unsigned int wait, + const u8 *buf, size_t buf_len, u64 *cookie, + int no_cck, int no_ack, int offchanok); +static int wpa_driver_capwap_probe_req_report(struct i802_bss *bss, + int report); +#ifdef ANDROID +static int android_pno_start(struct i802_bss *bss, + struct wpa_driver_scan_params *params); +static int android_pno_stop(struct i802_bss *bss); +#endif /* ANDROID */ + +#ifdef HOSTAPD +static void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); +static void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); +static int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); +static int wpa_driver_capwap_if_remove(struct i802_bss *bss, + enum wpa_driver_if_type type, + const char *ifname); +#else /* HOSTAPD */ +static inline void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) +{ +} + +static inline void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) +{ +} + +static inline int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) +{ + return 0; +} +#endif /* HOSTAPD */ + +static int wpa_driver_capwap_set_freq(struct i802_bss *bss, + struct hostapd_freq_params *freq); +static int capwap_disable_11b_rates(struct wpa_driver_capwap_data *drv, + int ifindex, int disabled); + +static int capwap_leave_ibss(struct wpa_driver_capwap_data *drv); +static int wpa_driver_capwap_authenticate_retry( + struct wpa_driver_capwap_data *drv); + + +static int is_ap_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_AP || + nlmode == NL80211_IFTYPE_P2P_GO); +} + + +static int is_sta_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_STATION || + nlmode == NL80211_IFTYPE_P2P_CLIENT); +} + + +static int is_p2p_interface(enum nl80211_iftype nlmode) +{ + return (nlmode == NL80211_IFTYPE_P2P_CLIENT || + nlmode == NL80211_IFTYPE_P2P_GO); +} + + +struct capwap_bss_info_arg { + struct wpa_driver_capwap_data *drv; + struct wpa_scan_results *res; + unsigned int assoc_freq; + u8 assoc_bssid[ETH_ALEN]; +}; + +static int bss_info_handler(struct nl_msg *msg, void *arg); + + +/* capwap code */ +static int ack_handler(struct nl_msg *msg, void *arg) +{ + int *err = arg; + *err = 0; + return NL_STOP; +} + +static int finish_handler(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + *ret = 0; + return NL_SKIP; +} + +static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg) +{ + int *ret = arg; + *ret = err->error; + return NL_SKIP; +} + + +static int no_seq_check(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + + +static int send_and_recv(struct capwap_global *global, + struct nl_handle *nl_handle, struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + struct nl_cb *cb; + int err = -ENOMEM; + + cb = nl_cb_clone(global->nl_cb); + if (!cb) + goto out; + + err = nl_send_auto_complete(nl_handle, msg); + if (err < 0) + goto out; + + err = 1; + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); + + if (valid_handler) + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, + valid_handler, valid_data); + + while (err > 0) + nl_recvmsgs(nl_handle, cb); + out: + nl_cb_put(cb); + nlmsg_free(msg); + return err; +} + + +static int send_and_recv_msgs_global(struct capwap_global *global, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + return send_and_recv(global, global->nl, msg, valid_handler, + valid_data); +} + + +static int send_and_recv_msgs(struct wpa_driver_capwap_data *drv, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + return send_and_recv(drv->global, drv->global->nl, msg, + valid_handler, valid_data); +} + + +struct family_data { + const char *group; + int id; +}; + + +static int family_handler(struct nl_msg *msg, void *arg) +{ + struct family_data *res = arg; + struct nlattr *tb[CTRL_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *mcgrp; + int i; + + nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[CTRL_ATTR_MCAST_GROUPS]) + return NL_SKIP; + + nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { + struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; + nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), + nla_len(mcgrp), NULL); + if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || + !tb2[CTRL_ATTR_MCAST_GRP_ID] || + os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]), + res->group, + nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0) + continue; + res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); + break; + }; + + return NL_SKIP; +} + + +static int nl_get_multicast_id(struct capwap_global *global, + const char *family, const char *group) +{ + struct nl_msg *msg; + int ret = -1; + struct family_data res = { group, -ENOENT }; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"), + 0, 0, CTRL_CMD_GETFAMILY, 0); + NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); + + ret = send_and_recv_msgs_global(global, msg, family_handler, &res); + msg = NULL; + if (ret == 0) + ret = res.id; + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static void * capwap_cmd(struct wpa_driver_capwap_data *drv, + struct nl_msg *msg, int flags, uint8_t cmd) +{ + return NULL; +} + + +struct wiphy_idx_data { + int wiphy_idx; +}; + + +static int netdev_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wiphy_idx_data *info = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_WIPHY]) + info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + + return NL_SKIP; +} + + +static int capwap_get_wiphy_index(struct i802_bss *bss) +{ + struct nl_msg *msg; + struct wiphy_idx_data data = { + .wiphy_idx = -1, + }; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0) + return data.wiphy_idx; + msg = NULL; +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int capwap_register_beacons(struct wpa_driver_capwap_data *drv, + struct capwap_wiphy_data *w) +{ + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS); + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx); + + ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Register beacons command " + "failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static void capwap_recv_beacons(int sock, void *eloop_ctx, void *handle) +{ + struct capwap_wiphy_data *w = eloop_ctx; + + wpa_printf(MSG_EXCESSIVE, "capwap: Beacon event message available"); + + nl_recvmsgs(handle, w->nl_cb); +} + + +static int process_beacon_event(struct nl_msg *msg, void *arg) +{ + struct capwap_wiphy_data *w = arg; + struct wpa_driver_capwap_data *drv; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + union wpa_event_data event; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (gnlh->cmd != NL80211_CMD_FRAME) { + wpa_printf(MSG_DEBUG, "capwap: Unexpected beacon event? (%d)", + gnlh->cmd); + return NL_SKIP; + } + + if (!tb[NL80211_ATTR_FRAME]) + return NL_SKIP; + + dl_list_for_each(drv, &w->drvs, struct wpa_driver_capwap_data, + wiphy_list) { + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]); + event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]); + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + } + + return NL_SKIP; +} + + +static struct capwap_wiphy_data * +capwap_get_wiphy_data_ap(struct i802_bss *bss) +{ + static DEFINE_DL_LIST(capwap_wiphys); + struct capwap_wiphy_data *w; + int wiphy_idx, found = 0; + struct i802_bss *tmp_bss; + + if (bss->wiphy_data != NULL) + return bss->wiphy_data; + + wiphy_idx = capwap_get_wiphy_index(bss); + + dl_list_for_each(w, &capwap_wiphys, struct capwap_wiphy_data, list) { + if (w->wiphy_idx == wiphy_idx) + goto add; + } + + /* alloc new one */ + w = os_zalloc(sizeof(*w)); + if (w == NULL) + return NULL; + w->wiphy_idx = wiphy_idx; + dl_list_init(&w->bsss); + dl_list_init(&w->drvs); + + w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!w->nl_cb) { + os_free(w); + return NULL; + } + nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); + nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event, + w); + + w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb, + "wiphy beacons"); + + w->nl_beacons_cache = nl_create_cache(w->nl_beacons); + + if (w->nl_beacons == NULL) { + os_free(w); + return NULL; + } + + if (capwap_register_beacons(bss->drv, w)) { + nl_destroy_cache(&w->nl_beacons_cache); + nl_destroy_handles(&w->nl_beacons); + os_free(w); + return NULL; + } + + eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons), + capwap_recv_beacons, w, w->nl_beacons); + + dl_list_add(&capwap_wiphys, &w->list); + +add: + /* drv entry for this bss already there? */ + dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) { + if (tmp_bss->drv == bss->drv) { + found = 1; + break; + } + } + /* if not add it */ + if (!found) + dl_list_add(&w->drvs, &bss->drv->wiphy_list); + + dl_list_add(&w->bsss, &bss->wiphy_list); + bss->wiphy_data = w; + return w; +} + + +static void capwap_put_wiphy_data_ap(struct i802_bss *bss) +{ + struct capwap_wiphy_data *w = bss->wiphy_data; + struct i802_bss *tmp_bss; + int found = 0; + + if (w == NULL) + return; + bss->wiphy_data = NULL; + dl_list_del(&bss->wiphy_list); + + /* still any for this drv present? */ + dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) { + if (tmp_bss->drv == bss->drv) { + found = 1; + break; + } + } + /* if not remove it */ + if (!found) + dl_list_del(&bss->drv->wiphy_list); + + if (!dl_list_empty(&w->bsss)) + return; + + eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons)); + + nl_cb_put(w->nl_cb); + nl_destroy_cache(&w->nl_beacons_cache); + nl_destroy_handles(&w->nl_beacons); + dl_list_del(&w->list); + os_free(w); +} + + +static int wpa_driver_capwap_get_bssid(void *priv, u8 *bssid) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + if (!drv->associated) + return -1; + os_memcpy(bssid, drv->bssid, ETH_ALEN); + return 0; +} + + +static int wpa_driver_capwap_get_ssid(void *priv, u8 *ssid) +{ + wpa_printf(MSG_DEBUG, "wpa_driver_capwap_get_ssid"); + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + if (!drv->associated) + return -1; + os_memcpy(ssid, drv->ssid, drv->ssid_len); + return drv->ssid_len; +} + + +static void wpa_driver_capwap_event_link(struct wpa_driver_capwap_data *drv, + char *buf, size_t len, int del) +{ + union wpa_event_data event; + + os_memset(&event, 0, sizeof(event)); + if (len > sizeof(event.interface_status.ifname)) + len = sizeof(event.interface_status.ifname) - 1; + os_memcpy(event.interface_status.ifname, buf, len); + event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : + EVENT_INTERFACE_ADDED; + + wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", + del ? "DEL" : "NEW", + event.interface_status.ifname, + del ? "removed" : "added"); + + if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) { + if (del) { + if (drv->if_removed) { + wpa_printf(MSG_DEBUG, "capwap: if_removed " + "already set - ignore event"); + return; + } + drv->if_removed = 1; + } else { + if (if_nametoindex(drv->first_bss.ifname) == 0) { + wpa_printf(MSG_DEBUG, "capwap: Interface %s " + "does not exist - ignore " + "RTM_NEWLINK", + drv->first_bss.ifname); + return; + } + if (!drv->if_removed) { + wpa_printf(MSG_DEBUG, "capwap: if_removed " + "already cleared - ignore event"); + return; + } + drv->if_removed = 0; + } + } + + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); +} + + +static int wpa_driver_capwap_own_ifname(struct wpa_driver_capwap_data *drv, + u8 *buf, size_t len) +{ + int attrlen, rta_len; + struct rtattr *attr; + + attrlen = len; + attr = (struct rtattr *) buf; + + rta_len = RTA_ALIGN(sizeof(struct rtattr)); + while (RTA_OK(attr, attrlen)) { + if (attr->rta_type == IFLA_IFNAME) { + if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname) + == 0) + return 1; + else + break; + } + attr = RTA_NEXT(attr, attrlen); + } + + return 0; +} + + +static int wpa_driver_capwap_own_ifindex(struct wpa_driver_capwap_data *drv, + int ifindex, u8 *buf, size_t len) +{ + if (drv->ifindex == ifindex) + return 1; + + if (drv->if_removed && wpa_driver_capwap_own_ifname(drv, buf, len)) { + drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname); + wpa_printf(MSG_DEBUG, "capwap: Update ifindex for a removed " + "interface"); + wpa_driver_capwap_finish_drv_init(drv); + return 1; + } + + return 0; +} + + +static struct wpa_driver_capwap_data * +capwap_find_drv(struct capwap_global *global, int idx, u8 *buf, size_t len) +{ + struct wpa_driver_capwap_data *drv; + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_capwap_data, list) { + if (wpa_driver_capwap_own_ifindex(drv, idx, buf, len) || + have_ifidx(drv, idx)) + return drv; + } + return NULL; +} + + +static void wpa_driver_capwap_event_rtm_newlink(void *ctx, + struct ifinfomsg *ifi, + u8 *buf, size_t len) +{ + struct capwap_global *global = ctx; + struct wpa_driver_capwap_data *drv; + int attrlen, rta_len; + struct rtattr *attr; + u32 brid = 0; + char namebuf[IFNAMSIZ]; + + drv = capwap_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) { + wpa_printf(MSG_DEBUG, "capwap: Ignore event for foreign " + "ifindex %d", ifi->ifi_index); + return; + } + + if (ifi->ifi_family == AF_BRIDGE && + drv->nlmode != NL80211_IFTYPE_AP) + return; + + wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " + "(%s%s%s%s)", + drv->operstate, ifi->ifi_flags, + (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", + (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", + (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", + (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); + + if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { + if (if_indextoname(ifi->ifi_index, namebuf) && + linux_iface_fake_up(drv->global->ioctl_sock, + drv->first_bss.ifname) > 0) { + wpa_printf(MSG_DEBUG, "capwap: Ignore interface down " + "event since interface %s is up", namebuf); + return; + } + wpa_printf(MSG_DEBUG, "capwap: Interface down"); + if (drv->ignore_if_down_event) { + wpa_printf(MSG_DEBUG, "capwap: Ignore interface down " + "event generated by mode change"); + drv->ignore_if_down_event = 0; + } else { + drv->if_disabled = 1; + wpa_supplicant_event(drv->ctx, + EVENT_INTERFACE_DISABLED, NULL); + } + } + + if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { + if (if_indextoname(ifi->ifi_index, namebuf) && + linux_iface_fake_up(drv->global->ioctl_sock, + drv->first_bss.ifname) == 0) { + wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " + "event since interface %s is down", + namebuf); + } else if (if_nametoindex(drv->first_bss.ifname) == 0) { + wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " + "event since interface %s does not exist", + drv->first_bss.ifname); + } else if (drv->if_removed) { + wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " + "event since interface %s is marked " + "removed", drv->first_bss.ifname); + } else { + wpa_printf(MSG_DEBUG, "capwap: Interface up"); + drv->if_disabled = 0; + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); + } + } + + /* + * Some drivers send the association event before the operup event--in + * this case, lifting operstate in wpa_driver_capwap_set_operstate() + * fails. This will hit us when wpa_supplicant does not need to do + * IEEE 802.1X authentication + */ + if (drv->operstate == 1 && + (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && + !(ifi->ifi_flags & IFF_RUNNING)) + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, + -1, IF_OPER_UP); + + attrlen = len; + attr = (struct rtattr *) buf; + rta_len = RTA_ALIGN(sizeof(struct rtattr)); + while (RTA_OK(attr, attrlen)) { + if (attr->rta_type == IFLA_IFNAME) { + wpa_driver_capwap_event_link( + drv, + ((char *) attr) + rta_len, + attr->rta_len - rta_len, 0); + } else if (attr->rta_type == IFLA_MASTER) + brid = nla_get_u32((struct nlattr *) attr); + attr = RTA_NEXT(attr, attrlen); + } + + if (ifi->ifi_family == AF_BRIDGE && brid) { + /* device has been added to bridge */ + if_indextoname(brid, namebuf); + wpa_printf(MSG_DEBUG, "capwap: Add ifindex %u for bridge %s", + brid, namebuf); + add_ifidx(drv, brid); + } +} + + +static void wpa_driver_capwap_event_rtm_dellink(void *ctx, + struct ifinfomsg *ifi, + u8 *buf, size_t len) +{ + struct capwap_global *global = ctx; + struct wpa_driver_capwap_data *drv; + int attrlen, rta_len; + struct rtattr *attr; + u32 brid = 0; + + drv = capwap_find_drv(global, ifi->ifi_index, buf, len); + if (!drv) { + wpa_printf(MSG_DEBUG, "capwap: Ignore dellink event for " + "foreign ifindex %d", ifi->ifi_index); + return; + } + + attrlen = len; + attr = (struct rtattr *) buf; + + if (ifi->ifi_family == AF_BRIDGE && + drv->nlmode != NL80211_IFTYPE_AP) + return; + + rta_len = RTA_ALIGN(sizeof(struct rtattr)); + while (RTA_OK(attr, attrlen)) { + if (attr->rta_type == IFLA_IFNAME) { + wpa_driver_capwap_event_link( + drv, + ((char *) attr) + rta_len, + attr->rta_len - rta_len, 1); + } else if (attr->rta_type == IFLA_MASTER) + brid = nla_get_u32((struct nlattr *) attr); + attr = RTA_NEXT(attr, attrlen); + } + + if (ifi->ifi_family == AF_BRIDGE && brid) { + /* device has been removed from bridge */ + char namebuf[IFNAMSIZ]; + if_indextoname(brid, namebuf); + wpa_printf(MSG_DEBUG, "capwap: Remove ifindex %u for bridge " + "%s", brid, namebuf); + del_ifidx(drv, brid); + } +} + + +static void mlme_event_auth(struct wpa_driver_capwap_data *drv, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + + wpa_printf(MSG_DEBUG, "capwap: Authenticate event"); + mgmt = (const struct ieee80211_mgmt *) frame; + if (len < 24 + sizeof(mgmt->u.auth)) { + wpa_printf(MSG_DEBUG, "capwap: Too short association event " + "frame"); + return; + } + + os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); + event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); + event.auth.auth_transaction = + le_to_host16(mgmt->u.auth.auth_transaction); + event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); + if (len > 24 + sizeof(mgmt->u.auth)) { + event.auth.ies = mgmt->u.auth.variable; + event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); + } + + wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); +} + + +static unsigned int capwap_get_assoc_freq(struct wpa_driver_capwap_data *drv) +{ + struct nl_msg *msg; + int ret; + struct capwap_bss_info_arg arg; + + os_memset(&arg, 0, sizeof(arg)); + msg = nlmsg_alloc(); + if (!msg) + goto nla_put_failure; + + capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + arg.drv = drv; + ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + msg = NULL; + if (ret == 0) { + wpa_printf(MSG_DEBUG, "capwap: Operating frequency for the " + "associated BSS from scan results: %u MHz", + arg.assoc_freq); + return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq; + } + wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " + "(%s)", ret, strerror(-ret)); +nla_put_failure: + nlmsg_free(msg); + return drv->assoc_freq; +} + + +static void mlme_event_assoc(struct wpa_driver_capwap_data *drv, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + u16 status; + + wpa_printf(MSG_DEBUG, "capwap: Associate event"); + mgmt = (const struct ieee80211_mgmt *) frame; + if (len < 24 + sizeof(mgmt->u.assoc_resp)) { + wpa_printf(MSG_DEBUG, "capwap: Too short association event " + "frame"); + return; + } + + status = le_to_host16(mgmt->u.assoc_resp.status_code); + if (status != WLAN_STATUS_SUCCESS) { + os_memset(&event, 0, sizeof(event)); + event.assoc_reject.bssid = mgmt->bssid; + if (len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_reject.resp_ies = + (u8 *) mgmt->u.assoc_resp.variable; + event.assoc_reject.resp_ies_len = + len - 24 - sizeof(mgmt->u.assoc_resp); + } + event.assoc_reject.status_code = status; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); + return; + } + + drv->associated = 1; + os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); + + os_memset(&event, 0, sizeof(event)); + if (len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; + event.assoc_info.resp_ies_len = + len - 24 - sizeof(mgmt->u.assoc_resp); + } + + event.assoc_info.freq = drv->assoc_freq; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); +} + + +static void mlme_event_connect(struct wpa_driver_capwap_data *drv, + enum nl80211_commands cmd, struct nlattr *status, + struct nlattr *addr, struct nlattr *req_ie, + struct nlattr *resp_ie) +{ + union wpa_event_data event; + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + /* + * Avoid reporting two association events that would confuse + * the core code. + */ + wpa_printf(MSG_DEBUG, "capwap: Ignore connect event (cmd=%d) " + "when using userspace SME", cmd); + return; + } + + if (cmd == NL80211_CMD_CONNECT) + wpa_printf(MSG_DEBUG, "capwap: Connect event"); + else if (cmd == NL80211_CMD_ROAM) + wpa_printf(MSG_DEBUG, "capwap: Roam event"); + + os_memset(&event, 0, sizeof(event)); + if (cmd == NL80211_CMD_CONNECT && + nla_get_u16(status) != WLAN_STATUS_SUCCESS) { + if (addr) + event.assoc_reject.bssid = nla_data(addr); + if (resp_ie) { + event.assoc_reject.resp_ies = nla_data(resp_ie); + event.assoc_reject.resp_ies_len = nla_len(resp_ie); + } + event.assoc_reject.status_code = nla_get_u16(status); + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); + return; + } + + drv->associated = 1; + if (addr) + os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); + + if (req_ie) { + event.assoc_info.req_ies = nla_data(req_ie); + event.assoc_info.req_ies_len = nla_len(req_ie); + } + if (resp_ie) { + event.assoc_info.resp_ies = nla_data(resp_ie); + event.assoc_info.resp_ies_len = nla_len(resp_ie); + } + + event.assoc_info.freq = capwap_get_assoc_freq(drv); + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); +} + + +static void mlme_event_disconnect(struct wpa_driver_capwap_data *drv, + struct nlattr *reason, struct nlattr *addr, + struct nlattr *by_ap) +{ + union wpa_event_data data; + unsigned int locally_generated = by_ap == NULL; + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + /* + * Avoid reporting two disassociation events that could + * confuse the core code. + */ + wpa_printf(MSG_DEBUG, "capwap: Ignore disconnect " + "event when using userspace SME"); + return; + } + + if (drv->ignore_next_local_disconnect) { + drv->ignore_next_local_disconnect = 0; + if (locally_generated) { + wpa_printf(MSG_DEBUG, "capwap: Ignore disconnect " + "event triggered during reassociation"); + return; + } + wpa_printf(MSG_WARNING, "capwap: Was expecting local " + "disconnect but got another disconnect " + "event first"); + } + + wpa_printf(MSG_DEBUG, "capwap: Disconnect event"); + drv->associated = 0; + os_memset(&data, 0, sizeof(data)); + if (reason) + data.deauth_info.reason_code = nla_get_u16(reason); + data.deauth_info.locally_generated = by_ap == NULL; + wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data); +} + + +static void mlme_event_ch_switch(struct wpa_driver_capwap_data *drv, + struct nlattr *freq, struct nlattr *type) +{ + union wpa_event_data data; + int ht_enabled = 1; + int chan_offset = 0; + + wpa_printf(MSG_DEBUG, "capwap: Channel switch event"); + + if (!freq || !type) + return; + + switch (nla_get_u32(type)) { + case NL80211_CHAN_NO_HT: + ht_enabled = 0; + break; + case NL80211_CHAN_HT20: + break; + case NL80211_CHAN_HT40PLUS: + chan_offset = 1; + break; + case NL80211_CHAN_HT40MINUS: + chan_offset = -1; + break; + } + + data.ch_switch.freq = nla_get_u32(freq); + data.ch_switch.ht_enabled = ht_enabled; + data.ch_switch.ch_offset = chan_offset; + + wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data); +} + + +static void mlme_timeout_event(struct wpa_driver_capwap_data *drv, + enum nl80211_commands cmd, struct nlattr *addr) +{ + union wpa_event_data event; + enum wpa_event_type ev; + + if (nla_len(addr) != ETH_ALEN) + return; + + wpa_printf(MSG_DEBUG, "capwap: MLME event %d; timeout with " MACSTR, + cmd, MAC2STR((u8 *) nla_data(addr))); + + if (cmd == NL80211_CMD_AUTHENTICATE) + ev = EVENT_AUTH_TIMED_OUT; + else if (cmd == NL80211_CMD_ASSOCIATE) + ev = EVENT_ASSOC_TIMED_OUT; + else + return; + + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); + wpa_supplicant_event(drv->ctx, ev, &event); +} + + +static void mlme_event_mgmt(struct wpa_driver_capwap_data *drv, + struct nlattr *freq, struct nlattr *sig, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + u16 fc, stype; + int ssi_signal = 0; + + wpa_printf(MSG_DEBUG, "capwap: Frame event"); + mgmt = (const struct ieee80211_mgmt *) frame; + if (len < 24) { + wpa_printf(MSG_DEBUG, "capwap: Too short action frame"); + return; + } + + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + + if (sig) + ssi_signal = (s32) nla_get_u32(sig); + + os_memset(&event, 0, sizeof(event)); + if (freq) { + event.rx_action.freq = nla_get_u32(freq); + drv->last_mgmt_freq = event.rx_action.freq; + } + if (stype == WLAN_FC_STYPE_ACTION) { + event.rx_action.da = mgmt->da; + event.rx_action.sa = mgmt->sa; + event.rx_action.bssid = mgmt->bssid; + event.rx_action.category = mgmt->u.action.category; + event.rx_action.data = &mgmt->u.action.category + 1; + event.rx_action.len = frame + len - event.rx_action.data; + wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); + } else { + event.rx_mgmt.frame = frame; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.ssi_signal = ssi_signal; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + } +} + + +static void mlme_event_mgmt_tx_status(struct wpa_driver_capwap_data *drv, + struct nlattr *cookie, const u8 *frame, + size_t len, struct nlattr *ack) +{ + union wpa_event_data event; + const struct ieee80211_hdr *hdr; + u16 fc; + + wpa_printf(MSG_DEBUG, "capwap: Frame TX status event"); + if (!is_ap_interface(drv->nlmode)) { + u64 cookie_val; + + if (!cookie) + return; + + cookie_val = nla_get_u64(cookie); + wpa_printf(MSG_DEBUG, "capwap: Action TX status:" + " cookie=0%llx%s (ack=%d)", + (long long unsigned int) cookie_val, + cookie_val == drv->send_action_cookie ? + " (match)" : " (unknown)", ack != NULL); + if (cookie_val != drv->send_action_cookie) + return; + } + + hdr = (const struct ieee80211_hdr *) frame; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = frame; + event.tx_status.data_len = len; + event.tx_status.ack = ack != NULL; + wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); +} + + +static void mlme_event_deauth_disassoc(struct wpa_driver_capwap_data *drv, + enum wpa_event_type type, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + const u8 *bssid = NULL; + u16 reason_code = 0; + + if (type == EVENT_DEAUTH) + wpa_printf(MSG_DEBUG, "capwap: Deauthenticate event"); + else + wpa_printf(MSG_DEBUG, "capwap: Disassociate event"); + + mgmt = (const struct ieee80211_mgmt *) frame; + if (len >= 24) { + bssid = mgmt->bssid; + + if (drv->associated != 0 && + os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && + os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { + /* + * We have presumably received this deauth as a + * response to a clear_state_mismatch() outgoing + * deauth. Don't let it take us offline! + */ + wpa_printf(MSG_DEBUG, "capwap: Deauth received " + "from Unknown BSSID " MACSTR " -- ignoring", + MAC2STR(bssid)); + return; + } + } + + drv->associated = 0; + os_memset(&event, 0, sizeof(event)); + + /* Note: Same offset for Reason Code in both frame subtypes */ + if (len >= 24 + sizeof(mgmt->u.deauth)) + reason_code = le_to_host16(mgmt->u.deauth.reason_code); + + if (type == EVENT_DISASSOC) { + event.disassoc_info.locally_generated = + !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN); + event.disassoc_info.addr = bssid; + event.disassoc_info.reason_code = reason_code; + if (frame + len > mgmt->u.disassoc.variable) { + event.disassoc_info.ie = mgmt->u.disassoc.variable; + event.disassoc_info.ie_len = frame + len - + mgmt->u.disassoc.variable; + } + } else { + event.deauth_info.locally_generated = + !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN); + event.deauth_info.addr = bssid; + event.deauth_info.reason_code = reason_code; + if (frame + len > mgmt->u.deauth.variable) { + event.deauth_info.ie = mgmt->u.deauth.variable; + event.deauth_info.ie_len = frame + len - + mgmt->u.deauth.variable; + } + } + + wpa_supplicant_event(drv->ctx, type, &event); +} + + +static void mlme_event_unprot_disconnect(struct wpa_driver_capwap_data *drv, + enum wpa_event_type type, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + u16 reason_code = 0; + + if (type == EVENT_UNPROT_DEAUTH) + wpa_printf(MSG_DEBUG, "capwap: Unprot Deauthenticate event"); + else + wpa_printf(MSG_DEBUG, "capwap: Unprot Disassociate event"); + + if (len < 24) + return; + + mgmt = (const struct ieee80211_mgmt *) frame; + + os_memset(&event, 0, sizeof(event)); + /* Note: Same offset for Reason Code in both frame subtypes */ + if (len >= 24 + sizeof(mgmt->u.deauth)) + reason_code = le_to_host16(mgmt->u.deauth.reason_code); + + if (type == EVENT_UNPROT_DISASSOC) { + event.unprot_disassoc.sa = mgmt->sa; + event.unprot_disassoc.da = mgmt->da; + event.unprot_disassoc.reason_code = reason_code; + } else { + event.unprot_deauth.sa = mgmt->sa; + event.unprot_deauth.da = mgmt->da; + event.unprot_deauth.reason_code = reason_code; + } + + wpa_supplicant_event(drv->ctx, type, &event); +} + + +static void mlme_event(struct wpa_driver_capwap_data *drv, + enum nl80211_commands cmd, struct nlattr *frame, + struct nlattr *addr, struct nlattr *timed_out, + struct nlattr *freq, struct nlattr *ack, + struct nlattr *cookie, struct nlattr *sig) +{ + if (timed_out && addr) { + mlme_timeout_event(drv, cmd, addr); + return; + } + + if (frame == NULL) { + wpa_printf(MSG_DEBUG, "capwap: MLME event %d without frame " + "data", cmd); + return; + } + + wpa_printf(MSG_DEBUG, "capwap: MLME event %d", cmd); + wpa_hexdump(MSG_MSGDUMP, "capwap: MLME event frame", + nla_data(frame), nla_len(frame)); + + switch (cmd) { + case NL80211_CMD_AUTHENTICATE: + mlme_event_auth(drv, nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_ASSOCIATE: + mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_DEAUTHENTICATE: + mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, + nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_DISASSOCIATE: + mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, + nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_FRAME: + mlme_event_mgmt(drv, freq, sig, nla_data(frame), + nla_len(frame)); + break; + case NL80211_CMD_FRAME_TX_STATUS: + mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), + nla_len(frame), ack); + break; + case NL80211_CMD_UNPROT_DEAUTHENTICATE: + mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, + nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_UNPROT_DISASSOCIATE: + mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC, + nla_data(frame), nla_len(frame)); + break; + default: + break; + } +} + + +static void mlme_event_michael_mic_failure(struct i802_bss *bss, + struct nlattr *tb[]) +{ + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "capwap: MLME event Michael MIC failure"); + os_memset(&data, 0, sizeof(data)); + if (tb[NL80211_ATTR_MAC]) { + wpa_hexdump(MSG_DEBUG, "capwap: Source MAC address", + nla_data(tb[NL80211_ATTR_MAC]), + nla_len(tb[NL80211_ATTR_MAC])); + data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); + } + if (tb[NL80211_ATTR_KEY_SEQ]) { + wpa_hexdump(MSG_DEBUG, "capwap: TSC", + nla_data(tb[NL80211_ATTR_KEY_SEQ]), + nla_len(tb[NL80211_ATTR_KEY_SEQ])); + } + if (tb[NL80211_ATTR_KEY_TYPE]) { + enum nl80211_key_type key_type = + nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); + wpa_printf(MSG_DEBUG, "capwap: Key Type %d", key_type); + if (key_type == NL80211_KEYTYPE_PAIRWISE) + data.michael_mic_failure.unicast = 1; + } else + data.michael_mic_failure.unicast = 1; + + if (tb[NL80211_ATTR_KEY_IDX]) { + u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); + wpa_printf(MSG_DEBUG, "capwap: Key Id %d", key_id); + } + + wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); +} + + +static void mlme_event_join_ibss(struct wpa_driver_capwap_data *drv, + struct nlattr *tb[]) +{ + if (tb[NL80211_ATTR_MAC] == NULL) { + wpa_printf(MSG_DEBUG, "capwap: No address in IBSS joined " + "event"); + return; + } + os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + drv->associated = 1; + wpa_printf(MSG_DEBUG, "capwap: IBSS " MACSTR " joined", + MAC2STR(drv->bssid)); + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); +} + + +static void mlme_event_remain_on_channel(struct wpa_driver_capwap_data *drv, + int cancel_event, struct nlattr *tb[]) +{ + unsigned int freq, chan_type, duration; + union wpa_event_data data; + u64 cookie; + + if (tb[NL80211_ATTR_WIPHY_FREQ]) + freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + else + freq = 0; + + if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) + chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + else + chan_type = 0; + + if (tb[NL80211_ATTR_DURATION]) + duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); + else + duration = 0; + + if (tb[NL80211_ATTR_COOKIE]) + cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + else + cookie = 0; + + wpa_printf(MSG_DEBUG, "capwap: Remain-on-channel event (cancel=%d " + "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", + cancel_event, freq, chan_type, duration, + (long long unsigned int) cookie, + cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); + + if (cookie != drv->remain_on_chan_cookie) + return; /* not for us */ + + if (cancel_event) + drv->pending_remain_on_chan = 0; + + os_memset(&data, 0, sizeof(data)); + data.remain_on_channel.freq = freq; + data.remain_on_channel.duration = duration; + wpa_supplicant_event(drv->ctx, cancel_event ? + EVENT_CANCEL_REMAIN_ON_CHANNEL : + EVENT_REMAIN_ON_CHANNEL, &data); +} + + +static void send_scan_event(struct wpa_driver_capwap_data *drv, int aborted, + struct nlattr *tb[]) +{ + union wpa_event_data event; + struct nlattr *nl; + int rem; + struct scan_info *info; +#define MAX_REPORT_FREQS 50 + int freqs[MAX_REPORT_FREQS]; + int num_freqs = 0; + + if (drv->scan_for_auth) { + drv->scan_for_auth = 0; + wpa_printf(MSG_DEBUG, "capwap: Scan results for missing " + "cfg80211 BSS entry"); + wpa_driver_capwap_authenticate_retry(drv); + return; + } + + os_memset(&event, 0, sizeof(event)); + info = &event.scan_info; + info->aborted = aborted; + + if (tb[NL80211_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { + struct wpa_driver_scan_ssid *s = + &info->ssids[info->num_ssids]; + s->ssid = nla_data(nl); + s->ssid_len = nla_len(nl); + info->num_ssids++; + if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) + break; + } + } + if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) + { + freqs[num_freqs] = nla_get_u32(nl); + num_freqs++; + if (num_freqs == MAX_REPORT_FREQS - 1) + break; + } + info->freqs = freqs; + info->num_freqs = num_freqs; + } + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); +} + + +static int get_link_signal(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + }; + struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; + static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + }; + struct wpa_signal_info *sig_change = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_STA_INFO] || + nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, + tb[NL80211_ATTR_STA_INFO], policy)) + return NL_SKIP; + if (!sinfo[NL80211_STA_INFO_SIGNAL]) + return NL_SKIP; + + sig_change->current_signal = + (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); + + if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { + if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, + sinfo[NL80211_STA_INFO_TX_BITRATE], + rate_policy)) { + sig_change->current_txrate = 0; + } else { + if (rinfo[NL80211_RATE_INFO_BITRATE]) { + sig_change->current_txrate = + nla_get_u16(rinfo[ + NL80211_RATE_INFO_BITRATE]) * 100; + } + } + } + + return NL_SKIP; +} + + +static int capwap_get_link_signal(struct wpa_driver_capwap_data *drv, + struct wpa_signal_info *sig) +{ + struct nl_msg *msg; + + sig->current_signal = -9999; + sig->current_txrate = 0; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); + + return send_and_recv_msgs(drv, msg, get_link_signal, sig); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int get_link_noise(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; + static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, + }; + struct wpa_signal_info *sig_change = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_SURVEY_INFO]) { + wpa_printf(MSG_DEBUG, "capwap: survey data missing!"); + return NL_SKIP; + } + + if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, + tb[NL80211_ATTR_SURVEY_INFO], + survey_policy)) { + wpa_printf(MSG_DEBUG, "capwap: failed to parse nested " + "attributes!"); + return NL_SKIP; + } + + if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) + return NL_SKIP; + + if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != + sig_change->frequency) + return NL_SKIP; + + if (!sinfo[NL80211_SURVEY_INFO_NOISE]) + return NL_SKIP; + + sig_change->current_noise = + (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); + + return NL_SKIP; +} + + +static int capwap_get_link_noise(struct wpa_driver_capwap_data *drv, + struct wpa_signal_info *sig_change) +{ + struct nl_msg *msg; + + sig_change->current_noise = 9999; + sig_change->frequency = drv->assoc_freq; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + return send_and_recv_msgs(drv, msg, get_link_noise, sig_change); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; + static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, + }; + struct wpa_scan_results *scan_results = arg; + struct wpa_scan_res *scan_res; + size_t i; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_SURVEY_INFO]) { + wpa_printf(MSG_DEBUG, "capwap: Survey data missing"); + return NL_SKIP; + } + + if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, + tb[NL80211_ATTR_SURVEY_INFO], + survey_policy)) { + wpa_printf(MSG_DEBUG, "capwap: Failed to parse nested " + "attributes"); + return NL_SKIP; + } + + if (!sinfo[NL80211_SURVEY_INFO_NOISE]) + return NL_SKIP; + + if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) + return NL_SKIP; + + for (i = 0; i < scan_results->num; ++i) { + scan_res = scan_results->res[i]; + if (!scan_res) + continue; + if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != + scan_res->freq) + continue; + if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID)) + continue; + scan_res->noise = (s8) + nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); + scan_res->flags &= ~WPA_SCAN_NOISE_INVALID; + } + + return NL_SKIP; +} + + +static int capwap_get_noise_for_scan_results( + struct wpa_driver_capwap_data *drv, + struct wpa_scan_results *scan_res) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, + scan_res); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static void capwap_cqm_event(struct wpa_driver_capwap_data *drv, + struct nlattr *tb[]) +{ + static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { + [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, + [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, + }; + struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; + enum nl80211_cqm_rssi_threshold_event event; + union wpa_event_data ed; + struct wpa_signal_info sig; + int res; + + if (tb[NL80211_ATTR_CQM] == NULL || + nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], + cqm_policy)) { + wpa_printf(MSG_DEBUG, "capwap: Ignore invalid CQM event"); + return; + } + + os_memset(&ed, 0, sizeof(ed)); + + if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { + if (!tb[NL80211_ATTR_MAC]) + return; + os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), + ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); + return; + } + + if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) + return; + event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); + + if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { + wpa_printf(MSG_DEBUG, "capwap: Connection quality monitor " + "event: RSSI high"); + ed.signal_change.above_threshold = 1; + } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { + wpa_printf(MSG_DEBUG, "capwap: Connection quality monitor " + "event: RSSI low"); + ed.signal_change.above_threshold = 0; + } else + return; + + res = capwap_get_link_signal(drv, &sig); + if (res == 0) { + ed.signal_change.current_signal = sig.current_signal; + ed.signal_change.current_txrate = sig.current_txrate; + wpa_printf(MSG_DEBUG, "capwap: Signal: %d dBm txrate: %d", + sig.current_signal, sig.current_txrate); + } + + res = capwap_get_link_noise(drv, &sig); + if (res == 0) { + ed.signal_change.current_noise = sig.current_noise; + wpa_printf(MSG_DEBUG, "capwap: Noise: %d dBm", + sig.current_noise); + } + + wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); +} + + +static void capwap_new_station_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + u8 *addr; + union wpa_event_data data; + + if (tb[NL80211_ATTR_MAC] == NULL) + return; + addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "capwap: New station " MACSTR, MAC2STR(addr)); + + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { + u8 *ies = NULL; + size_t ies_len = 0; + if (tb[NL80211_ATTR_IE]) { + ies = nla_data(tb[NL80211_ATTR_IE]); + ies_len = nla_len(tb[NL80211_ATTR_IE]); + } + wpa_hexdump(MSG_DEBUG, "capwap: Assoc Req IEs", ies, ies_len); + drv_event_assoc(drv->ctx, addr, ies, ies_len, 0); + return; + } + + if (drv->nlmode != NL80211_IFTYPE_ADHOC) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); +} + + +static void capwap_del_station_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + u8 *addr; + union wpa_event_data data; + + if (tb[NL80211_ATTR_MAC] == NULL) + return; + addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "capwap: Delete station " MACSTR, + MAC2STR(addr)); + + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { + drv_event_disassoc(drv->ctx, addr); + return; + } + + if (drv->nlmode != NL80211_IFTYPE_ADHOC) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); +} + + +static void capwap_rekey_offload_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; + static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { + [NL80211_REKEY_DATA_KEK] = { + .minlen = NL80211_KEK_LEN, + .maxlen = NL80211_KEK_LEN, + }, + [NL80211_REKEY_DATA_KCK] = { + .minlen = NL80211_KCK_LEN, + .maxlen = NL80211_KCK_LEN, + }, + [NL80211_REKEY_DATA_REPLAY_CTR] = { + .minlen = NL80211_REPLAY_CTR_LEN, + .maxlen = NL80211_REPLAY_CTR_LEN, + }, + }; + union wpa_event_data data; + + if (!tb[NL80211_ATTR_MAC]) + return; + if (!tb[NL80211_ATTR_REKEY_DATA]) + return; + if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, + tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) + return; + if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) + return; + + os_memset(&data, 0, sizeof(data)); + data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "capwap: Rekey offload event for BSSID " MACSTR, + MAC2STR(data.driver_gtk_rekey.bssid)); + data.driver_gtk_rekey.replay_ctr = + nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); + wpa_hexdump(MSG_DEBUG, "capwap: Rekey offload - Replay Counter", + data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); +} + + +static void capwap_pmksa_candidate_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; + static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { + [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, + [NL80211_PMKSA_CANDIDATE_BSSID] = { + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN, + }, + [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, + }; + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "capwap: PMKSA candidate event"); + + if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) + return; + if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, + tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) + return; + if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || + !cand[NL80211_PMKSA_CANDIDATE_BSSID]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.pmkid_candidate.bssid, + nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); + data.pmkid_candidate.index = + nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); + data.pmkid_candidate.preauth = + cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; + wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); +} + + +static void capwap_client_probe_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "capwap: Probe client event"); + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.client_poll.addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); +} + + +static void capwap_tdls_oper_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "capwap: TDLS operation event"); + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) { + case NL80211_TDLS_SETUP: + wpa_printf(MSG_DEBUG, "capwap: TDLS setup request for peer " + MACSTR, MAC2STR(data.tdls.peer)); + data.tdls.oper = TDLS_REQUEST_SETUP; + break; + case NL80211_TDLS_TEARDOWN: + wpa_printf(MSG_DEBUG, "capwap: TDLS teardown request for peer " + MACSTR, MAC2STR(data.tdls.peer)); + data.tdls.oper = TDLS_REQUEST_TEARDOWN; + break; + default: + wpa_printf(MSG_DEBUG, "capwap: Unsupported TDLS operatione " + "event"); + return; + } + if (tb[NL80211_ATTR_REASON_CODE]) { + data.tdls.reason_code = + nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); + } + + wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data); +} + + +static void capwap_connect_failed_event(struct wpa_driver_capwap_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + u32 reason; + + wpa_printf(MSG_DEBUG, "capwap: Connect failed event"); + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.connect_failed_reason.addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]); + switch (reason) { + case NL80211_CONN_FAIL_MAX_CLIENTS: + wpa_printf(MSG_DEBUG, "capwap: Max client reached"); + data.connect_failed_reason.code = MAX_CLIENT_REACHED; + break; + case NL80211_CONN_FAIL_BLOCKED_CLIENT: + wpa_printf(MSG_DEBUG, "capwap: Blocked client " MACSTR + " tried to connect", + MAC2STR(data.connect_failed_reason.addr)); + data.connect_failed_reason.code = BLOCKED_CLIENT; + break; + default: + wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason " + "%u", reason); + return; + } + + wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data); +} + + +static void capwap_spurious_frame(struct i802_bss *bss, struct nlattr **tb, + int wds) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + union wpa_event_data event; + + if (!tb[NL80211_ATTR_MAC]) + return; + + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.bssid = bss->addr; + event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]); + event.rx_from_unknown.wds = wds; + + wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); +} + + +static void do_process_drv_event(struct i802_bss *bss, int cmd, + struct nlattr **tb) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && + (cmd == NL80211_CMD_NEW_SCAN_RESULTS || + cmd == NL80211_CMD_SCAN_ABORTED)) { + wpa_driver_capwap_set_mode(&drv->first_bss, + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; + } + + switch (cmd) { + case NL80211_CMD_TRIGGER_SCAN: + wpa_printf(MSG_DEBUG, "capwap: Scan trigger"); + break; + case NL80211_CMD_START_SCHED_SCAN: + wpa_printf(MSG_DEBUG, "capwap: Sched scan started"); + break; + case NL80211_CMD_SCHED_SCAN_STOPPED: + wpa_printf(MSG_DEBUG, "capwap: Sched scan stopped"); + wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); + break; + case NL80211_CMD_NEW_SCAN_RESULTS: + wpa_printf(MSG_DEBUG, "capwap: New scan results available"); + drv->scan_complete_events = 1; + eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, + drv->ctx); + send_scan_event(drv, 0, tb); + break; + case NL80211_CMD_SCHED_SCAN_RESULTS: + wpa_printf(MSG_DEBUG, + "capwap: New sched scan results available"); + send_scan_event(drv, 0, tb); + break; + case NL80211_CMD_SCAN_ABORTED: + wpa_printf(MSG_DEBUG, "capwap: Scan aborted"); + /* + * Need to indicate that scan results are available in order + * not to make wpa_supplicant stop its scanning. + */ + eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, + drv->ctx); + send_scan_event(drv, 1, tb); + break; + case NL80211_CMD_AUTHENTICATE: + case NL80211_CMD_ASSOCIATE: + case NL80211_CMD_DEAUTHENTICATE: + case NL80211_CMD_DISASSOCIATE: + case NL80211_CMD_FRAME_TX_STATUS: + case NL80211_CMD_UNPROT_DEAUTHENTICATE: + case NL80211_CMD_UNPROT_DISASSOCIATE: + mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE], + tb[NL80211_ATTR_RX_SIGNAL_DBM]); + break; + case NL80211_CMD_CONNECT: + case NL80211_CMD_ROAM: + mlme_event_connect(drv, cmd, + tb[NL80211_ATTR_STATUS_CODE], + tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_REQ_IE], + tb[NL80211_ATTR_RESP_IE]); + break; + case NL80211_CMD_CH_SWITCH_NOTIFY: + mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ], + tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + break; + case NL80211_CMD_DISCONNECT: + mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], + tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_DISCONNECTED_BY_AP]); + break; + case NL80211_CMD_MICHAEL_MIC_FAILURE: + mlme_event_michael_mic_failure(bss, tb); + break; + case NL80211_CMD_JOIN_IBSS: + mlme_event_join_ibss(drv, tb); + break; + case NL80211_CMD_REMAIN_ON_CHANNEL: + mlme_event_remain_on_channel(drv, 0, tb); + break; + case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: + mlme_event_remain_on_channel(drv, 1, tb); + break; + case NL80211_CMD_NOTIFY_CQM: + capwap_cqm_event(drv, tb); + break; + case NL80211_CMD_REG_CHANGE: + wpa_printf(MSG_DEBUG, "capwap: Regulatory domain change"); + wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, + NULL); + break; + case NL80211_CMD_REG_BEACON_HINT: + wpa_printf(MSG_DEBUG, "capwap: Regulatory beacon hint"); + wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, + NULL); + break; + case NL80211_CMD_NEW_STATION: + capwap_new_station_event(drv, tb); + break; + case NL80211_CMD_DEL_STATION: + capwap_del_station_event(drv, tb); + break; + case NL80211_CMD_SET_REKEY_OFFLOAD: + capwap_rekey_offload_event(drv, tb); + break; + case NL80211_CMD_PMKSA_CANDIDATE: + capwap_pmksa_candidate_event(drv, tb); + break; + case NL80211_CMD_PROBE_CLIENT: + capwap_client_probe_event(drv, tb); + break; + case NL80211_CMD_TDLS_OPER: + capwap_tdls_oper_event(drv, tb); + break; + case NL80211_CMD_CONN_FAILED: + capwap_connect_failed_event(drv, tb); + break; + default: + wpa_printf(MSG_DEBUG, "capwap: Ignored unknown event " + "(cmd=%d)", cmd); + break; + } +} + + +static int process_drv_event(struct nl_msg *msg, void *arg) +{ + struct wpa_driver_capwap_data *drv = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct i802_bss *bss; + int ifidx = -1; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) + ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + + for (bss = &drv->first_bss; bss; bss = bss->next) { + if (ifidx == -1 || ifidx == bss->ifindex) { + do_process_drv_event(bss, gnlh->cmd, tb); + return NL_SKIP; + } + } + + wpa_printf(MSG_DEBUG, "capwap: Ignored event (cmd=%d) for foreign " + "interface (ifindex %d)", gnlh->cmd, ifidx); + + return NL_SKIP; +} + + +static int process_global_event(struct nl_msg *msg, void *arg) +{ + struct capwap_global *global = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct wpa_driver_capwap_data *drv, *tmp; + int ifidx = -1; + struct i802_bss *bss; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) + ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + + dl_list_for_each_safe(drv, tmp, &global->interfaces, + struct wpa_driver_capwap_data, list) { + for (bss = &drv->first_bss; bss; bss = bss->next) { + if (ifidx == -1 || ifidx == bss->ifindex) { + do_process_drv_event(bss, gnlh->cmd, tb); + return NL_SKIP; + } + } + } + + return NL_SKIP; +} + + +static int process_bss_event(struct nl_msg *msg, void *arg) +{ + struct i802_bss *bss = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: + case NL80211_CMD_FRAME_TX_STATUS: + mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE], + tb[NL80211_ATTR_RX_SIGNAL_DBM]); + break; + case NL80211_CMD_UNEXPECTED_FRAME: + capwap_spurious_frame(bss, tb, 0); + break; + case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: + capwap_spurious_frame(bss, tb, 1); + break; + default: + wpa_printf(MSG_DEBUG, "capwap: Ignored unknown event " + "(cmd=%d)", gnlh->cmd); + break; + } + + return NL_SKIP; +} + + +static void wpa_driver_capwap_event_receive(int sock, void *eloop_ctx, + void *handle) +{ + wpa_printf(MSG_DEBUG, "wpa_driver_capwap_event_receive"); + struct nl_cb *cb = eloop_ctx; + + wpa_printf(MSG_DEBUG, "capwap: Event message available"); + + nl_recvmsgs(handle, cb); +} + + +/** + * wpa_driver_capwap_set_country - ask capwap to set the regulatory domain + * @priv: driver_capwap private data + * @alpha2_arg: country to which to switch to + * Returns: 0 on success, -1 on failure + * + * This asks capwap to set the regulatory domain for given + * country ISO / IEC alpha2. + */ +static int wpa_driver_capwap_set_country(void *priv, const char *alpha2_arg) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + char alpha2[3]; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + alpha2[0] = alpha2_arg[0]; + alpha2[1] = alpha2_arg[1]; + alpha2[2] = '\0'; + + capwap_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG); + + NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2); + if (send_and_recv_msgs(drv, msg, NULL, NULL)) + return -EINVAL; + return 0; +nla_put_failure: + nlmsg_free(msg); + return -EINVAL; +} + + +struct wiphy_info_data { + struct wpa_driver_capa *capa; + + unsigned int error:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int monitor_supported:1; +}; + + +static unsigned int probe_resp_offload_support(int supp_protocols) +{ + unsigned int prot = 0; + + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P; + if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U) + prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING; + + return prot; +} + + +static int wiphy_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wiphy_info_data *info = arg; + int p2p_go_supported = 0, p2p_client_supported = 0; + int p2p_concurrent = 0, p2p_multichan_concurrent = 0; + int auth_supported = 0, connect_supported = 0; + struct wpa_driver_capa *capa = info->capa; + static struct nla_policy + iface_combination_policy[NUM_NL80211_IFACE_COMB] = { + [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, + [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, + [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, + [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, + }, + iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { + [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, + [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, + }; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) + capa->max_scan_ssids = + nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); + + if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) + capa->max_sched_scan_ssids = + nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); + + if (tb[NL80211_ATTR_MAX_MATCH_SETS]) + capa->max_match_sets = + nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); + + if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { + struct nlattr *nl_mode; + int i; + nla_for_each_nested(nl_mode, + tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { + switch (nla_type(nl_mode)) { + case NL80211_IFTYPE_AP: + capa->flags |= WPA_DRIVER_FLAGS_AP; + break; + case NL80211_IFTYPE_P2P_GO: + p2p_go_supported = 1; + break; + case NL80211_IFTYPE_P2P_CLIENT: + p2p_client_supported = 1; + break; + case NL80211_IFTYPE_MONITOR: + info->monitor_supported = 1; + break; + } + } + } + + if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) { + struct nlattr *nl_combi; + int rem_combi; + + nla_for_each_nested(nl_combi, + tb[NL80211_ATTR_INTERFACE_COMBINATIONS], + rem_combi) { + struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; + struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; + struct nlattr *nl_limit, *nl_mode; + int err, rem_limit, rem_mode; + int combination_has_p2p = 0, combination_has_mgd = 0; + + err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, + nl_combi, + iface_combination_policy); + if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || + !tb_comb[NL80211_IFACE_COMB_MAXNUM] || + !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) + goto broken_combination; + + nla_for_each_nested(nl_limit, + tb_comb[NL80211_IFACE_COMB_LIMITS], + rem_limit) { + err = nla_parse_nested(tb_limit, + MAX_NL80211_IFACE_LIMIT, + nl_limit, + iface_limit_policy); + if (err || + !tb_limit[NL80211_IFACE_LIMIT_TYPES]) + goto broken_combination; + + nla_for_each_nested( + nl_mode, + tb_limit[NL80211_IFACE_LIMIT_TYPES], + rem_mode) { + int ift = nla_type(nl_mode); + if (ift == NL80211_IFTYPE_P2P_GO || + ift == NL80211_IFTYPE_P2P_CLIENT) + combination_has_p2p = 1; + if (ift == NL80211_IFTYPE_STATION) + combination_has_mgd = 1; + } + if (combination_has_p2p && combination_has_mgd) + break; + } + + if (combination_has_p2p && combination_has_mgd) { + p2p_concurrent = 1; + if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1) + p2p_multichan_concurrent = 1; + break; + } + +broken_combination: + ; + } + } + + if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { + struct nlattr *nl_cmd; + int i; + + nla_for_each_nested(nl_cmd, + tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { + switch (nla_get_u32(nl_cmd)) { + case NL80211_CMD_AUTHENTICATE: + auth_supported = 1; + break; + case NL80211_CMD_CONNECT: + connect_supported = 1; + break; + case NL80211_CMD_START_SCHED_SCAN: + capa->sched_scan_supported = 1; + break; + case NL80211_CMD_PROBE_CLIENT: + info->poll_command_supported = 1; + break; + } + } + } + + if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { + wpa_printf(MSG_DEBUG, "capwap: Using driver-based " + "off-channel TX"); + capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; + } + + if (tb[NL80211_ATTR_ROAM_SUPPORT]) { + wpa_printf(MSG_DEBUG, "capwap: Using driver-based roaming"); + capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; + } + + /* default to 5000 since early versions of mac80211 don't set it */ + capa->max_remain_on_chan = 5000; + + if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD]) + capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD; + + if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]) + capa->max_remain_on_chan = + nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); + + if (auth_supported) + capa->flags |= WPA_DRIVER_FLAGS_SME; + else if (!connect_supported) { + wpa_printf(MSG_INFO, "capwap: Driver does not support " + "authentication/association or connect commands"); + info->error = 1; + } + + if (p2p_go_supported && p2p_client_supported) + capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; + if (p2p_concurrent) { + wpa_printf(MSG_DEBUG, "capwap: Use separate P2P group " + "interface (driver advertised support)"); + capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; + capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; + + if (p2p_multichan_concurrent) { + wpa_printf(MSG_DEBUG, "capwap: Enable multi-channel " + "concurrent (driver advertised support)"); + capa->flags |= + WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT; + } + } + + if (tb[NL80211_ATTR_TDLS_SUPPORT]) { + wpa_printf(MSG_DEBUG, "capwap: TDLS supported"); + capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; + + if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) { + wpa_printf(MSG_DEBUG, "capwap: TDLS external setup"); + capa->flags |= + WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; + } + } + + if (tb[NL80211_ATTR_DEVICE_AP_SME]) + info->device_ap_sme = 1; + + if (tb[NL80211_ATTR_FEATURE_FLAGS]) { + u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]); + + if (flags & NL80211_FEATURE_SK_TX_STATUS) + info->data_tx_status = 1; + + if (flags & NL80211_FEATURE_INACTIVITY_TIMER) + capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER; + + if (flags & NL80211_FEATURE_SAE) + capa->flags |= WPA_DRIVER_FLAGS_SAE; + + if (flags & NL80211_FEATURE_NEED_OBSS_SCAN) + capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN; + } + + if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) { + int protocols = + nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]); + wpa_printf(MSG_DEBUG, "capwap: Supports Probe Response " + "offload in AP mode"); + capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD; + capa->probe_resp_offloads = + probe_resp_offload_support(protocols); + } + + return NL_SKIP; +} + + +static int wpa_driver_capwap_get_info(struct wpa_driver_capwap_data *drv, + struct wiphy_info_data *info) +{ + return 0; +} + + +static int wpa_driver_capwap_capa(struct wpa_driver_capwap_data *drv) +{ + wpa_printf(MSG_DEBUG, " 4.wpa_driver_capwap_capa"); + struct wiphy_info_data info; + if (wpa_driver_capwap_get_info(drv, &info)) + return -1; + + drv->has_capability = 1; + /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ + drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; + drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | + WPA_DRIVER_CAPA_ENC_WEP104 | + WPA_DRIVER_CAPA_ENC_TKIP | + WPA_DRIVER_CAPA_ENC_CCMP; + drv->capa.auth = WPA_DRIVER_AUTH_OPEN | + WPA_DRIVER_AUTH_SHARED | + WPA_DRIVER_AUTH_LEAP; + + drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; + drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; + drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + + + if (!info.device_ap_sme) { + drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; + + /* + * No AP SME is currently assumed to also indicate no AP MLME + * in the driver/firmware. + */ + drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME; + } + + drv->device_ap_sme = info.device_ap_sme; + drv->poll_command_supported = info.poll_command_supported; + drv->data_tx_status = info.data_tx_status; + + /* + * If poll command and tx status are supported, mac80211 is new enough + * to have everything we need to not need monitor interfaces. + */ + drv->use_monitor = !info.poll_command_supported || !info.data_tx_status; + + if (drv->device_ap_sme && drv->use_monitor) { + /* + * Non-mac80211 drivers may not support monitor interface. + * Make sure we do not get stuck with incorrect capability here + * by explicitly testing this. + */ + if (!info.monitor_supported) { + wpa_printf(MSG_DEBUG, "capwap: Disable use_monitor " + "with device_ap_sme since no monitor mode " + "support detected"); + drv->use_monitor = 0; + } + } + + /* + * If we aren't going to use monitor interfaces, but the + * driver doesn't support data TX status, we won't get TX + * status for EAPOL frames. + */ + if (!drv->use_monitor && !info.data_tx_status) + drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + + return 0; +} + + +#ifdef ANDROID +static int android_genl_ctrl_resolve(struct nl_handle *handle, + const char *name) +{ + /* + * Android ICS has very minimal genl_ctrl_resolve() implementation, so + * need to work around that. + */ + struct nl_cache *cache = NULL; + struct genl_family *capwap = NULL; + int id = -1; + + if (genl_ctrl_alloc_cache(handle, &cache) < 0) { + wpa_printf(MSG_ERROR, "capwap: Failed to allocate generic " + "netlink cache"); + goto fail; + } + + capwap = genl_ctrl_search_by_name(cache, name); + if (capwap == NULL) + goto fail; + + id = genl_family_get_id(capwap); + +fail: + if (capwap) + genl_family_put(capwap); + if (cache) + nl_cache_free(cache); + + return id; +} +#define genl_ctrl_resolve android_genl_ctrl_resolve +#endif /* ANDROID */ + + +static int wpa_driver_capwap_init_nl_global(struct capwap_global *global) +{ + wpa_printf(MSG_DEBUG, " 2.wpa_driver_capwap_init_nl_global\n"); + int ret; + global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (global->nl_cb == NULL) { + wpa_printf(MSG_ERROR, "capwap: Failed to allocate netlink " + "callbacks"); + return -1; + } + + global->nl = nl_create_handle(global->nl_cb, "nl"); + global->nl_cache = nl_create_cache(global->nl); + if (global->nl == NULL) + goto err; + + global->capwap = genl_ctrl_search_by_name(global->nl_cache, "nl80211"); + if (global->capwap == NULL) { + wpa_printf(MSG_ERROR, "capwap: 'capwap' generic netlink not " + "found"); + goto err; + } + + global->nl_event = nl_create_handle(global->nl_cb, "event"); + global->nl_event_cache = nl_create_cache(global->nl_event); + if (global->nl_event == NULL) + goto err; + + ret = nl_get_multicast_id(global, "nl80211", "scan"); + if (ret >= 0) + ret = nl_socket_add_membership(global->nl_event, ret); + if (ret < 0) { + wpa_printf(MSG_ERROR, "capwap: Could not add multicast " + "membership for scan events: %d (%s)", + ret, strerror(-ret)); + goto err; + } + + ret = nl_get_multicast_id(global, "nl80211", "mlme"); + if (ret >= 0) + ret = nl_socket_add_membership(global->nl_event, ret); + if (ret < 0) { + wpa_printf(MSG_ERROR, "capwap: Could not add multicast " + "membership for mlme events: %d (%s)", + ret, strerror(-ret)); + goto err; + } + + ret = nl_get_multicast_id(global, "nl80211", "regulatory"); + if (ret >= 0) + ret = nl_socket_add_membership(global->nl_event, ret); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "capwap: Could not add multicast " + "membership for regulatory events: %d (%s)", + ret, strerror(-ret)); + /* Continue without regulatory events */ + } + + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_global_event, global); + + eloop_register_read_sock(nl_socket_get_fd(global->nl_event), + wpa_driver_capwap_event_receive, + global->nl_cb, global->nl_event); + + return 0; + +err: + nl_destroy_cache(&global->nl_event_cache); + nl_destroy_cache(&global->nl_cache); + nl_destroy_handles(&global->nl_event); + nl_destroy_handles(&global->nl); + nl_cb_put(global->nl_cb); + global->nl_cb = NULL; + return -1; +} + + +static int wpa_driver_capwap_init_nl(struct wpa_driver_capwap_data *drv) +{ + return 0; +} + +#ifdef CONFIG_RFKILL +static void wpa_driver_capwap_rfkill_blocked(void *ctx) +{ + wpa_printf(MSG_DEBUG, "capwap: RFKILL blocked"); + /* + * This may be for any interface; use ifdown event to disable + * interface. + */ +} + + +static void wpa_driver_capwap_rfkill_unblocked(void *ctx) +{ + struct wpa_driver_capwap_data *drv = ctx; + wpa_printf(MSG_DEBUG, "capwap: RFKILL unblocked"); + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, + drv->first_bss.ifname, 1)) { + wpa_printf(MSG_DEBUG, "capwap: Could not set interface UP " + "after rfkill unblock"); + return; + } + /* rtnetlink ifup handler will report interface as enabled */ +} +#endif /* CONFIG_RFKILL */ + + +static void capwap_get_phy_name(struct wpa_driver_capwap_data *drv) +{ + return; +} + +static void wpa_driver_capwap_handle_eapol_tx_status(int sock, + void *eloop_ctx, + void *handle) +{ + struct wpa_driver_capwap_data *drv = eloop_ctx; + u8 data[2048]; + struct msghdr msg; + struct iovec entry; + u8 control[512]; + struct cmsghdr *cmsg; + int res, found_ee = 0, found_wifi = 0, acked = 0; + union wpa_event_data event; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &entry; + msg.msg_iovlen = 1; + entry.iov_base = data; + entry.iov_len = sizeof(data); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + res = recvmsg(sock, &msg, MSG_ERRQUEUE); + /* if error or not fitting 802.3 header, return */ + if (res < 14) + return; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_WIFI_STATUS) { + int *ack; + + found_wifi = 1; + ack = (void *)CMSG_DATA(cmsg); + acked = *ack; + } + + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_TX_TIMESTAMP) { + struct sock_extended_err *err = + (struct sock_extended_err *)CMSG_DATA(cmsg); + + if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS) + found_ee = 1; + } + } + + if (!found_ee || !found_wifi) + return; + + memset(&event, 0, sizeof(event)); + event.eapol_tx_status.dst = data; + event.eapol_tx_status.data = data + 14; + event.eapol_tx_status.data_len = res - 14; + event.eapol_tx_status.ack = acked; + wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event); +} + + +static int capwap_init_bss(struct i802_bss *bss) +{ + bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!bss->nl_cb) + return -1; + + nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, + no_seq_check, NULL); + nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, + process_bss_event, bss); + + return 0; +} + + +static void capwap_destroy_bss(struct i802_bss *bss) +{ + nl_cb_put(bss->nl_cb); + bss->nl_cb = NULL; +} + + +/** + * wpa_driver_capwap_init - Initialize capwap driver interface + * @ctx: context to be used when calling wpa_supplicant functions, + * e.g., wpa_supplicant_event() + * @ifname: interface name, e.g., wlan0 + * @global_priv: private driver global data from global_init() + * Returns: Pointer to private data, %NULL on failure + */ +static void * wpa_driver_capwap_init(void *ctx, const char *ifname, + void *global_priv) +{ + wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_init\n"); + struct wpa_driver_capwap_data *drv; +#ifdef CONFIG_RFKILL + struct rfkill_config *rcfg; +#endif + struct i802_bss *bss; + + if (global_priv == NULL) + return NULL; + drv = os_zalloc(sizeof(*drv)); + if (drv == NULL) + return NULL; + drv->global = global_priv; + drv->ctx = ctx; + bss = &drv->first_bss; + bss->drv = drv; + bss->ctx = ctx; + + os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); + drv->monitor_ifidx = -1; + drv->monitor_sock = -1; + drv->eapol_tx_sock = -1; + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; + drv->nlmode = NL80211_IFTYPE_STATION; + +#ifdef HOSTAPD + drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); + drv->if_indices = drv->default_if_indices; +#endif + + if (wpa_driver_capwap_init_nl(drv)) { + os_free(drv); + return NULL; + } + + if (capwap_init_bss(bss)) + goto failed; + + capwap_get_phy_name(drv); + +#ifdef CONFIG_RFKILL + rcfg = os_zalloc(sizeof(*rcfg)); + if (rcfg == NULL) + goto failed; + rcfg->ctx = drv; + os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); + rcfg->blocked_cb = wpa_driver_capwap_rfkill_blocked; + rcfg->unblocked_cb = wpa_driver_capwap_rfkill_unblocked; + drv->rfkill = rfkill_init(rcfg); + if (drv->rfkill == NULL) { + wpa_printf(MSG_DEBUG, "capwap: RFKILL status not available"); + os_free(rcfg); + } +#endif /* CONFIG_RFKILL */ + + if (wpa_driver_capwap_finish_drv_init(drv)) + goto failed; + + drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0); + if (drv->eapol_tx_sock < 0) + goto failed; + + if (drv->data_tx_status) { + int enabled = 1; + + if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS, + &enabled, sizeof(enabled)) < 0) { + wpa_printf(MSG_DEBUG, + "capwap: wifi status sockopt failed\n"); + drv->data_tx_status = 0; + if (!drv->use_monitor) + drv->capa.flags &= + ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; + } else { + eloop_register_read_sock(drv->eapol_tx_sock, + wpa_driver_capwap_handle_eapol_tx_status, + drv, NULL); + } + } + + if (drv->global) { + dl_list_add(&drv->global->interfaces, &drv->list); + drv->in_interface_list = 1; + } + + return bss; + +failed: + wpa_driver_capwap_deinit(bss); + return NULL; +} + + +static int capwap_register_frame(struct i802_bss *bss, + struct nl_handle *nl_handle, + u16 type, const u8 *match, size_t match_len) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "capwap: Register frame type=0x%x nl_handle=%p", + type, nl_handle); + wpa_hexdump(MSG_DEBUG, "capwap: Register frame match", + match, match_len); + + capwap_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); + NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); + + ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Register frame command " + "failed (type=%u): ret=%d (%s)", + type, ret, strerror(-ret)); + wpa_hexdump(MSG_DEBUG, "capwap: Register frame match", + match, match_len); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int capwap_alloc_mgmt_handle(struct i802_bss *bss) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + + if (bss->nl_mgmt) { + wpa_printf(MSG_DEBUG, "capwap: Mgmt reporting " + "already on! (nl_mgmt=%p)", bss->nl_mgmt); + return -1; + } + + bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt"); + bss->nl_mgmt_cache = nl_create_cache(bss->nl_mgmt); + if (bss->nl_mgmt == NULL) + return -1; + + eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt), + wpa_driver_capwap_event_receive, bss->nl_cb, + bss->nl_mgmt); + + return 0; +} + + +static int capwap_register_action_frame(struct i802_bss *bss, + const u8 *match, size_t match_len) +{ + u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); + return capwap_register_frame(bss, bss->nl_mgmt, + type, match, match_len); +} + + +static int capwap_mgmt_subscribe_non_ap(struct i802_bss *bss) +{ + return 0; +} + + +static int capwap_register_spurious_class3(struct i802_bss *bss) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Register spurious class3 " + "failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int capwap_mgmt_subscribe_ap(struct i802_bss *bss) +{ + static const int stypes[] = { + WLAN_FC_STYPE_AUTH, + WLAN_FC_STYPE_ASSOC_REQ, + WLAN_FC_STYPE_REASSOC_REQ, + WLAN_FC_STYPE_DISASSOC, + WLAN_FC_STYPE_DEAUTH, + WLAN_FC_STYPE_ACTION, + WLAN_FC_STYPE_PROBE_REQ, +/* Beacon doesn't work as mac80211 doesn't currently allow + * it, but it wouldn't really be the right thing anyway as + * it isn't per interface ... maybe just dump the scan + * results periodically for OLBC? + */ +// WLAN_FC_STYPE_BEACON, + }; + unsigned int i; + + if (capwap_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "capwap: Subscribe to mgmt frames with AP " + "handle %p", bss->nl_mgmt); + + for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { + if (capwap_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (stypes[i] << 4), + NULL, 0) < 0) { + goto out_err; + } + } + + if (capwap_register_spurious_class3(bss)) + goto out_err; + + if (capwap_get_wiphy_data_ap(bss) == NULL) + goto out_err; + + return 0; + +out_err: + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_cache(&bss->nl_mgmt_cache); + nl_destroy_handles(&bss->nl_mgmt); + return -1; +} + + +static int capwap_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss) +{ + if (capwap_alloc_mgmt_handle(bss)) + return -1; + wpa_printf(MSG_DEBUG, "capwap: Subscribe to mgmt frames with AP " + "handle %p (device SME)", bss->nl_mgmt); + + if (capwap_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ACTION << 4), + NULL, 0) < 0) + goto out_err; + + return 0; + +out_err: + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_cache(&bss->nl_mgmt_cache); + nl_destroy_handles(&bss->nl_mgmt); + return -1; +} + + +static void capwap_mgmt_unsubscribe(struct i802_bss *bss, const char *reason) +{ + if (bss->nl_mgmt == NULL) + return; + wpa_printf(MSG_DEBUG, "capwap: Unsubscribe mgmt frames handle %p " + "(%s)", bss->nl_mgmt, reason); + eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt)); + nl_destroy_cache(&bss->nl_mgmt_cache); + nl_destroy_handles(&bss->nl_mgmt); + + capwap_put_wiphy_data_ap(bss); +} + + +#ifdef CONFIG_RFKILL +static void wpa_driver_capwap_send_rfkill(void *eloop_ctx, void *timeout_ctx) +{ + wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); +} +#endif /* CONFIG_RFKILL */ + +static int +wpa_driver_capwap_finish_drv_init_sta(struct wpa_driver_capwap_data *drv, + int *send_rfkill_event) +{ + struct i802_bss *bss = &drv->first_bss; + + /* + * Make sure the interface starts up in station mode unless this is a + * dynamically added interface (e.g., P2P) that was already configured + * with proper iftype. + */ + if (drv->ifindex != drv->global->if_add_ifindex && + wpa_driver_capwap_set_mode(bss, NL80211_IFTYPE_STATION) < 0) { + wpa_printf(MSG_ERROR, "capwap: Could not configure driver to " + "use managed mode"); + return -1; + } + + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { +#ifdef CONFIG_RFKILL + if (rfkill_is_blocked(drv->rfkill)) { + wpa_printf(MSG_DEBUG, "capwap: Could not yet enable " + "interface '%s' due to rfkill", + bss->ifname); + drv->if_disabled = 1; + *send_rfkill_event = 1; + } else +#endif + { + wpa_printf(MSG_ERROR, "capwap: Could not set " + "interface '%s' UP", bss->ifname); + return -1; + } + } + + netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, + 1, IF_OPER_DORMANT); +} + +static int +wpa_driver_capwap_finish_drv_init(struct wpa_driver_capwap_data *drv) +{ + wpa_printf(MSG_DEBUG, " 3.wpa_driver_capwap_finish_drv_init\n"); + struct i802_bss *bss = &drv->first_bss; + int send_rfkill_event = 0; + + drv->ifindex = if_nametoindex(bss->ifname); + drv->first_bss.ifindex = drv->ifindex; + + if (drv->nlmode == NL80211_IFTYPE_STATION) + wpa_driver_capwap_finish_drv_init_sta(drv, &send_rfkill_event); + + + if (wpa_driver_capwap_capa(drv)) + return -1; + + if (linux_get_fake_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + bss->addr)) + return -1; + + if (send_rfkill_event) { +#ifdef CONFIG_RFKILL + eloop_register_timeout(0, 0, wpa_driver_capwap_send_rfkill, + drv, drv->ctx); +#endif + } + + return 0; +} + + +static int wpa_driver_capwap_del_bss_beacon(struct i802_bss *bss) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + + bss->beacon_set = 0; + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +static int wpa_driver_capwap_del_beacon(struct wpa_driver_capwap_data *drv) +{ + struct i802_bss *bss; + + for (bss = &drv->first_bss; bss; bss = bss->next) + wpa_driver_capwap_del_bss_beacon(bss); + + return 0; +} + +static int wpa_driver_capwap_stop_ap(void *priv) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_del_beacon(bss->drv); +} + +/** + * wpa_driver_capwap_deinit - Deinitialize capwap driver interface + * @bss: Pointer to private capwap data from wpa_driver_capwap_init() + * + * Shut down driver interface and processing of driver events. Free + * private data buffer if one was allocated in wpa_driver_capwap_init(). + */ +static void wpa_driver_capwap_deinit(struct i802_bss *bss) +{ + wpa_printf(MSG_DEBUG,"wpa_driver_capwap_deinit\n"); + struct wpa_driver_capwap_data *drv = bss->drv; +} + + +/** + * wpa_driver_capwap_scan_timeout - Scan timeout to report scan completion + * @eloop_ctx: Driver private data + * @timeout_ctx: ctx argument given to wpa_driver_capwap_init() + * + * This function can be used as registered timeout when starting a scan to + * generate a scan completed event if the driver does not report this. + */ +static void wpa_driver_capwap_scan_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_driver_capwap_data *drv = eloop_ctx; + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { + wpa_driver_capwap_set_mode(&drv->first_bss, + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; + } + wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); + wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); +} + + +static struct nl_msg * +capwap_scan_common(struct wpa_driver_capwap_data *drv, u8 cmd, + struct wpa_driver_scan_params *params) +{ + struct nl_msg *msg; + int err; + size_t i; + + msg = nlmsg_alloc(); + if (!msg) + return NULL; + + capwap_cmd(drv, msg, 0, cmd); + + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0) + goto fail; + + if (params->num_ssids) { + struct nl_msg *ssids = nlmsg_alloc(); + if (ssids == NULL) + goto fail; + for (i = 1; i < params->num_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Scan SSID", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + if (nla_put(ssids, i + 1, params->ssids[i].ssid_len, + params->ssids[i].ssid) < 0) { + nlmsg_free(ssids); + goto fail; + } + } + err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); + nlmsg_free(ssids); + if (err < 0) + goto fail; + } + + if (params->extra_ies) { + wpa_hexdump(MSG_MSGDUMP, "capwap: Scan extra IEs", + params->extra_ies, params->extra_ies_len); + if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len, + params->extra_ies) < 0) + goto fail; + } + + if (params->freqs) { + struct nl_msg *freqs = nlmsg_alloc(); + if (freqs == NULL) + goto fail; + for (i = 0; params->freqs[i]; i++) { + wpa_printf(MSG_MSGDUMP, "capwap: Scan frequency %u " + "MHz", params->freqs[i]); + if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) { + nlmsg_free(freqs); + goto fail; + } + } + err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, + freqs); + nlmsg_free(freqs); + if (err < 0) + goto fail; + } + + os_free(drv->filter_ssids); + drv->filter_ssids = params->filter_ssids; + params->filter_ssids = NULL; + drv->num_filter_ssids = params->num_filter_ssids; + + return msg; + +fail: + nlmsg_free(msg); + return NULL; +} + + +/** + * wpa_driver_capwap_scan - Request the driver to initiate scan + * @bss: Pointer to private driver data from wpa_driver_capwap_init() + * @params: Scan parameters + * Returns: 0 on success, -1 on failure + */ +static int wpa_driver_capwap_scan(struct i802_bss *bss, + struct wpa_driver_scan_params *params) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = -1, timeout; + struct nl_msg *msg, *rates = NULL; + + drv->scan_for_auth = 0; + + msg = capwap_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params); + if (!msg) + return -1; + + if (params->p2p_probe) { + wpa_printf(MSG_DEBUG, "capwap: P2P probe - mask SuppRates"); + + rates = nlmsg_alloc(); + if (rates == NULL) + goto nla_put_failure; + + /* + * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates + * by masking out everything else apart from the OFDM rates 6, + * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz + * rates are left enabled. + */ + NLA_PUT(rates, NL80211_BAND_2GHZ, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) < + 0) + goto nla_put_failure; + + NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Scan trigger failed: ret=%d " + "(%s)", ret, strerror(-ret)); +#ifdef HOSTAPD + if (is_ap_interface(drv->nlmode)) { + /* + * mac80211 does not allow scan requests in AP mode, so + * try to do this in station mode. + */ + if (wpa_driver_capwap_set_mode( + bss, NL80211_IFTYPE_STATION)) + goto nla_put_failure; + + if (wpa_driver_capwap_scan(bss, params)) { + wpa_driver_capwap_set_mode(bss, drv->nlmode); + goto nla_put_failure; + } + + /* Restore AP mode when processing scan results */ + drv->ap_scan_as_station = drv->nlmode; + ret = 0; + } else + goto nla_put_failure; +#else /* HOSTAPD */ + goto nla_put_failure; +#endif /* HOSTAPD */ + } + + /* Not all drivers generate "scan completed" wireless event, so try to + * read results after a timeout. */ + timeout = 10; + if (drv->scan_complete_events) { + /* + * The driver seems to deliver events to notify when scan is + * complete, so use longer timeout to avoid race conditions + * with scanning and following association request. + */ + timeout = 30; + } + wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " + "seconds", ret, timeout); + eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); + eloop_register_timeout(timeout, 0, wpa_driver_capwap_scan_timeout, + drv, drv->ctx); + +nla_put_failure: + nlmsg_free(msg); + nlmsg_free(rates); + return ret; +} + + +/** + * wpa_driver_capwap_sched_scan - Initiate a scheduled scan + * @priv: Pointer to private driver data from wpa_driver_capwap_init() + * @params: Scan parameters + * @interval: Interval between scan cycles in milliseconds + * Returns: 0 on success, -1 on failure or if not supported + */ +static int wpa_driver_capwap_sched_scan(void *priv, + struct wpa_driver_scan_params *params, + u32 interval) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = -1; + struct nl_msg *msg; + struct nl_msg *match_set_ssid = NULL, *match_sets = NULL; + struct nl_msg *match_set_rssi = NULL; + size_t i; + +#ifdef ANDROID + if (!drv->capa.sched_scan_supported) + return android_pno_start(bss, params); +#endif /* ANDROID */ + + msg = capwap_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params); + if (!msg) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval); + + if ((drv->num_filter_ssids && + (int) drv->num_filter_ssids <= drv->capa.max_match_sets) || + params->filter_rssi) { + match_sets = nlmsg_alloc(); + if (match_sets == NULL) + goto nla_put_failure; + + for (i = 1; i < drv->num_filter_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, + "capwap: Sched scan filter SSID", + drv->filter_ssids[i].ssid, + drv->filter_ssids[i].ssid_len); + + match_set_ssid = nlmsg_alloc(); + if (match_set_ssid == NULL) + goto nla_put_failure; + NLA_PUT(match_set_ssid, + NL80211_ATTR_SCHED_SCAN_MATCH_SSID, + drv->filter_ssids[i].ssid_len, + drv->filter_ssids[i].ssid); + + if (nla_put_nested(match_sets, i + 1, match_set_ssid) < + 0) + goto nla_put_failure; + } + + if (params->filter_rssi) { + match_set_rssi = nlmsg_alloc(); + if (match_set_rssi == NULL) + goto nla_put_failure; + NLA_PUT_U32(match_set_rssi, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, + params->filter_rssi); + wpa_printf(MSG_MSGDUMP, + "capwap: Sched scan RSSI filter %d dBm", + params->filter_rssi); + if (nla_put_nested(match_sets, 0, match_set_rssi) < 0) + goto nla_put_failure; + } + + if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, + match_sets) < 0) + goto nla_put_failure; + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + + /* TODO: if we get an error here, we should fall back to normal scan */ + + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Sched scan start failed: " + "ret=%d (%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + wpa_printf(MSG_DEBUG, "capwap: Sched scan requested (ret=%d) - " + "scan interval %d msec", ret, interval); + +nla_put_failure: + nlmsg_free(match_set_ssid); + nlmsg_free(match_sets); + nlmsg_free(match_set_rssi); + nlmsg_free(msg); + return ret; +} + + +/** + * wpa_driver_capwap_stop_sched_scan - Stop a scheduled scan + * @priv: Pointer to private driver data from wpa_driver_capwap_init() + * Returns: 0 on success, -1 on failure or if not supported + */ +static int wpa_driver_capwap_stop_sched_scan(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = 0; + struct nl_msg *msg; + +#ifdef ANDROID + if (!drv->capa.sched_scan_supported) + return android_pno_stop(bss); +#endif /* ANDROID */ + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Sched scan stop failed: " + "ret=%d (%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + wpa_printf(MSG_DEBUG, "capwap: Sched scan stop sent (ret=%d)", ret); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static const u8 * capwap_get_ie(const u8 *ies, size_t ies_len, u8 ie) +{ + const u8 *end, *pos; + + if (ies == NULL) + return NULL; + + pos = ies; + end = ies + ies_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} + + +static int capwap_scan_filtered(struct wpa_driver_capwap_data *drv, + const u8 *ie, size_t ie_len) +{ + const u8 *ssid; + size_t i; + + if (drv->filter_ssids == NULL) + return 0; + + ssid = capwap_get_ie(ie, ie_len, WLAN_EID_SSID); + if (ssid == NULL) + return 1; + + for (i = 0; i < drv->num_filter_ssids; i++) { + if (ssid[1] == drv->filter_ssids[i].ssid_len && + os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == + 0) + return 0; + } + + return 1; +} + + +static int bss_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *bss[NL80211_BSS_MAX + 1]; + static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_TSF] = { .type = NLA_U64 }, + [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, + [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, + [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, + [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, + [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, + [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, + }; + struct capwap_bss_info_arg *_arg = arg; + struct wpa_scan_results *res = _arg->res; + struct wpa_scan_res **tmp; + struct wpa_scan_res *r; + const u8 *ie, *beacon_ie; + size_t ie_len, beacon_ie_len; + u8 *pos; + size_t i; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_BSS]) + return NL_SKIP; + if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], + bss_policy)) + return NL_SKIP; + if (bss[NL80211_BSS_STATUS]) { + enum nl80211_bss_status status; + status = nla_get_u32(bss[NL80211_BSS_STATUS]); + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_FREQUENCY]) { + _arg->assoc_freq = + nla_get_u32(bss[NL80211_BSS_FREQUENCY]); + wpa_printf(MSG_DEBUG, "capwap: Associated on %u MHz", + _arg->assoc_freq); + } + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_BSSID]) { + os_memcpy(_arg->assoc_bssid, + nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); + wpa_printf(MSG_DEBUG, "capwap: Associated with " + MACSTR, MAC2STR(_arg->assoc_bssid)); + } + } + if (!res) + return NL_SKIP; + if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { + ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + } else { + ie = NULL; + ie_len = 0; + } + if (bss[NL80211_BSS_BEACON_IES]) { + beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); + beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); + } else { + beacon_ie = NULL; + beacon_ie_len = 0; + } + + if (capwap_scan_filtered(_arg->drv, ie ? ie : beacon_ie, + ie ? ie_len : beacon_ie_len)) + return NL_SKIP; + + r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); + if (r == NULL) + return NL_SKIP; + if (bss[NL80211_BSS_BSSID]) + os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), + ETH_ALEN); + if (bss[NL80211_BSS_FREQUENCY]) + r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); + if (bss[NL80211_BSS_BEACON_INTERVAL]) + r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); + if (bss[NL80211_BSS_CAPABILITY]) + r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); + r->flags |= WPA_SCAN_NOISE_INVALID; + if (bss[NL80211_BSS_SIGNAL_MBM]) { + r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); + r->level /= 100; /* mBm to dBm */ + r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; + } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { + r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); + r->flags |= WPA_SCAN_QUAL_INVALID; + } else + r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; + if (bss[NL80211_BSS_TSF]) + r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); + if (bss[NL80211_BSS_SEEN_MS_AGO]) + r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); + r->ie_len = ie_len; + pos = (u8 *) (r + 1); + if (ie) { + os_memcpy(pos, ie, ie_len); + pos += ie_len; + } + r->beacon_ie_len = beacon_ie_len; + if (beacon_ie) + os_memcpy(pos, beacon_ie, beacon_ie_len); + + if (bss[NL80211_BSS_STATUS]) { + enum nl80211_bss_status status; + status = nla_get_u32(bss[NL80211_BSS_STATUS]); + switch (status) { + case NL80211_BSS_STATUS_AUTHENTICATED: + r->flags |= WPA_SCAN_AUTHENTICATED; + break; + case NL80211_BSS_STATUS_ASSOCIATED: + r->flags |= WPA_SCAN_ASSOCIATED; + break; + default: + break; + } + } + + /* + * cfg80211 maintains separate BSS table entries for APs if the same + * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does + * not use frequency as a separate key in the BSS table, so filter out + * duplicated entries. Prefer associated BSS entry in such a case in + * order to get the correct frequency into the BSS table. + */ + for (i = 0; i < res->num; i++) { + const u8 *s1, *s2; + if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0) + continue; + + s1 = capwap_get_ie((u8 *) (res->res[i] + 1), + res->res[i]->ie_len, WLAN_EID_SSID); + s2 = capwap_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID); + if (s1 == NULL || s2 == NULL || s1[1] != s2[1] || + os_memcmp(s1, s2, 2 + s1[1]) != 0) + continue; + + /* Same BSSID,SSID was already included in scan results */ + wpa_printf(MSG_DEBUG, "capwap: Remove duplicated scan result " + "for " MACSTR, MAC2STR(r->bssid)); + + if ((r->flags & WPA_SCAN_ASSOCIATED) && + !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) { + os_free(res->res[i]); + res->res[i] = r; + } else + os_free(r); + return NL_SKIP; + } + + tmp = os_realloc_array(res->res, res->num + 1, + sizeof(struct wpa_scan_res *)); + if (tmp == NULL) { + os_free(r); + return NL_SKIP; + } + tmp[res->num++] = r; + res->res = tmp; + + return NL_SKIP; +} + + +static void clear_state_mismatch(struct wpa_driver_capwap_data *drv, + const u8 *addr) +{ + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + wpa_printf(MSG_DEBUG, "capwap: Clear possible state " + "mismatch (" MACSTR ")", MAC2STR(addr)); + wpa_driver_capwap_mlme(drv, addr, + NL80211_CMD_DEAUTHENTICATE, + WLAN_REASON_PREV_AUTH_NOT_VALID, 1); + } +} + + +static void wpa_driver_capwap_check_bss_status( + struct wpa_driver_capwap_data *drv, struct wpa_scan_results *res) +{ + size_t i; + + for (i = 0; i < res->num; i++) { + struct wpa_scan_res *r = res->res[i]; + if (r->flags & WPA_SCAN_AUTHENTICATED) { + wpa_printf(MSG_DEBUG, "capwap: Scan results " + "indicates BSS status with " MACSTR + " as authenticated", + MAC2STR(r->bssid)); + if (is_sta_interface(drv->nlmode) && + os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && + os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "capwap: Unknown BSSID" + " in local state (auth=" MACSTR + " assoc=" MACSTR ")", + MAC2STR(drv->auth_bssid), + MAC2STR(drv->bssid)); + clear_state_mismatch(drv, r->bssid); + } + } + + if (r->flags & WPA_SCAN_ASSOCIATED) { + wpa_printf(MSG_DEBUG, "capwap: Scan results " + "indicate BSS status with " MACSTR + " as associated", + MAC2STR(r->bssid)); + if (is_sta_interface(drv->nlmode) && + !drv->associated) { + wpa_printf(MSG_DEBUG, "capwap: Local state " + "(not associated) does not match " + "with BSS state"); + clear_state_mismatch(drv, r->bssid); + } else if (is_sta_interface(drv->nlmode) && + os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "capwap: Local state " + "(associated with " MACSTR ") does " + "not match with BSS state", + MAC2STR(drv->bssid)); + clear_state_mismatch(drv, r->bssid); + clear_state_mismatch(drv, drv->bssid); + } + } + } +} + + +static struct wpa_scan_results * +capwap_get_scan_results(struct wpa_driver_capwap_data *drv) +{ + struct nl_msg *msg; + struct wpa_scan_results *res; + int ret; + struct capwap_bss_info_arg arg; + + res = os_zalloc(sizeof(*res)); + if (res == NULL) + return NULL; + msg = nlmsg_alloc(); + if (!msg) + goto nla_put_failure; + + capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + arg.drv = drv; + arg.res = res; + ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + msg = NULL; + if (ret == 0) { + wpa_printf(MSG_DEBUG, "capwap: Received scan results (%lu " + "BSSes)", (unsigned long) res->num); + capwap_get_noise_for_scan_results(drv, res); + return res; + } + wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " + "(%s)", ret, strerror(-ret)); +nla_put_failure: + nlmsg_free(msg); + wpa_scan_results_free(res); + return NULL; +} + + +/** + * wpa_driver_capwap_get_scan_results - Fetch the latest scan results + * @priv: Pointer to private wext data from wpa_driver_capwap_init() + * Returns: Scan results on success, -1 on failure + */ +static struct wpa_scan_results * +wpa_driver_capwap_get_scan_results(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct wpa_scan_results *res; + + res = capwap_get_scan_results(drv); + if (res) + wpa_driver_capwap_check_bss_status(drv, res); + return res; +} + + +static void capwap_dump_scan(struct wpa_driver_capwap_data *drv) +{ + struct wpa_scan_results *res; + size_t i; + + res = capwap_get_scan_results(drv); + if (res == NULL) { + wpa_printf(MSG_DEBUG, "capwap: Failed to get scan results"); + return; + } + + wpa_printf(MSG_DEBUG, "capwap: Scan result dump"); + for (i = 0; i < res->num; i++) { + struct wpa_scan_res *r = res->res[i]; + wpa_printf(MSG_DEBUG, "capwap: %d/%d " MACSTR "%s%s", + (int) i, (int) res->num, MAC2STR(r->bssid), + r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "", + r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); + } + + wpa_scan_results_free(res); +} + + +static int wpa_driver_capwap_set_key(const char *ifname, struct i802_bss *bss, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + int ifindex = if_nametoindex(ifname); + struct nl_msg *msg; + int ret; + + wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d " + "set_tx=%d seq_len=%lu key_len=%lu", + __func__, ifindex, alg, addr, key_idx, set_tx, + (unsigned long) seq_len, (unsigned long) key_len); +#ifdef CONFIG_TDLS + if (key_idx == -1) + key_idx = 0; +#endif /* CONFIG_TDLS */ + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + if (alg == WPA_ALG_NONE) { + capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY); + } else { + capwap_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); + NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); + switch (alg) { + case WPA_ALG_WEP: + if (key_len == 5) + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP40); + else + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP104); + break; + case WPA_ALG_TKIP: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_TKIP); + break; + case WPA_ALG_CCMP: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_CCMP); + break; + case WPA_ALG_GCMP: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_GCMP); + break; + case WPA_ALG_IGTK: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_AES_CMAC); + break; + case WPA_ALG_SMS4: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_SMS4); + break; + case WPA_ALG_KRK: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_KRK); + break; + default: + wpa_printf(MSG_ERROR, "%s: Unsupported encryption " + "algorithm %d", __func__, alg); + nlmsg_free(msg); + return -1; + } + } + + if (seq && seq_len) + NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq); + + if (addr && !is_broadcast_ether_addr(addr)) { + wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + if (alg != WPA_ALG_WEP && key_idx && !set_tx) { + wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK"); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, + NL80211_KEYTYPE_GROUP); + } + } else if (addr && is_broadcast_ether_addr(addr)) { + struct nl_msg *types; + int err; + wpa_printf(MSG_DEBUG, " broadcast key"); + types = nlmsg_alloc(); + if (!types) + goto nla_put_failure; + NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); + err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, + types); + nlmsg_free(types); + if (err) + goto nla_put_failure; + } + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) + ret = 0; + if (ret) + wpa_printf(MSG_DEBUG, "capwap: set_key failed; err=%d %s)", + ret, strerror(-ret)); + + /* + * If we failed or don't need to set the default TX key (below), + * we're done here. + */ + if (ret || !set_tx || alg == WPA_ALG_NONE) + return ret; + if (is_ap_interface(drv->nlmode) && addr && + !is_broadcast_ether_addr(addr)) + return ret; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_KEY); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + if (alg == WPA_ALG_IGTK) + NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); + else + NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); + if (addr && is_broadcast_ether_addr(addr)) { + struct nl_msg *types; + int err; + types = nlmsg_alloc(); + if (!types) + goto nla_put_failure; + NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); + err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, + types); + nlmsg_free(types); + if (err) + goto nla_put_failure; + } else if (addr) { + struct nl_msg *types; + int err; + types = nlmsg_alloc(); + if (!types) + goto nla_put_failure; + NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST); + err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, + types); + nlmsg_free(types); + if (err) + goto nla_put_failure; + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + ret = 0; + if (ret) + wpa_printf(MSG_DEBUG, "capwap: set_key default failed; " + "err=%d %s)", ret, strerror(-ret)); + return ret; + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, + int key_idx, int defkey, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); + if (!key_attr) + return -1; + + if (defkey && alg == WPA_ALG_IGTK) + NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT); + else if (defkey) + NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); + + NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); + + switch (alg) { + case WPA_ALG_WEP: + if (key_len == 5) + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP40); + else + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP104); + break; + case WPA_ALG_TKIP: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); + break; + case WPA_ALG_CCMP: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); + break; + case WPA_ALG_GCMP: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP); + break; + case WPA_ALG_IGTK: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_AES_CMAC); + break; + default: + wpa_printf(MSG_ERROR, "%s: Unsupported encryption " + "algorithm %d", __func__, alg); + return -1; + } + + if (seq && seq_len) + NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); + + NLA_PUT(msg, NL80211_KEY_DATA, key_len, key); + + nla_nest_end(msg, key_attr); + + return 0; + nla_put_failure: + return -1; +} + + +static int capwap_set_conn_keys(struct wpa_driver_associate_params *params, + struct nl_msg *msg) +{ + int i, privacy = 0; + struct nlattr *nl_keys, *nl_key; + + for (i = 0; i < 4; i++) { + if (!params->wep_key[i]) + continue; + privacy = 1; + break; + } + if (params->wps == WPS_MODE_PRIVACY) + privacy = 1; + if (params->pairwise_suite && + params->pairwise_suite != WPA_CIPHER_NONE) + privacy = 1; + + if (!privacy) + return 0; + + NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); + + nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS); + if (!nl_keys) + goto nla_put_failure; + + for (i = 0; i < 4; i++) { + if (!params->wep_key[i]) + continue; + + nl_key = nla_nest_start(msg, i); + if (!nl_key) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i], + params->wep_key[i]); + if (params->wep_key_len[i] == 5) + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP40); + else + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP104); + + NLA_PUT_U8(msg, NL80211_KEY_IDX, i); + + if (i == params->wep_tx_keyidx) + NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); + + nla_nest_end(msg, nl_key); + } + nla_nest_end(msg, nl_keys); + + return 0; + +nla_put_failure: + return -ENOBUFS; +} + + +static int wpa_driver_capwap_mlme(struct wpa_driver_capwap_data *drv, + const u8 *addr, int cmd, u16 reason_code, + int local_state_change) +{ + int ret = -1; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, cmd); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); + if (addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + if (local_state_change) + NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_dbg(drv->ctx, MSG_DEBUG, + "capwap: MLME command failed: reason=%u ret=%d (%s)", + reason_code, ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_capwap_disconnect(struct wpa_driver_capwap_data *drv, + int reason_code) +{ + wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code); + drv->associated = 0; + drv->ignore_next_local_disconnect = 0; + /* Disconnect command doesn't need BSSID - it uses cached value */ + return wpa_driver_capwap_mlme(drv, NULL, NL80211_CMD_DISCONNECT, + reason_code, 0); +} + + +static int wpa_driver_capwap_deauthenticate(struct i802_bss *bss, + const u8 *addr, int reason_code) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) + return wpa_driver_capwap_disconnect(drv, reason_code); + wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", + __func__, MAC2STR(addr), reason_code); + drv->associated = 0; + if (drv->nlmode == NL80211_IFTYPE_ADHOC) + return capwap_leave_ibss(drv); + return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, + reason_code, 0); +} + + +static void capwap_copy_auth_params(struct wpa_driver_capwap_data *drv, + struct wpa_driver_auth_params *params) +{ + int i; + + drv->auth_freq = params->freq; + drv->auth_alg = params->auth_alg; + drv->auth_wep_tx_keyidx = params->wep_tx_keyidx; + drv->auth_local_state_change = params->local_state_change; + drv->auth_p2p = params->p2p; + + if (params->bssid) + os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN); + else + os_memset(drv->auth_bssid_, 0, ETH_ALEN); + + if (params->ssid) { + os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len); + drv->auth_ssid_len = params->ssid_len; + } else + drv->auth_ssid_len = 0; + + + os_free(drv->auth_ie); + drv->auth_ie = NULL; + drv->auth_ie_len = 0; + if (params->ie) { + drv->auth_ie = os_malloc(params->ie_len); + if (drv->auth_ie) { + os_memcpy(drv->auth_ie, params->ie, params->ie_len); + drv->auth_ie_len = params->ie_len; + } + } + + for (i = 0; i < 4; i++) { + if (params->wep_key[i] && params->wep_key_len[i] && + params->wep_key_len[i] <= 16) { + os_memcpy(drv->auth_wep_key[i], params->wep_key[i], + params->wep_key_len[i]); + drv->auth_wep_key_len[i] = params->wep_key_len[i]; + } else + drv->auth_wep_key_len[i] = 0; + } +} + + +static int wpa_driver_capwap_authenticate( + struct i802_bss *bss, struct wpa_driver_auth_params *params) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = -1, i; + struct nl_msg *msg; + enum nl80211_auth_type type; + enum nl80211_iftype nlmode; + int count = 0; + int is_retry; + + is_retry = drv->retry_auth; + drv->retry_auth = 0; + + drv->associated = 0; + os_memset(drv->auth_bssid, 0, ETH_ALEN); + /* FIX: IBSS mode */ + nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + if (drv->nlmode != nlmode && + wpa_driver_capwap_set_mode(bss, nlmode) < 0) + return -1; + +retry: + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "capwap: Authenticate (ifindex=%d)", + drv->ifindex); + + capwap_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE); + + for (i = 0; i < 4; i++) { + if (!params->wep_key[i]) + continue; + wpa_driver_capwap_set_key(bss->ifname, bss, WPA_ALG_WEP, + NULL, i, + i == params->wep_tx_keyidx, NULL, 0, + params->wep_key[i], + params->wep_key_len[i]); + if (params->wep_tx_keyidx != i) + continue; + if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, + params->wep_key[i], params->wep_key_len[i])) { + nlmsg_free(msg); + return -1; + } + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { + wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + } + if (params->ssid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + } + wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len); + if (params->ie) + NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie); + if (params->sae_data) { + wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data, + params->sae_data_len); + NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len, + params->sae_data); + } + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (params->auth_alg & WPA_AUTH_ALG_SHARED) + type = NL80211_AUTHTYPE_SHARED_KEY; + else if (params->auth_alg & WPA_AUTH_ALG_LEAP) + type = NL80211_AUTHTYPE_NETWORK_EAP; + else if (params->auth_alg & WPA_AUTH_ALG_FT) + type = NL80211_AUTHTYPE_FT; + else if (params->auth_alg & WPA_AUTH_ALG_SAE) + type = NL80211_AUTHTYPE_SAE; + else + goto nla_put_failure; + wpa_printf(MSG_DEBUG, " * Auth Type %d", type); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); + if (params->local_state_change) { + wpa_printf(MSG_DEBUG, " * Local state change only"); + NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_dbg(drv->ctx, MSG_DEBUG, + "capwap: MLME command failed (auth): ret=%d (%s)", + ret, strerror(-ret)); + count++; + if (ret == -EALREADY && count == 1 && params->bssid && + !params->local_state_change) { + /* + * mac80211 does not currently accept new + * authentication if we are already authenticated. As a + * workaround, force deauthentication and try again. + */ + wpa_printf(MSG_DEBUG, "capwap: Retry authentication " + "after forced deauthentication"); + wpa_driver_capwap_deauthenticate( + bss, params->bssid, + WLAN_REASON_PREV_AUTH_NOT_VALID); + nlmsg_free(msg); + goto retry; + } + + if (ret == -ENOENT && params->freq && !is_retry) { + /* + * cfg80211 has likely expired the BSS entry even + * though it was previously available in our internal + * BSS table. To recover quickly, start a single + * channel scan on the specified channel. + */ + struct wpa_driver_scan_params scan; + int freqs[2]; + + os_memset(&scan, 0, sizeof(scan)); + scan.num_ssids = 1; + if (params->ssid) { + scan.ssids[0].ssid = params->ssid; + scan.ssids[0].ssid_len = params->ssid_len; + } + freqs[0] = params->freq; + freqs[1] = 0; + scan.freqs = freqs; + wpa_printf(MSG_DEBUG, "capwap: Trigger single " + "channel scan to refresh cfg80211 BSS " + "entry"); + ret = wpa_driver_capwap_scan(bss, &scan); + if (ret == 0) { + capwap_copy_auth_params(drv, params); + drv->scan_for_auth = 1; + } + } else if (is_retry) { + /* + * Need to indicate this with an event since the return + * value from the retry is not delivered to core code. + */ + union wpa_event_data event; + wpa_printf(MSG_DEBUG, "capwap: Authentication retry " + "failed"); + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.timeout_event.addr, drv->auth_bssid_, + ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT, + &event); + } + + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "capwap: Authentication request send " + "successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_capwap_authenticate_retry( + struct wpa_driver_capwap_data *drv) +{ + struct wpa_driver_auth_params params; + struct i802_bss *bss = &drv->first_bss; + int i; + + wpa_printf(MSG_DEBUG, "capwap: Try to authenticate again"); + + os_memset(¶ms, 0, sizeof(params)); + params.freq = drv->auth_freq; + params.auth_alg = drv->auth_alg; + params.wep_tx_keyidx = drv->auth_wep_tx_keyidx; + params.local_state_change = drv->auth_local_state_change; + params.p2p = drv->auth_p2p; + + if (!is_zero_ether_addr(drv->auth_bssid_)) + params.bssid = drv->auth_bssid_; + + if (drv->auth_ssid_len) { + params.ssid = drv->auth_ssid; + params.ssid_len = drv->auth_ssid_len; + } + + params.ie = drv->auth_ie; + params.ie_len = drv->auth_ie_len; + + for (i = 0; i < 4; i++) { + if (drv->auth_wep_key_len[i]) { + params.wep_key[i] = drv->auth_wep_key[i]; + params.wep_key_len[i] = drv->auth_wep_key_len[i]; + } + } + + drv->retry_auth = 1; + return wpa_driver_capwap_authenticate(bss, ¶ms); +} + + +struct phy_info_arg { + u16 *num_modes; + struct hostapd_hw_modes *modes; +}; + +static int phy_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct phy_info_arg *phy_info = arg; + + struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; + + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; + + struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; + static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { + [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, + [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, + }; + + struct nlattr *nl_band; + struct nlattr *nl_freq; + struct nlattr *nl_rate; + int rem_band, rem_freq, rem_rate; + struct hostapd_hw_modes *mode; + int idx, mode_is_set; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) + return NL_SKIP; + + nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { + mode = os_realloc_array(phy_info->modes, + *phy_info->num_modes + 1, + sizeof(*mode)); + if (!mode) + return NL_SKIP; + phy_info->modes = mode; + + mode_is_set = 0; + + mode = &phy_info->modes[*(phy_info->num_modes)]; + memset(mode, 0, sizeof(*mode)); + mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN; + *(phy_info->num_modes) += 1; + + nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), + nla_len(nl_band), NULL); + + if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { + mode->ht_capab = nla_get_u16( + tb_band[NL80211_BAND_ATTR_HT_CAPA]); + } + + if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { + mode->a_mpdu_params |= nla_get_u8( + tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) & + 0x03; + } + + if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { + mode->a_mpdu_params |= nla_get_u8( + tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) << + 2; + } + + if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && + nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) { + u8 *mcs; + mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); + os_memcpy(mode->mcs_set, mcs, 16); + } + + if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) { + mode->vht_capab = nla_get_u32( + tb_band[NL80211_BAND_ATTR_VHT_CAPA]); + } + + if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] && + nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) { + u8 *mcs; + mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]); + os_memcpy(mode->vht_mcs_set, mcs, 8); + } + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), + nla_len(nl_freq), freq_policy); + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + mode->num_channels++; + } + + mode->channels = os_calloc(mode->num_channels, + sizeof(struct hostapd_channel_data)); + if (!mode->channels) + return NL_SKIP; + + idx = 0; + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), + nla_len(nl_freq), freq_policy); + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + + mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + mode->channels[idx].flag = 0; + + if (!mode_is_set) { + /* crude heuristic */ + if (mode->channels[idx].freq < 4000) + mode->mode = HOSTAPD_MODE_IEEE80211B; + else if (mode->channels[idx].freq > 50000) + mode->mode = HOSTAPD_MODE_IEEE80211AD; + else + mode->mode = HOSTAPD_MODE_IEEE80211A; + mode_is_set = 1; + } + + switch (mode->mode) { + case HOSTAPD_MODE_IEEE80211AD: + mode->channels[idx].chan = + (mode->channels[idx].freq - 56160) / + 2160; + break; + case HOSTAPD_MODE_IEEE80211A: + mode->channels[idx].chan = + mode->channels[idx].freq / 5 - 1000; + break; + case HOSTAPD_MODE_IEEE80211B: + case HOSTAPD_MODE_IEEE80211G: + if (mode->channels[idx].freq == 2484) + mode->channels[idx].chan = 14; + else + mode->channels[idx].chan = + (mode->channels[idx].freq - + 2407) / 5; + break; + default: + break; + } + + if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) + mode->channels[idx].flag |= + HOSTAPD_CHAN_DISABLED; + if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) + mode->channels[idx].flag |= + HOSTAPD_CHAN_PASSIVE_SCAN; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) + mode->channels[idx].flag |= + HOSTAPD_CHAN_NO_IBSS; + if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) + mode->channels[idx].flag |= + HOSTAPD_CHAN_RADAR; + + if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && + !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) + mode->channels[idx].max_tx_power = + nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100; + + idx++; + } + + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), + nla_len(nl_rate), rate_policy); + if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) + continue; + mode->num_rates++; + } + + mode->rates = os_calloc(mode->num_rates, sizeof(int)); + if (!mode->rates) + return NL_SKIP; + + idx = 0; + + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), + nla_len(nl_rate), rate_policy); + if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) + continue; + mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); + + /* crude heuristic */ + if (mode->mode == HOSTAPD_MODE_IEEE80211B && + mode->rates[idx] > 200) + mode->mode = HOSTAPD_MODE_IEEE80211G; + + idx++; + } + } + + return NL_SKIP; +} + +static struct hostapd_hw_modes * +wpa_driver_capwap_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes) +{ + u16 m; + struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; + int i, mode11g_idx = -1; + int j; + + /* If only 802.11g mode is included, use it to construct matching + * 802.11b mode data. */ + + for (m = 0; m < *num_modes; m++) { + wpa_printf(MSG_DEBUG,"*** 2.2 %d\n",m); + if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) + return modes; /* 802.11b already included */ + if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) + mode11g_idx = m; + } + + if (mode11g_idx < 0) + return modes; /* 2.4 GHz band not supported at all */ + + nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes)); + if (nmodes == NULL) + return modes; /* Could not add 802.11b mode */ + + mode = &nmodes[*num_modes]; + os_memset(mode, 0, sizeof(*mode)); + (*num_modes)++; + modes = nmodes; + + mode->mode = HOSTAPD_MODE_IEEE80211B; + + mode11g = &modes[mode11g_idx]; + mode->num_channels = mode11g->num_channels; + mode->channels = os_malloc(mode11g->num_channels * + sizeof(struct hostapd_channel_data)); + if (mode->channels == NULL) { + (*num_modes)--; + return modes; /* Could not add 802.11b mode */ + } + os_memcpy(mode->channels, mode11g->channels, + mode11g->num_channels * sizeof(struct hostapd_channel_data)); + + mode->num_rates = 0; + mode->rates = os_malloc(4 * sizeof(int)); + if (mode->rates == NULL) { + os_free(mode->channels); + (*num_modes)--; + return modes; /* Could not add 802.11b mode */ + } + + for (i = 0; i < mode11g->num_rates; i++) { + if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && + mode11g->rates[i] != 55 && mode11g->rates[i] != 110) + continue; + mode->rates[mode->num_rates] = mode11g->rates[i]; + mode->num_rates++; + if (mode->num_rates == 4) + break; + } + + if (mode->num_rates == 0) { + os_free(mode->channels); + os_free(mode->rates); + (*num_modes)--; + return modes; /* No 802.11b rates */ + } + + wpa_printf(MSG_DEBUG, "capwap: Added 802.11b mode based on 802.11g information"); + wpa_printf(MSG_DEBUG,"*** Num_channels:%d Num_rates:%d capab:%d flags:%d MODE:%d mpdu:%02X",modes->num_channels,modes->num_rates,modes->ht_capab,modes->flags,modes->mode,modes->a_mpdu_params); + + for(j=0;j < 16;j++){ + wpa_printf(MSG_DEBUG,"%02X ",modes->mcs_set[j]); + } + + for(j=0;j < modes->num_channels;j++){ + wpa_printf(MSG_DEBUG,"*** %d freq:%d flag:%d chan:%d freq:%d maxPower:%02X ",j,modes->channels[j].freq,modes->channels[j].flag,modes->channels[j].chan,modes->channels[j].freq,modes->channels[j].max_tx_power); + } + for(j=0;j < modes->num_rates;j++){ + wpa_printf(MSG_DEBUG,"*** %d rate:%d ",j,modes->rates[j]); + } + + return modes; +} + + +static void capwap_set_ht40_mode(struct hostapd_hw_modes *mode, int start, + int end) +{ + int c; + + for (c = 0; c < mode->num_channels; c++) { + struct hostapd_channel_data *chan = &mode->channels[c]; + if (chan->freq - 10 >= start && chan->freq + 10 <= end) + chan->flag |= HOSTAPD_CHAN_HT40; + } +} + + +static void capwap_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, + int end) +{ + int c; + + for (c = 0; c < mode->num_channels; c++) { + struct hostapd_channel_data *chan = &mode->channels[c]; + if (!(chan->flag & HOSTAPD_CHAN_HT40)) + continue; + if (chan->freq - 30 >= start && chan->freq - 10 <= end) + chan->flag |= HOSTAPD_CHAN_HT40MINUS; + if (chan->freq + 10 >= start && chan->freq + 30 <= end) + chan->flag |= HOSTAPD_CHAN_HT40PLUS; + } +} + + +static void capwap_reg_rule_ht40(struct nlattr *tb[], + struct phy_info_arg *results) +{ + u32 start, end, max_bw; + u16 m; + + if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || + tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || + tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) + return; + + start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; + end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; + max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; + + wpa_printf(MSG_DEBUG, "capwap: %u-%u @ %u MHz", + start, end, max_bw); + if (max_bw < 40) + return; + + for (m = 0; m < *results->num_modes; m++) { + if (!(results->modes[m].ht_capab & + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) + continue; + capwap_set_ht40_mode(&results->modes[m], start, end); + } +} + + +static void capwap_reg_rule_sec(struct nlattr *tb[], + struct phy_info_arg *results) +{ + u32 start, end, max_bw; + u16 m; + + if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || + tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || + tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) + return; + + start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; + end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; + max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; + + if (max_bw < 20) + return; + + for (m = 0; m < *results->num_modes; m++) { + if (!(results->modes[m].ht_capab & + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) + continue; + capwap_set_ht40_mode_sec(&results->modes[m], start, end); + } +} + + +static int capwap_get_reg(struct nl_msg *msg, void *arg) +{ + struct phy_info_arg *results = arg; + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *nl_rule; + struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1]; + int rem_rule; + static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { + [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, + [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, + [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, + [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, + [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, + [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, + }; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb_msg[NL80211_ATTR_REG_ALPHA2] || + !tb_msg[NL80211_ATTR_REG_RULES]) { + wpa_printf(MSG_DEBUG, "capwap: No regulatory information " + "available"); + return NL_SKIP; + } + + wpa_printf(MSG_DEBUG, "capwap: Regulatory information - country=%s", + (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2])); + + nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) + { + nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, + nla_data(nl_rule), nla_len(nl_rule), reg_policy); + capwap_reg_rule_ht40(tb_rule, results); + } + + nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) + { + nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, + nla_data(nl_rule), nla_len(nl_rule), reg_policy); + capwap_reg_rule_sec(tb_rule, results); + } + + return NL_SKIP; +} + + +static int capwap_set_ht40_flags(struct wpa_driver_capwap_data *drv, + struct phy_info_arg *results) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_GET_REG); + return send_and_recv_msgs(drv, msg, capwap_get_reg, results); +} + + +static struct hostapd_hw_modes * +AC_wpa_driver_capwap_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) +{ + int rate_arrays[8]; + int num_rates; + int num_modes1; + int i; + + num_rates = capability_get_rates(rate_arrays); + num_modes1 = capability_get_num_modes(); + + struct hostapd_hw_modes *mode; + int clen, rlen; + const short chan2freq[14] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 + }; + + + *flags = 0; + mode = os_zalloc(sizeof(struct hostapd_hw_modes)); + if (mode == NULL) + return NULL; + + *num_modes = 1; + + if(capability_is_B()){ + mode->mode = HOSTAPD_MODE_IEEE80211B; + }else{ + wpa_printf(MSG_ERROR, "ERROR AC_wpa_driver_capwap_get_hw_feature_data\n"); + exit(1); + } + + mode->num_channels = capability_get_num_channels(); + mode->num_rates = num_rates ; + + clen = mode->num_channels * sizeof(struct hostapd_channel_data); + rlen = mode->num_rates * sizeof(int); + + mode->channels = os_zalloc(clen); + mode->rates = os_zalloc(rlen); + if (mode->channels == NULL || mode->rates == NULL) { + os_free(mode->channels); + os_free(mode->rates); + os_free(mode); + return NULL; + } + for (i = 0; i < mode->num_channels; i++) { + mode->channels[i].chan = i + 1; + mode->channels[i].freq = chan2freq[i]; + /* TODO: Get allowed channel list from the driver */ + if (i >= 11) + mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; + } + + for( i=0; inum_rates ; i++){ + if( rate_arrays[i] < 0 ) + mode->rates[i] = -1 * rate_arrays[i]; + else + mode->rates[i] = rate_arrays[i]; + } + + return mode; + +} + +static struct hostapd_hw_modes * +wpa_driver_capwap_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) { + return AC_wpa_driver_capwap_get_hw_feature_data(priv,num_modes,flags); +} + + +static int wpa_driver_capwap_send_mntr(struct wpa_driver_capwap_data *drv, + const void *data, size_t len, + int encrypt, int noack) +{ + + wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_send_frame "); + unsigned char buf[3000]; + + __u8 rtap_hdr[] = { + 0x00, 0x00, /* radiotap version */ + 0x0e, 0x00, /* radiotap length */ + 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ + IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ + 0x00, /* padding */ + 0x00, 0x00, /* RX and TX flags to indicate that */ + 0x00, 0x00, /* this is the injected frame directly */ + }; + struct iovec iov[2] = { + { + .iov_base = &rtap_hdr, + .iov_len = sizeof(rtap_hdr), + }, + { + .iov_base = (void *) data, + .iov_len = len, + } + }; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = iov, + .msg_iovlen = 2, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + int res; + u16 txflags = 0; + + if (encrypt) + rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; + + if (noack) + txflags |= IEEE80211_RADIOTAP_F_TX_NOACK; + WPA_PUT_LE16(&rtap_hdr[12], txflags); + + memcpy(buf,(u8 *)(data),len); + //AC_handle_send_data_to_WTP(buf, len, generic_ac_info.own_mac_addr); + + //Switch_Mac_Address_AC_to_WTP(buf, generic_ac_info.own_mac_addr); + ipc_send_80211_to_wtp(generic_ac_info.fd_ipc, buf, len); + + return 0; + + res = sendmsg(drv->monitor_sock, &msg, 0); + if (res < 0) { + wpa_printf(MSG_INFO, "capwap: sendmsg: %s", strerror(errno)); + return -1; + } + return 0; +} + + +static int wpa_driver_capwap_send_frame(struct i802_bss *bss, + const void *data, size_t len, + int encrypt, int noack, + unsigned int freq, int no_cck, + int offchanok, unsigned int wait_time) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + u64 cookie; + + if (freq == 0) + freq = bss->freq; + + if (drv->use_monitor) + return wpa_driver_capwap_send_mntr(drv, data, len, + encrypt, noack); + + return capwap_send_frame_cmd(bss, freq, wait_time, data, len, + &cookie, no_cck, noack, offchanok); +} + + +static int wpa_driver_capwap_send_mlme(struct i802_bss *bss, const u8 *data, + size_t data_len, int noack, + unsigned int freq, int no_cck, + int offchanok, + unsigned int wait_time) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct ieee80211_mgmt *mgmt; + int encrypt = 1; + u16 fc; + + mgmt = (struct ieee80211_mgmt *) data; + fc = le_to_host16(mgmt->frame_control); + + if (is_sta_interface(drv->nlmode) && + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { + /* + * The use of last_mgmt_freq is a bit of a hack, + * but it works due to the single-threaded nature + * of wpa_supplicant. + */ + if (freq == 0) + freq = drv->last_mgmt_freq; + return capwap_send_frame_cmd(bss, freq, 0, + data, data_len, NULL, 1, noack, + 1); + } + + if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { + if (freq == 0) + freq = bss->freq; + return capwap_send_frame_cmd(bss, freq, + (int) freq == bss->freq ? 0 : + wait_time, + data, data_len, + &drv->send_action_cookie, + no_cck, noack, offchanok); + } + + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { + /* + * Only one of the authentication frame types is encrypted. + * In order for static WEP encryption to work properly (i.e., + * to not encrypt the frame), we need to tell mac80211 about + * the frames that must not be encrypted. + */ + u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); + u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); + if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) + encrypt = 0; + } + + return wpa_driver_capwap_send_frame(bss, data, data_len, encrypt, + noack, freq, no_cck, offchanok, + wait_time); +} + + +int round1=0; + +static int capwap_set_bss(struct i802_bss *bss, int cts, int preamble, + int slot, int ht_opmode, int ap_isolate, + int *basic_rates) +{ + wpa_printf(MSG_DEBUG,"> capwap_set_bss\n"); + if(round1)return 0; + else round1=1; + + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); + + if (cts >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); + if (preamble >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); + if (slot >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); + if (ht_opmode >= 0) + NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); + if (ap_isolate >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate); + + if (basic_rates) { + u8 rates[NL80211_MAX_SUPP_RATES]; + u8 rates_len = 0; + int i; + + for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; + i++) + rates[rates_len++] = basic_rates[i] / 5; + + NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int wpa_driver_capwap_set_ap(void *priv, + struct wpa_driver_ap_params *params) +{ + wpa_printf(MSG_DEBUG, "> wpa_driver_capwap_set_ap \n"); + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + u8 cmd = NL80211_CMD_NEW_BEACON; + int ret; + int beacon_set; + int ifindex = if_nametoindex(bss->ifname); + int num_suites; + u32 suites[10]; + u32 ver; + + beacon_set = bss->beacon_set; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "capwap: Set beacon (beacon_set=%d)", + beacon_set); + if (beacon_set) + cmd = NL80211_CMD_SET_BEACON; + + capwap_cmd(drv, msg, 0, cmd); + NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head); + NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int); + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->proberesp && params->proberesp_len) + NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len, + params->proberesp); + switch (params->hide_ssid) { + case NO_SSID_HIDING: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_NOT_IN_USE); + break; + case HIDDEN_SSID_ZERO_LEN: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_LEN); + break; + case HIDDEN_SSID_ZERO_CONTENTS: + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_CONTENTS); + break; + } + if (params->privacy) + NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); + if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == + (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { + /* Leave out the attribute */ + } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_SHARED_KEY); + else + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_OPEN_SYSTEM); + + ver = 0; + if (params->wpa_version & WPA_PROTO_WPA) + ver |= NL80211_WPA_VERSION_1; + if (params->wpa_version & WPA_PROTO_RSN) + ver |= NL80211_WPA_VERSION_2; + if (ver) + NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); + + num_suites = 0; + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X) + suites[num_suites++] = WLAN_AKM_SUITE_8021X; + if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK) + suites[num_suites++] = WLAN_AKM_SUITE_PSK; + if (num_suites) { + NLA_PUT(msg, NL80211_ATTR_AKM_SUITES, + num_suites * sizeof(u32), suites); + } + + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X && + params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); + + num_suites = 0; + if (params->pairwise_ciphers & WPA_CIPHER_CCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; + if (params->pairwise_ciphers & WPA_CIPHER_GCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP; + if (params->pairwise_ciphers & WPA_CIPHER_TKIP) + suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; + if (params->pairwise_ciphers & WPA_CIPHER_WEP104) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; + if (params->pairwise_ciphers & WPA_CIPHER_WEP40) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + if (num_suites) { + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + num_suites * sizeof(u32), suites); + } + + switch (params->group_cipher) { + case WPA_CIPHER_CCMP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_CCMP); + break; + case WPA_CIPHER_GCMP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_GCMP); + break; + case WPA_CIPHER_TKIP: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_TKIP); + break; + case WPA_CIPHER_WEP104: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_WEP104); + break; + case WPA_CIPHER_WEP40: + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + WLAN_CIPHER_SUITE_WEP40); + break; + } + + if (params->beacon_ies) { + NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies), + wpabuf_head(params->beacon_ies)); + } + if (params->proberesp_ies) { + NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP, + wpabuf_len(params->proberesp_ies), + wpabuf_head(params->proberesp_ies)); + } + if (params->assocresp_ies) { + NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP, + wpabuf_len(params->assocresp_ies), + wpabuf_head(params->assocresp_ies)); + } + + if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) { + NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT, + params->ap_max_inactivity); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Beacon set failed: %d (%s)", + ret, strerror(-ret)); + } else { + bss->beacon_set = 1; + capwap_set_bss(bss, params->cts_protect, params->preamble, + params->short_slot_time, params->ht_opmode, + params->isolate, params->basic_rates); + } + + wpa_printf(MSG_DEBUG, "=== (P) privacy: %d\n",params->privacy); + wpa_printf(MSG_DEBUG, "=== (T) short_slot_time: %d\n",params->short_slot_time); + wpa_printf(MSG_DEBUG, "=== (S) preamble: %d\n",params->preamble); + + prep_beacon(generic_ac_info.fd_ipc,drv->ctx,params); + + //ipc_send_ADD_WLAN(generic_ac_info.fd_ipc, params->ssid, params->ssid_len); + + return ret; + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int wpa_driver_capwap_set_freq(struct i802_bss *bss, + struct hostapd_freq_params *freq) +{ + wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_set_freq\n"); + return 0; +} + + +static u32 sta_flags_capwap(int flags) +{ + u32 f = 0; + + if (flags & WPA_STA_AUTHORIZED) + f |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (flags & WPA_STA_WMM) + f |= BIT(NL80211_STA_FLAG_WME); + if (flags & WPA_STA_SHORT_PREAMBLE) + f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (flags & WPA_STA_MFP) + f |= BIT(NL80211_STA_FLAG_MFP); + if (flags & WPA_STA_TDLS_PEER) + f |= BIT(NL80211_STA_FLAG_TDLS_PEER); + + return f; +} + + +static int wpa_driver_capwap_sta_add(void *priv, + struct hostapd_sta_add_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg, *wme = NULL; + struct nl80211_sta_flag_update upd; + int ret = -ENOBUFS; + + if ((params->flags & WPA_STA_TDLS_PEER) && + !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "capwap: %s STA " MACSTR, + params->set ? "Set" : "Add", MAC2STR(params->addr)); + capwap_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION : + NL80211_CMD_NEW_STATION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); + NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, + params->supp_rates); + wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates, + params->supp_rates_len); + if (!params->set) { + wpa_printf(MSG_DEBUG, " * aid=%u", params->aid); + NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); + wpa_printf(MSG_DEBUG, " * listen_interval=%u", + params->listen_interval); + NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, + params->listen_interval); + } + if (params->ht_capabilities) { + wpa_hexdump(MSG_DEBUG, " * ht_capabilities", + (u8 *) params->ht_capabilities, + sizeof(*params->ht_capabilities)); + NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, + sizeof(*params->ht_capabilities), + params->ht_capabilities); + } + + if (params->vht_capabilities) { + wpa_hexdump(MSG_DEBUG, " * vht_capabilities", + (u8 *) params->vht_capabilities, + sizeof(*params->vht_capabilities)); + NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, + sizeof(*params->vht_capabilities), + params->vht_capabilities); + } + + wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability); + NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability); + + if (params->ext_capab) { + wpa_hexdump(MSG_DEBUG, " * ext_capab", + params->ext_capab, params->ext_capab_len); + NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY, + params->ext_capab_len, params->ext_capab); + } + + os_memset(&upd, 0, sizeof(upd)); + upd.mask = sta_flags_capwap(params->flags); + upd.set = upd.mask; + wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x", + upd.set, upd.mask); + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + if (params->flags & WPA_STA_WMM) { + wme = nlmsg_alloc(); + if (!wme) + goto nla_put_failure; + + wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo); + NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES, + params->qosinfo & WMM_QOSINFO_STA_AC_MASK); + NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP, + (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) & + WMM_QOSINFO_STA_SP_MASK); + if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0) + goto nla_put_failure; + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) + wpa_printf(MSG_DEBUG, "capwap: NL80211_CMD_%s_STATION " + "result: %d (%s)", params->set ? "SET" : "NEW", ret, + strerror(-ret)); + if (ret == -EEXIST) + ret = 0; + nla_put_failure: + nlmsg_free(wme); + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_capwap_sta_remove(struct i802_bss *bss, const u8 *addr) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + return 0; + return ret; + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static void capwap_remove_iface(struct wpa_driver_capwap_data *drv, + int ifidx) +{ + struct nl_msg *msg; + + wpa_printf(MSG_DEBUG, "capwap: Remove interface ifindex=%d", ifidx); + + /* stop listening for EAPOL on this interface */ + del_ifidx(drv, ifidx); + + msg = nlmsg_alloc(); + if (!msg) + goto nla_put_failure; + + capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); + + if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + return; + msg = NULL; + nla_put_failure: + nlmsg_free(msg); + wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); +} + + +static const char * capwap_iftype_str(enum nl80211_iftype mode) +{ + switch (mode) { + case NL80211_IFTYPE_ADHOC: + return "ADHOC"; + case NL80211_IFTYPE_STATION: + return "STATION"; + case NL80211_IFTYPE_AP: + return "AP"; + case NL80211_IFTYPE_MONITOR: + return "MONITOR"; + case NL80211_IFTYPE_P2P_CLIENT: + return "P2P_CLIENT"; + case NL80211_IFTYPE_P2P_GO: + return "P2P_GO"; + default: + return "unknown"; + } +} + + +static int capwap_create_iface_once(struct wpa_driver_capwap_data *drv, + const char *ifname, + enum nl80211_iftype iftype, + const u8 *addr, int wds) +{ + wpa_printf(MSG_DEBUG, "# capwap_create_iface_once\n"); + struct nl_msg *msg, *flags = NULL; + int ifidx; + int ret = -ENOBUFS; + + wpa_printf(MSG_DEBUG, "capwap: Create interface iftype %d (%s)", + iftype, capwap_iftype_str(iftype)); + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); + + if (iftype == NL80211_IFTYPE_MONITOR) { + int err; + + flags = nlmsg_alloc(); + if (!flags) + goto nla_put_failure; + + NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); + + err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); + + nlmsg_free(flags); + + if (err) + goto nla_put_failure; + } else if (wds) { + NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + nla_put_failure: + nlmsg_free(msg); + wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", + ifname, ret, strerror(-ret)); + return ret; + } + + ifidx = if_nametoindex(ifname); + wpa_printf(MSG_DEBUG, "capwap: New interface %s created: ifindex=%d", + ifname, ifidx); + + /* start listening for EAPOL on this interface */ + wpa_printf(MSG_DEBUG, "start listening for EAPOL on this interface\n"); + add_ifidx(drv, ifidx); + + if (addr && iftype != NL80211_IFTYPE_MONITOR && + linux_set_fake_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) { + capwap_remove_iface(drv, ifidx); + return -1; + } + + wpa_printf(MSG_DEBUG, "#9 %d\n",ifidx); + + return ifidx; +} + + +static int capwap_create_iface(struct wpa_driver_capwap_data *drv, + const char *ifname, enum nl80211_iftype iftype, + const u8 *addr, int wds) +{ + int ret; + + ret = capwap_create_iface_once(drv, ifname, iftype, addr, wds); + + /* if error occurred and interface exists already */ + if (ret == -ENFILE && if_nametoindex(ifname)) { + wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); + + /* Try to remove the interface that was already there. */ + capwap_remove_iface(drv, if_nametoindex(ifname)); + + /* Try to create the interface again */ + ret = capwap_create_iface_once(drv, ifname, iftype, addr, + wds); + } + + if (ret >= 0 && is_p2p_interface(iftype)) + capwap_disable_11b_rates(drv, ret, 1); + + return ret; +} + + +static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) +{ + struct ieee80211_hdr *hdr; + u16 fc; + union wpa_event_data event; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = buf; + event.tx_status.data_len = len; + event.tx_status.ack = ok; + wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); +} + + +static void from_unknown_sta(struct wpa_driver_capwap_data *drv, + u8 *buf, size_t len) +{ + struct ieee80211_hdr *hdr = (void *)buf; + u16 fc; + union wpa_event_data event; + + if (len < sizeof(*hdr)) + return; + + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); + event.rx_from_unknown.addr = hdr->addr2; + event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) == + (WLAN_FC_FROMDS | WLAN_FC_TODS); + wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); +} + + +static void handle_frame(struct wpa_driver_capwap_data *drv, + u8 *buf, size_t len, int datarate, int ssi_signal) +{ + struct ieee80211_hdr *hdr; + u16 fc; + union wpa_event_data event; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + switch (WLAN_FC_GET_TYPE(fc)) { + case WLAN_FC_TYPE_MGMT: + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.datarate = datarate; + event.rx_mgmt.ssi_signal = ssi_signal; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + break; + case WLAN_FC_TYPE_CTRL: + /* can only get here with PS-Poll frames */ + wpa_printf(MSG_DEBUG, "CTRL"); + from_unknown_sta(drv, buf, len); + break; + case WLAN_FC_TYPE_DATA: + from_unknown_sta(drv, buf, len); + break; + } +} + + +static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_driver_capwap_data *drv = eloop_ctx; + int len; + unsigned char buf[3000]; + struct ieee80211_radiotap_iterator iter; + int ret; + int datarate = 0, ssi_signal = 0; + int injected = 0, failed = 0, rxflags = 0; + len = recv(sock, buf, sizeof(buf), 0); + + if (len < 0) { + perror("recv"); + return; + } + + if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { + wpa_printf(MSG_DEBUG, "received invalid radiotap frame\n"); + return; + } + + while (1) { + ret = ieee80211_radiotap_iterator_next(&iter); + if (ret == -ENOENT) + break; + if (ret) { + wpa_printf(MSG_DEBUG, "received invalid radiotap frame (%d)\n", ret); + return; + } + switch (iter.this_arg_index) { + case IEEE80211_RADIOTAP_FLAGS: + if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) + len -= 4; + break; + case IEEE80211_RADIOTAP_RX_FLAGS: + rxflags = 1; + break; + case IEEE80211_RADIOTAP_TX_FLAGS: + injected = 1; + failed = le_to_host16((*(uint16_t *) iter.this_arg)) & + IEEE80211_RADIOTAP_F_TX_FAIL; + break; + case IEEE80211_RADIOTAP_DATA_RETRIES: + break; + case IEEE80211_RADIOTAP_CHANNEL: + /* TODO: convert from freq/flags to channel number */ + break; + case IEEE80211_RADIOTAP_RATE: + datarate = *iter.this_arg * 5; + break; + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + ssi_signal = (s8) *iter.this_arg; + break; + } + } + + if (rxflags && injected) + return; + + if (!injected) + handle_frame(drv, buf + iter.max_length, + len - iter.max_length, datarate, ssi_signal); + else + handle_tx_callback(drv->ctx, buf + iter.max_length, + len - iter.max_length, !failed); +} + + +/* + * we post-process the filter code later and rewrite + * this to the offset to the last instruction + */ +#define PASS 0xFF +#define FAIL 0xFE + +static struct sock_filter msock_filter_insns[] = { + /* + * do a little-endian load of the radiotap length field + */ + /* load lower byte into A */ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), + /* put it into X (== index register) */ + BPF_STMT(BPF_MISC| BPF_TAX, 0), + /* load upper byte into A */ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), + /* left-shift it by 8 */ + BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), + /* or with X */ + BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), + /* put result into X */ + BPF_STMT(BPF_MISC| BPF_TAX, 0), + + /* + * Allow management frames through, this also gives us those + * management frames that we sent ourselves with status + */ + /* load the lower byte of the IEEE 802.11 frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), + /* mask off frame type and version */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), + /* accept frame if it's both 0, fall through otherwise */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), + + /* + * TODO: add a bit to radiotap RX flags that indicates + * that the sending station is not associated, then + * add a filter here that filters on our DA and that flag + * to allow us to deauth frames to that bad station. + * + * For now allow all To DS data frames through. + */ + /* load the IEEE 802.11 frame control field */ + BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0), + /* mask off frame type, version and DS status */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03), + /* accept frame if version 0, type 2 and To DS, fall through otherwise + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0), + +#if 0 + /* + * drop non-data frames + */ + /* load the lower byte of the frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), + /* mask off QoS bit */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), + /* drop non-data frames */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), +#endif + /* load the upper byte of the frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), + /* mask off toDS/fromDS */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), + /* accept WDS frames */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), + + /* + * add header length to index + */ + /* load the lower byte of the frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), + /* mask off QoS bit */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), + /* right shift it by 6 to give 0 or 2 */ + BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), + /* add data frame header length */ + BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), + /* add index, was start of 802.11 header */ + BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), + /* move to index, now start of LL header */ + BPF_STMT(BPF_MISC | BPF_TAX, 0), + + /* + * Accept empty data frames, we use those for + * polling activity. + */ + BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), + + /* + * Accept EAPOL frames + */ + BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), + BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), + + /* keep these last two statements or change the code below */ + /* return 0 == "DROP" */ + BPF_STMT(BPF_RET | BPF_K, 0), + /* return ~0 == "keep all" */ + BPF_STMT(BPF_RET | BPF_K, ~0), +}; + +static struct sock_fprog msock_filter = { + .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]), + .filter = msock_filter_insns, +}; + + +static int add_monitor_filter(int s) +{ + int idx; + + /* rewrite all PASS/FAIL jump offsets */ + for (idx = 0; idx < msock_filter.len; idx++) { + struct sock_filter *insn = &msock_filter_insns[idx]; + + if (BPF_CLASS(insn->code) == BPF_JMP) { + if (insn->code == (BPF_JMP|BPF_JA)) { + if (insn->k == PASS) + insn->k = msock_filter.len - idx - 2; + else if (insn->k == FAIL) + insn->k = msock_filter.len - idx - 3; + } + + if (insn->jt == PASS) + insn->jt = msock_filter.len - idx - 2; + else if (insn->jt == FAIL) + insn->jt = msock_filter.len - idx - 3; + + if (insn->jf == PASS) + insn->jf = msock_filter.len - idx - 2; + else if (insn->jf == FAIL) + insn->jf = msock_filter.len - idx - 3; + } + } + + if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, + &msock_filter, sizeof(msock_filter))) { + perror("SO_ATTACH_FILTER"); + return -1; + } + + return 0; +} + + +static void capwap_remove_monitor_interface( + struct wpa_driver_capwap_data *drv) +{ + return; + drv->monitor_refcount--; + if (drv->monitor_refcount > 0) + return; + + if (drv->monitor_ifidx >= 0) { + capwap_remove_iface(drv, drv->monitor_ifidx); + drv->monitor_ifidx = -1; + } + if (drv->monitor_sock >= 0) { + eloop_unregister_read_sock(drv->monitor_sock); + close(drv->monitor_sock); + drv->monitor_sock = -1; + } +} + + +static int +capwap_create_monitor_interface(struct wpa_driver_capwap_data *drv) +{ + wpa_printf(MSG_DEBUG, "8.5 capwap_create_monitor_interface\n"); + char buf[IFNAMSIZ]; + struct sockaddr_ll ll; + int optval; + socklen_t optlen; + + if (drv->monitor_ifidx >= 0) { + drv->monitor_refcount++; + return 0; + } + + if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) { + /* + * P2P interface name is of the format p2p-%s-%d. For monitor + * interface name corresponding to P2P GO, replace "p2p-" with + * "mon-" to retain the same interface name length and to + * indicate that it is a monitor interface. + */ + snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4); + } else { + /* Non-P2P interface with AP functionality. */ + snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); + } + + buf[IFNAMSIZ - 1] = '\0'; + + drv->monitor_ifidx = + capwap_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, + 0); + + if (drv->monitor_ifidx == -EOPNOTSUPP) { + /* + * This is backward compatibility for a few versions of + * the kernel only that didn't advertise the right + * attributes for the only driver that then supported + * AP mode w/o monitor -- ath6kl. + */ + wpa_printf(MSG_DEBUG, "capwap: Driver does not support " + "monitor interface type - try to run without it"); + drv->device_ap_sme = 1; + } + + if (drv->monitor_ifidx < 0) + return -1; + + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, buf, 1)) + goto error; + + memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + ll.sll_ifindex = drv->monitor_ifidx; + drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (drv->monitor_sock < 0) { + perror("socket[PF_PACKET,SOCK_RAW]"); + goto error; + } + + if (add_monitor_filter(drv->monitor_sock)) { + wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " + "interface; do filtering in user space"); + /* This works, but will cost in performance. */ + } + + if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { + perror("monitor socket bind"); + goto error; + } + + optlen = sizeof(optval); + optval = 20; + if (setsockopt + (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { + perror("Failed to set socket priority"); + goto error; + } + + if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, + drv, NULL)) { + wpa_printf(MSG_DEBUG, "Could not register monitor read socket\n"); + goto error; + } + + return 0; + error: + capwap_remove_monitor_interface(drv); + return -1; +} + + +static int capwap_setup_ap(struct i802_bss *bss) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + + wpa_printf(MSG_DEBUG, "capwap: Setup AP - device_ap_sme=%d " + "use_monitor=%d", drv->device_ap_sme, drv->use_monitor); + + /* + * Disable Probe Request reporting unless we need it in this way for + * devices that include the AP SME, in the other case (unless using + * monitor iface) we'll get it through the nl_mgmt socket instead. + */ + if (!drv->device_ap_sme) + wpa_driver_capwap_probe_req_report(bss, 0); + + if (!drv->device_ap_sme && !drv->use_monitor) + if (capwap_mgmt_subscribe_ap(bss)) + return -1; + + if (drv->device_ap_sme && !drv->use_monitor) + if (capwap_mgmt_subscribe_ap_dev_sme(bss)) + return -1; + + if (!drv->device_ap_sme && drv->use_monitor && + capwap_create_monitor_interface(drv) && + !drv->device_ap_sme) + return -1; + + if (drv->device_ap_sme && + wpa_driver_capwap_probe_req_report(bss, 1) < 0) { + wpa_printf(MSG_DEBUG, "capwap: Failed to enable " + "Probe Request frame reporting in AP mode"); + /* Try to survive without this */ + } + + return 0; +} + + +static void capwap_teardown_ap(struct i802_bss *bss) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + + if (drv->device_ap_sme) { + wpa_driver_capwap_probe_req_report(bss, 0); + if (!drv->use_monitor) + capwap_mgmt_unsubscribe(bss, "AP teardown (dev SME)"); + } else if (drv->use_monitor) + capwap_remove_monitor_interface(drv); + else + capwap_mgmt_unsubscribe(bss, "AP teardown"); + + bss->beacon_set = 0; +} + + +static int capwap_send_eapol_data(struct i802_bss *bss, + const u8 *addr, const u8 *data, + size_t data_len) +{ + wpa_printf(MSG_DEBUG, "capwap_send_eapol_data\n"); + struct sockaddr_ll ll; + int ret; + + if (bss->drv->eapol_tx_sock < 0) { + wpa_printf(MSG_DEBUG, "capwap: No socket to send EAPOL"); + return -1; + } + + os_memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + ll.sll_ifindex = bss->ifindex; + ll.sll_protocol = htons(ETH_P_PAE); + ll.sll_halen = ETH_ALEN; + os_memcpy(ll.sll_addr, addr, ETH_ALEN); + ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0, + (struct sockaddr *) &ll, sizeof(ll)); + if (ret < 0) + wpa_printf(MSG_ERROR, "capwap: EAPOL TX: %s", + strerror(errno)); + + return ret; +} + + +static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +static int wpa_driver_capwap_hapd_send_eapol( + void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, const u8 *own_addr, u32 flags) +{ + wpa_printf(MSG_DEBUG, "-------------- wpa_driver_capwap_hapd_send_eapol\n"); + return; + + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct ieee80211_hdr *hdr; + size_t len; + u8 *pos; + int res; + int qos = flags & WPA_STA_WMM; + + if (drv->device_ap_sme || !drv->use_monitor) + return capwap_send_eapol_data(bss, addr, data, data_len); + + len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + wpa_printf(MSG_DEBUG, "malloc() failed for i802_send_data(len=%lu)\n", + (unsigned long) len); + return -1; + } + + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); + hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); + if (encrypt) + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); + if (qos) { + hdr->frame_control |= + host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); + } + + memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); + memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + pos = (u8 *) (hdr + 1); + + if (qos) { + /* Set highest priority in QoS header */ + pos[0] = 7; + pos[1] = 0; + pos += 2; + } + + memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); + pos += sizeof(rfc1042_header); + WPA_PUT_BE16(pos, ETH_P_PAE); + pos += 2; + memcpy(pos, data, data_len); + + res = wpa_driver_capwap_send_frame(bss, (u8 *) hdr, len, encrypt, 0, + 0, 0, 0, 0); + if (res < 0) { + wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " + "failed: %d (%s)", + (unsigned long) len, errno, strerror(errno)); + } + os_free(hdr); + + return res; +} + + +static int wpa_driver_capwap_sta_set_flags(void *priv, const u8 *addr, + int total_flags, + int flags_or, int flags_and) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg, *flags = NULL; + struct nl80211_sta_flag_update upd; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + flags = nlmsg_alloc(); + if (!flags) { + nlmsg_free(msg); + return -ENOMEM; + } + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + /* + * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This + * can be removed eventually. + */ + if (total_flags & WPA_STA_AUTHORIZED) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); + + if (total_flags & WPA_STA_WMM) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); + + if (total_flags & WPA_STA_SHORT_PREAMBLE) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); + + if (total_flags & WPA_STA_MFP) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); + + if (total_flags & WPA_STA_TDLS_PEER) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER); + + if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) + goto nla_put_failure; + + os_memset(&upd, 0, sizeof(upd)); + upd.mask = sta_flags_capwap(flags_or | ~flags_and); + upd.set = sta_flags_capwap(flags_or); + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + nlmsg_free(flags); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + nlmsg_free(flags); + return -ENOBUFS; +} + + +static int wpa_driver_capwap_ap(struct wpa_driver_capwap_data *drv, + struct wpa_driver_associate_params *params) +{ + enum nl80211_iftype nlmode, old_mode; + struct hostapd_freq_params freq = { + .freq = params->freq, + }; + + if (params->p2p) { + wpa_printf(MSG_DEBUG, "capwap: Setup AP operations for P2P " + "group (GO)"); + nlmode = NL80211_IFTYPE_P2P_GO; + } else + nlmode = NL80211_IFTYPE_AP; + + old_mode = drv->nlmode; + if (wpa_driver_capwap_set_mode(&drv->first_bss, nlmode)) { + capwap_remove_monitor_interface(drv); + return -1; + } + + if (wpa_driver_capwap_set_freq(&drv->first_bss, &freq)) { + if (old_mode != nlmode) + wpa_driver_capwap_set_mode(&drv->first_bss, old_mode); + capwap_remove_monitor_interface(drv); + return -1; + } + + return 0; +} + + +static int capwap_leave_ibss(struct wpa_driver_capwap_data *drv) +{ + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Leave IBSS failed: ret=%d " + "(%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + ret = 0; + wpa_printf(MSG_DEBUG, "capwap: Leave IBSS request sent successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_capwap_ibss(struct wpa_driver_capwap_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + int ret = -1, i; + int count = 0; + + wpa_printf(MSG_DEBUG, "capwap: Join IBSS (ifindex=%d)", drv->ifindex); + + if (wpa_driver_capwap_set_mode(&drv->first_bss, + NL80211_IFTYPE_ADHOC)) { + wpa_printf(MSG_INFO, "capwap: Failed to set interface into " + "IBSS mode"); + return -1; + } + +retry: + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; + + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + +// if (params->fixed_freq) { +// wpa_printf(MSG_DEBUG, " * fixed_freq"); +// NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED); +// } + +// if (params->beacon_interval > 0) { +// wpa_printf(MSG_DEBUG, " * beacon_interval=%d", +// params->beacon_interval); +// NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, +// params->beacon_interval); +// } + +// if (params->rates[0] > 0) { +// wpa_printf(MSG_DEBUG, " * basic_rates:"); +// i = 0; +// while (i < NL80211_MAX_SUPP_RATES && +// params->rates[i] > 0) { +// wpa_printf(MSG_DEBUG, " %.1f", +// (double)params->rates[i] / 2); +// i++; +// } +// NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, i, +// params->rates); +// } + +// if (params->mcast_rate > 0) { +// wpa_printf(MSG_DEBUG, " * mcast_rates=%.1f", +// (double)params->mcast_rate / 10); +// NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, params->mcast_rate); +// } + +// if (params->ht_set) { +// switch(params->htmode) { +// case NL80211_CHAN_HT20: +// wpa_printf(MSG_DEBUG, " * ht=HT20"); +// break; +// case NL80211_CHAN_HT40PLUS: +// wpa_printf(MSG_DEBUG, " * ht=HT40+"); +// break; +// case NL80211_CHAN_HT40MINUS: +// wpa_printf(MSG_DEBUG, " * ht=HT40-"); +// break; +// } +// NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, +// params->htmode); +// } + + ret = capwap_set_conn_keys(params, msg); + if (ret) + goto nla_put_failure; + + if (params->bssid && params->fixed_bssid) { + wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + + if (params->key_mgmt_suite == KEY_MGMT_802_1X || + params->key_mgmt_suite == KEY_MGMT_PSK || + params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 || + params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) { + wpa_printf(MSG_DEBUG, " * control port"); + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + } + + if (params->wpa_ie) { + wpa_hexdump(MSG_DEBUG, + " * Extra IEs for Beacon/Probe Response frames", + params->wpa_ie, params->wpa_ie_len); + NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, + params->wpa_ie); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Join IBSS failed: ret=%d (%s)", + ret, strerror(-ret)); + count++; + if (ret == -EALREADY && count == 1) { + wpa_printf(MSG_DEBUG, "capwap: Retry IBSS join after " + "forced leave"); + capwap_leave_ibss(drv); + nlmsg_free(msg); + goto retry; + } + + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "capwap: Join IBSS request sent successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_capwap_try_connect( + struct wpa_driver_capwap_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + enum nl80211_auth_type type; + int ret = 0; + int algs; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "capwap: Connect (ifindex=%d)", drv->ifindex); + capwap_cmd(drv, msg, 0, NL80211_CMD_CONNECT); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { + wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + } + if (params->bg_scan_period >= 0) { + wpa_printf(MSG_DEBUG, " * bg scan period=%d", + params->bg_scan_period); + NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD, + params->bg_scan_period); + } + if (params->ssid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; + } + wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); + if (params->wpa_ie) + NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, + params->wpa_ie); + + algs = 0; + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + algs++; + if (params->auth_alg & WPA_AUTH_ALG_SHARED) + algs++; + if (params->auth_alg & WPA_AUTH_ALG_LEAP) + algs++; + if (algs > 1) { + wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " + "selection"); + goto skip_auth_type; + } + + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (params->auth_alg & WPA_AUTH_ALG_SHARED) + type = NL80211_AUTHTYPE_SHARED_KEY; + else if (params->auth_alg & WPA_AUTH_ALG_LEAP) + type = NL80211_AUTHTYPE_NETWORK_EAP; + else if (params->auth_alg & WPA_AUTH_ALG_FT) + type = NL80211_AUTHTYPE_FT; + else + goto nla_put_failure; + + wpa_printf(MSG_DEBUG, " * Auth Type %d", type); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); + +skip_auth_type: + if (params->wpa_proto) { + enum nl80211_wpa_versions ver = 0; + + if (params->wpa_proto & WPA_PROTO_WPA) + ver |= NL80211_WPA_VERSION_1; + if (params->wpa_proto & WPA_PROTO_RSN) + ver |= NL80211_WPA_VERSION_2; + + wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver); + NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); + } + + if (params->pairwise_suite != CIPHER_NONE) { + int cipher; + + switch (params->pairwise_suite) { + case CIPHER_SMS4: + cipher = WLAN_CIPHER_SUITE_SMS4; + break; + case CIPHER_WEP40: + cipher = WLAN_CIPHER_SUITE_WEP40; + break; + case CIPHER_WEP104: + cipher = WLAN_CIPHER_SUITE_WEP104; + break; + case CIPHER_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case CIPHER_GCMP: + cipher = WLAN_CIPHER_SUITE_GCMP; + break; + case CIPHER_TKIP: + default: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); + } + + if (params->group_suite != CIPHER_NONE) { + int cipher; + + switch (params->group_suite) { + case CIPHER_SMS4: + cipher = WLAN_CIPHER_SUITE_SMS4; + break; + case CIPHER_WEP40: + cipher = WLAN_CIPHER_SUITE_WEP40; + break; + case CIPHER_WEP104: + cipher = WLAN_CIPHER_SUITE_WEP104; + break; + case CIPHER_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case CIPHER_GCMP: + cipher = WLAN_CIPHER_SUITE_GCMP; + break; + case CIPHER_TKIP: + default: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); + } + + if (params->key_mgmt_suite == KEY_MGMT_802_1X || + params->key_mgmt_suite == KEY_MGMT_PSK || + params->key_mgmt_suite == KEY_MGMT_CCKM) { + int mgmt = WLAN_AKM_SUITE_PSK; + + switch (params->key_mgmt_suite) { + case KEY_MGMT_CCKM: + mgmt = WLAN_AKM_SUITE_CCKM; + break; + case KEY_MGMT_802_1X: + mgmt = WLAN_AKM_SUITE_8021X; + break; + case KEY_MGMT_PSK: + default: + mgmt = WLAN_AKM_SUITE_PSK; + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); + } + +#ifdef CONFIG_IEEE80211W + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) + NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); +#endif /* CONFIG_IEEE80211W */ + + if (params->disable_ht) + NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); + + if (params->htcaps && params->htcaps_mask) { + int sz = sizeof(struct ieee80211_ht_capabilities); + NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps); + NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz, + params->htcaps_mask); + } + + ret = capwap_set_conn_keys(params, msg); + if (ret) + goto nla_put_failure; + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: MLME connect failed: ret=%d " + "(%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "capwap: Connect request send successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; + +} + + +static int wpa_driver_capwap_connect( + struct wpa_driver_capwap_data *drv, + struct wpa_driver_associate_params *params) +{ + int ret = wpa_driver_capwap_try_connect(drv, params); + if (ret == -EALREADY) { + /* + * cfg80211 does not currently accept new connections if + * we are already connected. As a workaround, force + * disconnection and try again. + */ + wpa_printf(MSG_DEBUG, "capwap: Explicitly " + "disconnecting before reassociation " + "attempt"); + if (wpa_driver_capwap_disconnect( + drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) + return -1; + /* Ignore the next local disconnect message. */ + drv->ignore_next_local_disconnect = 1; + ret = wpa_driver_capwap_try_connect(drv, params); + } + return ret; +} + + +static int wpa_driver_capwap_associate( + void *priv, struct wpa_driver_associate_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = -1; + struct nl_msg *msg; + + if (params->mode == IEEE80211_MODE_AP) + return wpa_driver_capwap_ap(drv, params); + + if (params->mode == IEEE80211_MODE_IBSS) + return wpa_driver_capwap_ibss(drv, params); + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { + enum nl80211_iftype nlmode = params->p2p ? + NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; + + if (wpa_driver_capwap_set_mode(priv, nlmode) < 0) + return -1; + return wpa_driver_capwap_connect(drv, params); + } + + drv->associated = 0; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "capwap: Associate (ifindex=%d)", + drv->ifindex); + capwap_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { + wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + drv->assoc_freq = params->freq; + } else + drv->assoc_freq = 0; + if (params->bg_scan_period >= 0) { + wpa_printf(MSG_DEBUG, " * bg scan period=%d", + params->bg_scan_period); + NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD, + params->bg_scan_period); + } + if (params->ssid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; + } + wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); + if (params->wpa_ie) + NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, + params->wpa_ie); + + if (params->pairwise_suite != CIPHER_NONE) { + int cipher; + + switch (params->pairwise_suite) { + case CIPHER_WEP40: + cipher = WLAN_CIPHER_SUITE_WEP40; + break; + case CIPHER_WEP104: + cipher = WLAN_CIPHER_SUITE_WEP104; + break; + case CIPHER_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case CIPHER_GCMP: + cipher = WLAN_CIPHER_SUITE_GCMP; + break; + case CIPHER_TKIP: + default: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + } + wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); + } + + if (params->group_suite != CIPHER_NONE) { + int cipher; + + switch (params->group_suite) { + case CIPHER_WEP40: + cipher = WLAN_CIPHER_SUITE_WEP40; + break; + case CIPHER_WEP104: + cipher = WLAN_CIPHER_SUITE_WEP104; + break; + case CIPHER_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case CIPHER_GCMP: + cipher = WLAN_CIPHER_SUITE_GCMP; + break; + case CIPHER_TKIP: + default: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + } + wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); + } + +#ifdef CONFIG_IEEE80211W + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) + NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); +#endif /* CONFIG_IEEE80211W */ + + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + + if (params->prev_bssid) { + wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, + MAC2STR(params->prev_bssid)); + NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, + params->prev_bssid); + } + + if (params->disable_ht) + NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); + + if (params->htcaps && params->htcaps_mask) { + int sz = sizeof(struct ieee80211_ht_capabilities); + NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps); + NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz, + params->htcaps_mask); + } + + if (params->p2p) + wpa_printf(MSG_DEBUG, " * P2P group"); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_dbg(drv->ctx, MSG_DEBUG, + "capwap: MLME command failed (assoc): ret=%d (%s)", + ret, strerror(-ret)); + capwap_dump_scan(drv); + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "capwap: Association request send " + "successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int capwap_set_mode(struct wpa_driver_capwap_data *drv, + int ifindex, enum nl80211_iftype mode) +{ + wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_set_mode\n"); + struct nl_msg *msg; + int ret = -ENOBUFS; + + wpa_printf(MSG_DEBUG, "capwap: Set mode ifindex %d iftype %d (%s)", + ifindex, mode, capwap_iftype_str(mode)); + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (!ret) + return 0; +nla_put_failure: + nlmsg_free(msg); + wpa_printf(MSG_DEBUG, "capwap: Failed to set interface %d to mode %d:" + " %d (%s)", ifindex, mode, ret, strerror(-ret)); + return ret; +} + + +static int wpa_driver_capwap_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode) +{ + wpa_printf(MSG_DEBUG, " 6.wpa_driver_capwap_set_mode\n"); + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = -1; + int i; + int was_ap = is_ap_interface(drv->nlmode); + int res; + + res = capwap_set_mode(drv, drv->ifindex, nlmode); + if (res == 0) { + drv->nlmode = nlmode; + ret = 0; + goto done; + } + + if (res == -ENODEV) + return -1; + + if (nlmode == drv->nlmode) { + wpa_printf(MSG_DEBUG, "capwap: Interface already in " + "requested mode - ignore error"); + ret = 0; + goto done; /* Already in the requested mode */ + } + + /* mac80211 doesn't allow mode changes while the device is up, so + * take the device down, try to set the mode again, and bring the + * device back up. + */ + wpa_printf(MSG_DEBUG, "capwap: Try mode change after setting " + "interface down"); + for (i = 0; i < 10; i++) { + res = linux_set_fake_iface_flags(drv->global->ioctl_sock, + bss->ifname, 0); + if (res == -EACCES || res == -ENODEV) + break; + if (res == 0) { + /* Try to set the mode again while the interface is + * down */ + ret = capwap_set_mode(drv, drv->ifindex, nlmode); + if (ret == -EACCES) + break; + if (res && !ret) + ret = -1; + else if (ret != -EBUSY) + break; + } else + wpa_printf(MSG_DEBUG, "capwap: Failed to set " + "interface down"); + os_sleep(0, 100000); + } + + if (!ret) { + wpa_printf(MSG_DEBUG, "capwap: Mode change succeeded while " + "interface is down"); + drv->nlmode = nlmode; + drv->ignore_if_down_event = 1; + linux_set_fake_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); + } + +done: + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Interface mode change to %d " + "from %d failed", nlmode, drv->nlmode); + return ret; + } + + if (is_p2p_interface(nlmode)) + capwap_disable_11b_rates(drv, drv->ifindex, 1); + else if (drv->disabled_11b_rates) + capwap_disable_11b_rates(drv, drv->ifindex, 0); + + if (is_ap_interface(nlmode)) { + capwap_mgmt_unsubscribe(bss, "start AP"); + /* Setup additional AP mode functionality if needed */ + if (capwap_setup_ap(bss)) + return -1; + } else if (was_ap) { + /* Remove additional AP mode functionality */ + capwap_teardown_ap(bss); + } else { + capwap_mgmt_unsubscribe(bss, "mode change"); + } + + if (!bss->in_deinit && !is_ap_interface(nlmode) && + capwap_mgmt_subscribe_non_ap(bss) < 0) + wpa_printf(MSG_DEBUG, "capwap: Failed to register Action " + "frame processing - ignore for now"); + + return 0; +} + + +static int wpa_driver_capwap_get_capa(void *priv, + struct wpa_driver_capa *capa) +{ + wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_get_capa\n"); + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + if (!drv->has_capability) + return -1; + os_memcpy(capa, &drv->capa, sizeof(*capa)); + return 0; +} + + +static int wpa_driver_capwap_set_operstate(void *priv, int state) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + + wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", + __func__, drv->operstate, state, state ? "UP" : "DORMANT"); + drv->operstate = state; + return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, + state ? IF_OPER_UP : IF_OPER_DORMANT); +} + + +static int wpa_driver_capwap_set_supp_port(void *priv, int authorized) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + struct nl80211_sta_flag_update upd; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); + + os_memset(&upd, 0, sizeof(upd)); + upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); + if (authorized) + upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +/* Set kernel driver on given frequency (MHz) */ +static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + wpa_printf(MSG_DEBUG, " 1.i802_set_freq \n"); + struct i802_bss *bss = priv; + return wpa_driver_capwap_set_freq(bss, freq); +} + + +#if defined(HOSTAPD) || defined(CONFIG_AP) + +static inline int min_int(int a, int b) +{ + if (a < b) + return a; + return b; +} + + +static int get_key_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + /* + * TODO: validate the key index and mac address! + * Otherwise, there's a race condition as soon as + * the kernel starts sending key notifications. + */ + + if (tb[NL80211_ATTR_KEY_SEQ]) + memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), + min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); + return NL_SKIP; +} + + +static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, + int idx, u8 *seq) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_GET_KEY); + + if (addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); + + memset(seq, 0, 6); + + return send_and_recv_msgs(drv, msg, get_key_handler, seq); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int i802_set_rts(void *priv, int rts) +{ + wpa_printf(MSG_DEBUG, "> i802_set_rts %d \n",rts); + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; + u32 val; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + if (rts >= 2347) + val = (u32) -1; + else + val = rts; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (!ret) + return 0; +nla_put_failure: + nlmsg_free(msg); + wpa_printf(MSG_DEBUG, "capwap: Failed to set RTS threshold %d: " + "%d (%s)", rts, ret, strerror(-ret)); + return ret; +} + + +static int i802_set_frag(void *priv, int frag) +{ + wpa_printf(MSG_DEBUG, "> i802_set_frag %d\n",frag); + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; + u32 val; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + if (frag >= 2346) + val = (u32) -1; + else + val = frag; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (!ret) + return 0; +nla_put_failure: + nlmsg_free(msg); + wpa_printf(MSG_DEBUG, "capwap: Failed to set fragmentation threshold " + "%d: %d (%s)", frag, ret, strerror(-ret)); + return ret; +} + + +static int i802_flush(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int res; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); + + /* + * XXX: FIX! this needs to flush all VLANs too + */ + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + + res = send_and_recv_msgs(drv, msg, NULL, NULL); + if (res) { + wpa_printf(MSG_DEBUG, "capwap: Station flush failed: ret=%d " + "(%s)", res, strerror(-res)); + } + return res; + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +#endif /* HOSTAPD || CONFIG_AP */ + + +static int get_sta_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct hostap_sta_driver_data *data = arg; + struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; + static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 }, + }; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + /* + * TODO: validate the interface and mac address! + * Otherwise, there's a race condition as soon as + * the kernel starts sending station notifications. + */ + + if (!tb[NL80211_ATTR_STA_INFO]) { + wpa_printf(MSG_DEBUG, "sta stats missing!"); + return NL_SKIP; + } + if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, + tb[NL80211_ATTR_STA_INFO], + stats_policy)) { + wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); + return NL_SKIP; + } + + if (stats[NL80211_STA_INFO_INACTIVE_TIME]) + data->inactive_msec = + nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); + if (stats[NL80211_STA_INFO_RX_BYTES]) + data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); + if (stats[NL80211_STA_INFO_TX_BYTES]) + data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); + if (stats[NL80211_STA_INFO_RX_PACKETS]) + data->rx_packets = + nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); + if (stats[NL80211_STA_INFO_TX_PACKETS]) + data->tx_packets = + nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); + if (stats[NL80211_STA_INFO_TX_FAILED]) + data->tx_retry_failed = + nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]); + + return NL_SKIP; +} + +static int i802_read_sta_data(struct i802_bss *bss, + struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + + os_memset(data, 0, sizeof(*data)); + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, get_sta_handler, data); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +#if defined(HOSTAPD) || defined(CONFIG_AP) + +static int i802_set_tx_queue_params(void *priv, int queue, int aifs, + int cw_min, int cw_max, int burst_time) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *txq, *params; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); + if (!txq) + goto nla_put_failure; + + /* We are only sending parameters for a single TXQ at a time */ + params = nla_nest_start(msg, 1); + if (!params) + goto nla_put_failure; + + switch (queue) { + case 0: + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO); + break; + case 1: + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI); + break; + case 2: + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE); + break; + case 3: + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK); + break; + } + /* Burst time is configured in units of 0.1 msec and TXOP parameter in + * 32 usec, so need to convert the value here. */ + NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); + NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); + NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); + + nla_nest_end(msg, params); + + nla_nest_end(msg, txq); + + if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + return 0; + msg = NULL; + nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr, + const char *ifname, int vlan_id) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, + if_nametoindex(ifname)); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret < 0) { + wpa_printf(MSG_ERROR, "capwap: NL80211_ATTR_STA_VLAN (addr=" + MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", + MAC2STR(addr), ifname, vlan_id, ret, + strerror(-ret)); + } + nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int i802_get_inact_sec(void *priv, const u8 *addr) +{ + struct hostap_sta_driver_data data; + int ret; + + data.inactive_msec = (unsigned long) -1; + ret = i802_read_sta_data(priv, &data, addr); + if (ret || data.inactive_msec == (unsigned long) -1) + return -1; + return data.inactive_msec / 1000; +} + + +static int i802_sta_clear_stats(void *priv, const u8 *addr) +{ +#if 0 + /* TODO */ +#endif + return 0; +} + + +static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason) +{ + wpa_printf(MSG_DEBUG, " 1.i802_sta_deauth \n"); + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct ieee80211_mgmt mgmt; + + if (drv->device_ap_sme) + return wpa_driver_capwap_sta_remove(bss, addr); + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DEAUTH); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); + mgmt.u.deauth.reason_code = host_to_le16(reason); + int r = wpa_driver_capwap_send_mlme(bss, (u8 *) &mgmt, + IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth), 0, 0, 0, 0, + 0); + return r; +} + + +static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, + int reason) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct ieee80211_mgmt mgmt; + + if (drv->device_ap_sme) + return wpa_driver_capwap_sta_remove(bss, addr); + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DISASSOC); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); + mgmt.u.disassoc.reason_code = host_to_le16(reason); + return wpa_driver_capwap_send_mlme(bss, (u8 *) &mgmt, + IEEE80211_HDRLEN + + sizeof(mgmt.u.disassoc), 0, 0, 0, 0, + 0); +} + +#endif /* HOSTAPD || CONFIG_AP */ + +#ifdef HOSTAPD + +static void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) +{ + wpa_printf(MSG_DEBUG," 3.add_ifidx\n"); + int i; + int *old; + + wpa_printf(MSG_DEBUG, "capwap: Add own interface ifindex %d", + ifidx); + for (i = 0; i < drv->num_if_indices; i++) { + if (drv->if_indices[i] == 0) { + drv->if_indices[i] = ifidx; + return; + } + } + + if (drv->if_indices != drv->default_if_indices) + old = drv->if_indices; + else + old = NULL; + + drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1, + sizeof(int)); + if (!drv->if_indices) { + if (!old) + drv->if_indices = drv->default_if_indices; + else + drv->if_indices = old; + wpa_printf(MSG_ERROR, "Failed to reallocate memory for " + "interfaces"); + wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); + return; + } else if (!old) + os_memcpy(drv->if_indices, drv->default_if_indices, + sizeof(drv->default_if_indices)); + drv->if_indices[drv->num_if_indices] = ifidx; + drv->num_if_indices++; +} + + +static void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) +{ + int i; + + for (i = 0; i < drv->num_if_indices; i++) { + if (drv->if_indices[i] == ifidx) { + drv->if_indices[i] = 0; + break; + } + } +} + + +static int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) +{ + int i; + + for (i = 0; i < drv->num_if_indices; i++) + if (drv->if_indices[i] == ifidx) + return 1; + + return 0; +} + + +static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, + const char *bridge_ifname) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + char name[IFNAMSIZ + 1]; + + os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); + wpa_printf(MSG_DEBUG, "capwap: Set WDS STA addr=" MACSTR + " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); + if (val) { + if (!if_nametoindex(name)) { + if (capwap_create_iface(drv, name, + NL80211_IFTYPE_AP_VLAN, + bss->addr, 1) < 0) + return -1; + if (bridge_ifname && + linux_br_fake_add_if(drv->global->ioctl_sock, + bridge_ifname, name) < 0) + return -1; + } + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, name, 1)) { + wpa_printf(MSG_ERROR, "capwap: Failed to set WDS STA " + "interface %s up", name); + } + return i802_set_sta_vlan(priv, addr, name, 0); + } else { + if (bridge_ifname) + linux_br_fake_del_if(drv->global->ioctl_sock, bridge_ifname, + name); + + i802_set_sta_vlan(priv, addr, bss->ifname, 0); + return wpa_driver_capwap_if_remove(priv, WPA_IF_AP_VLAN, + name); + } +} + +void AC_handle_eapol(struct wpa_driver_capwap_data *drv, u8 *buf, int len){ + u8 sa[6]; + + int hlen = GetEapol_Frame(sa, buf, len); + //stampa_mac("AC eapol: " ,sa); + + drv_event_eapol_rx(drv->ctx, sa, buf + hlen, len - hlen); +} + + + +static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) +{ + wpa_printf(MSG_DEBUG, "handle_eapol %d\n",sock); + struct wpa_driver_capwap_data *drv = eloop_ctx; + struct sockaddr_ll lladdr; + unsigned char buf[3000]; + int len; + socklen_t fromlen = sizeof(lladdr); + + len = recvfrom(sock, buf, sizeof(buf), 0, + (struct sockaddr *)&lladdr, &fromlen); + + return; + if (len < 0) { + wpa_printf(MSG_ERROR, "recv"); + return; + } + + wpa_printf(MSG_DEBUG, "LOCALE"); + stampa_frame(buf,len); + + wpa_printf(MSG_DEBUG, "%d,%d", len,have_ifidx(drv, lladdr.sll_ifindex)); + + //stampa_mac(" EAPOL MAC: ",lladdr.sll_addr); + drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len); +} + + +static int i802_check_bridge(struct wpa_driver_capwap_data *drv, + struct i802_bss *bss, + const char *brname, const char *ifname) +{ + wpa_printf(MSG_DEBUG, " 7.i802_check_bridge\n"); + int ifindex; + char in_br[IFNAMSIZ]; + + os_strlcpy(bss->brname, brname, IFNAMSIZ); + ifindex = if_nametoindex(brname); + if (ifindex == 0) { + /* + * Bridge was configured, but the bridge device does + * not exist. Try to add it now. + */ + if (linux_br_fake_add(drv->global->ioctl_sock, brname) < 0) { + wpa_printf(MSG_ERROR, "capwap: Failed to add the " + "bridge interface %s: %s", + brname, strerror(errno)); + return -1; + } + bss->added_bridge = 1; + add_ifidx(drv, if_nametoindex(brname)); + } + + if (linux_br_fake_get(in_br, ifname) == 0) { + if (os_strcmp(in_br, brname) == 0) + return 0; /* already in the bridge */ + + wpa_printf(MSG_DEBUG, "capwap: Removing interface %s from " + "bridge %s", ifname, in_br); + if (linux_br_fake_del_if(drv->global->ioctl_sock, in_br, ifname) < + 0) { + wpa_printf(MSG_ERROR, "capwap: Failed to " + "remove interface %s from bridge " + "%s: %s", + ifname, brname, strerror(errno)); + return -1; + } + } + + wpa_printf(MSG_DEBUG, "capwap: Adding interface %s into bridge %s", + ifname, brname); + if (linux_br_fake_add_if(drv->global->ioctl_sock, brname, ifname) < 0) { + wpa_printf(MSG_ERROR, "capwap: Failed to add interface %s " + "into bridge %s: %s", + ifname, brname, strerror(errno)); + return -1; + } + bss->added_if_into_bridge = 1; + + return 0; +} + +static void *i802_init(struct hostapd_data *hapd, + struct wpa_init_params *params) +{ + wpa_printf(MSG_DEBUG, " 1.i802_init\n"); + struct wpa_driver_capwap_data *drv; + struct i802_bss *bss; + size_t i; + char brname[IFNAMSIZ]; + int ifindex, br_ifindex; + int br_added = 0; + + bss = wpa_driver_capwap_init(hapd, params->ifname, + params->global_priv); + if (bss == NULL) + return NULL; + + drv = bss->drv; + drv->nlmode = NL80211_IFTYPE_AP; + drv->eapol_sock = -1; + + if (linux_br_fake_get(brname, params->ifname) == 0) { + wpa_printf(MSG_DEBUG, "capwap: Interface %s is in bridge %s", + params->ifname, brname); + br_ifindex = if_nametoindex(brname); + } else { + brname[0] = '\0'; + br_ifindex = 0; + } + + for (i = 0; i < params->num_bridge; i++) { + if (params->bridge[i]) { + ifindex = if_nametoindex(params->bridge[i]); + if (ifindex) + add_ifidx(drv, ifindex); + if (ifindex == br_ifindex) + br_added = 1; + } + } + if (!br_added && br_ifindex && + (params->num_bridge == 0 || !params->bridge[0])) + add_ifidx(drv, br_ifindex); + + /* start listening for EAPOL on the default AP interface */ + add_ifidx(drv, drv->ifindex); + + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, bss->ifname, 0)) + goto failed; + + if (params->bssid) { + if (linux_set_fake_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + params->bssid)) + goto failed; + } + + if (wpa_driver_capwap_set_mode(bss, drv->nlmode)) { + wpa_printf(MSG_ERROR, "capwap: Failed to set interface %s " + "into AP mode", bss->ifname); + goto failed; + } + + if (params->num_bridge && params->bridge[0] && + i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) + goto failed; + + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) + goto failed; + + drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); + if (drv->eapol_sock < 0) { + perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); + goto failed; + } + + if (linux_get_fake_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->own_addr)) goto failed; + + generic_ac_info.pseudo_interface = params->ifname; + void (*pointer_inject_frame)(void *, unsigned char*,int); + pointer_inject_frame = AC_inject_frame_in_hostapd; + + generic_ac_info.fd_ipc = start_ipc(drv->ctx, pointer_inject_frame); + + capability_get_mac(generic_ac_info.own_mac_addr); + memcpy(drv->addr,generic_ac_info.own_mac_addr, ETH_ALEN); + memcpy(params->own_addr,generic_ac_info.own_mac_addr, ETH_ALEN); + if(generic_ac_info.fd_ipc<=0){ + wpa_printf(MSG_ERROR, "Error: start_ipc"); + return; + } + + return bss; + +failed: + wpa_driver_capwap_deinit(bss); + return NULL; +} + + +static void i802_deinit(void *priv) +{ + struct i802_bss *bss = priv; + ipc_send_DEL_WLAN(generic_ac_info.fd_ipc); + end_ipc(generic_ac_info.fd_ipc); + wpa_driver_capwap_deinit(bss); +} + +#endif /* HOSTAPD */ + + +static enum capwap_iftype wpa_driver_capwap_if_type( + enum wpa_driver_if_type type) +{ + switch (type) { + case WPA_IF_STATION: + return NL80211_IFTYPE_STATION; + case WPA_IF_P2P_CLIENT: + case WPA_IF_P2P_GROUP: + return NL80211_IFTYPE_P2P_CLIENT; + case WPA_IF_AP_VLAN: + return NL80211_IFTYPE_AP_VLAN; + case WPA_IF_AP_BSS: + return NL80211_IFTYPE_AP; + case WPA_IF_P2P_GO: + return NL80211_IFTYPE_P2P_GO; + } + return -1; +} + + +#ifdef CONFIG_P2P + +static int capwap_addr_in_use(struct capwap_global *global, const u8 *addr) +{ + struct wpa_driver_capwap_data *drv; + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_capwap_data, list) { + if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0) + return 1; + } + return 0; +} + + +static int capwap_p2p_interface_addr(struct wpa_driver_capwap_data *drv, + u8 *new_addr) +{ + unsigned int idx; + + if (!drv->global) + return -1; + + os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN); + for (idx = 0; idx < 64; idx++) { + new_addr[0] = drv->first_bss.addr[0] | 0x02; + new_addr[0] ^= idx << 2; + if (!capwap_addr_in_use(drv->global, new_addr)) + break; + } + if (idx == 64) + return -1; + + wpa_printf(MSG_DEBUG, "capwap: Assigned new P2P Interface Address " + MACSTR, MAC2STR(new_addr)); + + return 0; +} + +#endif /* CONFIG_P2P */ + + +static int wpa_driver_capwap_if_add(void *priv, enum wpa_driver_if_type type, + const char *ifname, const u8 *addr, + void *bss_ctx, void **drv_priv, + char *force_ifname, u8 *if_addr, + const char *bridge) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + int ifidx; +#ifdef HOSTAPD + struct i802_bss *new_bss = NULL; + + if (type == WPA_IF_AP_BSS) { + new_bss = os_zalloc(sizeof(*new_bss)); + if (new_bss == NULL) + return -1; + } +#endif /* HOSTAPD */ + + if (addr) + os_memcpy(if_addr, addr, ETH_ALEN); + ifidx = capwap_create_iface(drv, ifname, + wpa_driver_capwap_if_type(type), addr, + 0); + if (ifidx < 0) { +#ifdef HOSTAPD + os_free(new_bss); +#endif /* HOSTAPD */ + return -1; + } + + if (!addr && + linux_get_fake_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + if_addr) < 0) { + capwap_remove_iface(drv, ifidx); + return -1; + } + +#ifdef CONFIG_P2P + if (!addr && + (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || + type == WPA_IF_P2P_GO)) { + /* Enforce unique P2P Interface Address */ + u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN]; + + if (linux_get_fake_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + own_addr) < 0 || + linux_get_fake_ifhwaddr(drv->global->ioctl_sock, ifname, + new_addr) < 0) { + capwap_remove_iface(drv, ifidx); + return -1; + } + if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) { + wpa_printf(MSG_DEBUG, "capwap: Allocate new address " + "for P2P group interface"); + if (capwap_p2p_interface_addr(drv, new_addr) < 0) { + capwap_remove_iface(drv, ifidx); + return -1; + } + if (linux_set_fake_ifhwaddr(drv->global->ioctl_sock, ifname, + new_addr) < 0) { + capwap_remove_iface(drv, ifidx); + return -1; + } + } + os_memcpy(if_addr, new_addr, ETH_ALEN); + } +#endif /* CONFIG_P2P */ + +#ifdef HOSTAPD + if (bridge && + i802_check_bridge(drv, new_bss, bridge, ifname) < 0) { + wpa_printf(MSG_ERROR, "capwap: Failed to add the new " + "interface %s to a bridge %s", ifname, bridge); + capwap_remove_iface(drv, ifidx); + os_free(new_bss); + return -1; + } + + if (type == WPA_IF_AP_BSS) { + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, ifname, 1)) + { + capwap_remove_iface(drv, ifidx); + os_free(new_bss); + return -1; + } + os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); + os_memcpy(new_bss->addr, if_addr, ETH_ALEN); + new_bss->ifindex = ifidx; + new_bss->drv = drv; + new_bss->next = drv->first_bss.next; + new_bss->freq = drv->first_bss.freq; + new_bss->ctx = bss_ctx; + drv->first_bss.next = new_bss; + if (drv_priv) + *drv_priv = new_bss; + capwap_init_bss(new_bss); + + /* Subscribe management frames for this WPA_IF_AP_BSS */ + if (capwap_setup_ap(new_bss)) + return -1; + } +#endif /* HOSTAPD */ + + if (drv->global) + drv->global->if_add_ifindex = ifidx; + + return 0; +} + + +static int wpa_driver_capwap_if_remove(struct i802_bss *bss, + enum wpa_driver_if_type type, + const char *ifname) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + int ifindex = if_nametoindex(ifname); + + wpa_printf(MSG_DEBUG, "capwap: %s(type=%d ifname=%s) ifindex=%d", + __func__, type, ifname, ifindex); + if (ifindex <= 0) + return -1; + + capwap_remove_iface(drv, ifindex); + +#ifdef HOSTAPD + if (type != WPA_IF_AP_BSS) + return 0; + + if (bss->added_if_into_bridge) { + if (linux_br_fake_del_if(drv->global->ioctl_sock, bss->brname, + bss->ifname) < 0) + wpa_printf(MSG_INFO, "capwap: Failed to remove " + "interface %s from bridge %s: %s", + bss->ifname, bss->brname, strerror(errno)); + } + if (bss->added_bridge) { + if (linux_br_fake_del(drv->global->ioctl_sock, bss->brname) < 0) + wpa_printf(MSG_INFO, "capwap: Failed to remove " + "bridge %s: %s", + bss->brname, strerror(errno)); + } + + if (bss != &drv->first_bss) { + struct i802_bss *tbss; + + for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { + if (tbss->next == bss) { + tbss->next = bss->next; + /* Unsubscribe management frames */ + capwap_teardown_ap(bss); + capwap_destroy_bss(bss); + os_free(bss); + bss = NULL; + break; + } + } + if (bss) + wpa_printf(MSG_INFO, "capwap: %s - could not find " + "BSS %p in the list", __func__, bss); + } +#endif /* HOSTAPD */ + + return 0; +} + + +static int cookie_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + u64 *cookie = arg; + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (tb[NL80211_ATTR_COOKIE]) + *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + return NL_SKIP; +} + + +static int capwap_send_frame_cmd(struct i802_bss *bss, + unsigned int freq, unsigned int wait, + const u8 *buf, size_t buf_len, + u64 *cookie_out, int no_cck, int no_ack, + int offchanok) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + u64 cookie; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "capwap: CMD_FRAME freq=%u wait=%u no_cck=%d " + "no_ack=%d offchanok=%d", + freq, wait, no_cck, no_ack, offchanok); + capwap_cmd(drv, msg, 0, NL80211_CMD_FRAME); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (wait) + NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); + if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) + NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + if (no_cck) + NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); + if (no_ack) + NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK); + + NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf); + + cookie = 0; + ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Frame command failed: ret=%d " + "(%s) (freq=%u wait=%u)", ret, strerror(-ret), + freq, wait); + goto nla_put_failure; + } + wpa_printf(MSG_DEBUG, "capwap: Frame TX command accepted%s; " + "cookie 0x%llx", no_ack ? " (no ACK)" : "", + (long long unsigned int) cookie); + + if (cookie_out) + *cookie_out = no_ack ? (u64) -1 : cookie; + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_capwap_send_action(struct i802_bss *bss, + unsigned int freq, + unsigned int wait_time, + const u8 *dst, const u8 *src, + const u8 *bssid, + const u8 *data, size_t data_len, + int no_cck) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + int ret = -1; + u8 *buf; + struct ieee80211_hdr *hdr; + + wpa_printf(MSG_DEBUG, "capwap: Send Action frame (ifindex=%d, " + "freq=%u MHz wait=%d ms no_cck=%d)", + drv->ifindex, freq, wait_time, no_cck); + + buf = os_zalloc(24 + data_len); + if (buf == NULL) + return ret; + os_memcpy(buf + 24, data, data_len); + hdr = (struct ieee80211_hdr *) buf; + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); + os_memcpy(hdr->addr1, dst, ETH_ALEN); + os_memcpy(hdr->addr2, src, ETH_ALEN); + os_memcpy(hdr->addr3, bssid, ETH_ALEN); + + if (is_ap_interface(drv->nlmode)) + ret = wpa_driver_capwap_send_mlme(bss, buf, 24 + data_len, + 0, freq, no_cck, 1, + wait_time); + else + ret = capwap_send_frame_cmd(bss, freq, wait_time, buf, + 24 + data_len, + &drv->send_action_cookie, + no_cck, 0, 1); + + os_free(buf); + return ret; +} + + +static void wpa_driver_capwap_send_action_cancel_wait(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return; + + wpa_printf(MSG_DEBUG, "capwap: Cancel TX frame wait: cookie=0x%llx", + (long long unsigned int) drv->send_action_cookie); + capwap_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) + wpa_printf(MSG_DEBUG, "capwap: wait cancel failed: ret=%d " + "(%s)", ret, strerror(-ret)); + + nla_put_failure: + nlmsg_free(msg); +} + + +static int wpa_driver_capwap_remain_on_channel(void *priv, unsigned int freq, + unsigned int duration) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + u64 cookie; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); + + cookie = 0; + ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); + msg = NULL; + if (ret == 0) { + wpa_printf(MSG_DEBUG, "capwap: Remain-on-channel cookie " + "0x%llx for freq=%u MHz duration=%u", + (long long unsigned int) cookie, freq, duration); + drv->remain_on_chan_cookie = cookie; + drv->pending_remain_on_chan = 1; + return 0; + } + wpa_printf(MSG_DEBUG, "capwap: Failed to request remain-on-channel " + "(freq=%d duration=%u): %d (%s)", + freq, duration, ret, strerror(-ret)); +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int wpa_driver_capwap_cancel_remain_on_channel(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + if (!drv->pending_remain_on_chan) { + wpa_printf(MSG_DEBUG, "capwap: No pending remain-on-channel " + "to cancel"); + return -1; + } + + wpa_printf(MSG_DEBUG, "capwap: Cancel remain-on-channel with cookie " + "0x%llx", + (long long unsigned int) drv->remain_on_chan_cookie); + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret == 0) + return 0; + wpa_printf(MSG_DEBUG, "capwap: Failed to cancel remain-on-channel: " + "%d (%s)", ret, strerror(-ret)); +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int wpa_driver_capwap_probe_req_report(struct i802_bss *bss, int report) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + + if (!report) { + if (bss->nl_preq && drv->device_ap_sme && + is_ap_interface(drv->nlmode)) { + /* + * Do not disable Probe Request reporting that was + * enabled in capwap_setup_ap(). + */ + wpa_printf(MSG_DEBUG, "capwap: Skip disabling of " + "Probe Request reporting nl_preq=%p while " + "in AP mode", bss->nl_preq); + } else if (bss->nl_preq) { + wpa_printf(MSG_DEBUG, "capwap: Disable Probe Request " + "reporting nl_preq=%p", bss->nl_preq); + eloop_unregister_read_sock( + nl_socket_get_fd(bss->nl_preq)); + nl_destroy_cache(&bss->nl_preq_cache); + nl_destroy_handles(&bss->nl_preq); + } + return 0; + } + + if (bss->nl_preq) { + wpa_printf(MSG_DEBUG, "capwap: Probe Request reporting " + "already on! nl_preq=%p", bss->nl_preq); + return 0; + } + + bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq"); + bss->nl_preq_cache = nl_create_cache(bss->nl_preq); + if (bss->nl_preq == NULL) + return -1; + wpa_printf(MSG_DEBUG, "capwap: Enable Probe Request " + "reporting nl_preq=%p", bss->nl_preq); + + if (capwap_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_PROBE_REQ << 4), + NULL, 0) < 0) + goto out_err; + + eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq), + wpa_driver_capwap_event_receive, bss->nl_cb, + bss->nl_preq); + + return 0; + + out_err: + nl_destroy_cache(&bss->nl_preq_cache); + nl_destroy_handles(&bss->nl_preq); + return -1; +} + + +static int capwap_disable_11b_rates(struct wpa_driver_capwap_data *drv, + int ifindex, int disabled) +{ + struct nl_msg *msg; + struct nlattr *bands, *band; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + + bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); + if (!bands) + goto nla_put_failure; + + /* + * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything + * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS + * rates. All 5 GHz rates are left enabled. + */ + band = nla_nest_start(msg, NL80211_BAND_2GHZ); + if (!band) + goto nla_put_failure; + if (disabled) { + NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + } + nla_nest_end(msg, band); + + nla_nest_end(msg, bands); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "capwap: Set TX rates failed: ret=%d " + "(%s)", ret, strerror(-ret)); + } else + drv->disabled_11b_rates = disabled; + + return ret; + +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int wpa_driver_capwap_deinit_ap(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + if (!is_ap_interface(drv->nlmode)) + return -1; + wpa_driver_capwap_del_beacon(drv); + return wpa_driver_capwap_set_mode(priv, NL80211_IFTYPE_STATION); +} + +static int wpa_driver_capwap_deinit_p2p_cli(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT) + return -1; + return wpa_driver_capwap_set_mode(priv, NL80211_IFTYPE_STATION); +} + + +static void wpa_driver_capwap_resume(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + if (linux_set_fake_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { + wpa_printf(MSG_DEBUG, "capwap: Failed to set interface up on " + "resume event"); + } +} + + +static int capwap_send_ft_action(void *priv, u8 action, const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + int ret; + u8 *data, *pos; + size_t data_len; + const u8 *own_addr = bss->addr; + + if (action != 1) { + wpa_printf(MSG_ERROR, "capwap: Unsupported send_ft_action " + "action %d", action); + return -1; + } + + /* + * Action frame payload: + * Category[1] = 6 (Fast BSS Transition) + * Action[1] = 1 (Fast BSS Transition Request) + * STA Address + * Target AP Address + * FT IEs + */ + + data_len = 2 + 2 * ETH_ALEN + ies_len; + data = os_malloc(data_len); + if (data == NULL) + return -1; + pos = data; + *pos++ = 0x06; /* FT Action category */ + *pos++ = action; + os_memcpy(pos, own_addr, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, target_ap, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, ies, ies_len); + + ret = wpa_driver_capwap_send_action(bss, drv->assoc_freq, 0, + drv->bssid, own_addr, drv->bssid, + data, data_len, 0); + os_free(data); + + return ret; +} + + +static int capwap_signal_monitor(void *priv, int threshold, int hysteresis) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg, *cqm = NULL; + int ret = -1; + + wpa_printf(MSG_DEBUG, "capwap: Signal monitor threshold=%d " + "hysteresis=%d", threshold, hysteresis); + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_CQM); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + cqm = nlmsg_alloc(); + if (cqm == NULL) + goto nla_put_failure; + + NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold); + NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis); + if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0) + goto nla_put_failure; + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + +nla_put_failure: + nlmsg_free(cqm); + nlmsg_free(msg); + return ret; +} + + +static int capwap_signal_poll(void *priv, struct wpa_signal_info *si) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + int res; + + os_memset(si, 0, sizeof(*si)); + res = capwap_get_link_signal(drv, si); + if (res != 0) + return res; + + return capwap_get_link_noise(drv, si); +} + + +static int wpa_driver_capwap_shared_freq(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct wpa_driver_capwap_data *driver; + int freq = 0; + + /* + * If the same PHY is in connected state with some other interface, + * then retrieve the assoc freq. + */ + wpa_printf(MSG_DEBUG, "capwap: Get shared freq for PHY %s", + drv->phyname); + + dl_list_for_each(driver, &drv->global->interfaces, + struct wpa_driver_capwap_data, list) { + if (drv == driver || + os_strcmp(drv->phyname, driver->phyname) != 0 || + !driver->associated) + continue; + + wpa_printf(MSG_DEBUG, "capwap: Found a match for PHY %s - %s " + MACSTR, + driver->phyname, driver->first_bss.ifname, + MAC2STR(driver->first_bss.addr)); + if (is_ap_interface(driver->nlmode)) + freq = driver->first_bss.freq; + else + freq = capwap_get_assoc_freq(driver); + wpa_printf(MSG_DEBUG, "capwap: Shared freq for PHY %s: %d", + drv->phyname, freq); + } + + if (!freq) + wpa_printf(MSG_DEBUG, "capwap: No shared interface for " + "PHY (%s) in associated state", drv->phyname); + + return freq; +} + + +static int capwap_send_frame(void *priv, const u8 *data, size_t data_len, + int encrypt) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_send_frame(bss, data, data_len, encrypt, 0, + 0, 0, 0, 0); +} + + +static int capwap_set_param(void *priv, const char *param) +{ + wpa_printf(MSG_DEBUG, "capwap: driver param='%s'", param); + if (param == NULL) + return 0; + +#ifdef CONFIG_P2P + if (os_strstr(param, "use_p2p_group_interface=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + + wpa_printf(MSG_DEBUG, "capwap: Use separate P2P group " + "interface"); + drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; + drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; + } +#endif /* CONFIG_P2P */ + + return 0; +} + + +static void * capwap_global_init(void) +{ + wpa_printf(MSG_DEBUG," 1.capwap_global_init\n"); + struct capwap_global *global; + struct netlink_config *cfg; + + global = os_zalloc(sizeof(*global)); + if (global == NULL) + return NULL; + global->ioctl_sock = -1; + dl_list_init(&global->interfaces); + global->if_add_ifindex = -1; + + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto err; + + cfg->ctx = global; + cfg->newlink_cb = wpa_driver_capwap_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_capwap_event_rtm_dellink; + global->netlink = netlink_fake_init(cfg); + if (global->netlink == NULL) { + os_free(cfg); + goto err; + } + + if (wpa_driver_capwap_init_nl_global(global) < 0) + goto err; + + global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (global->ioctl_sock < 0) { + perror("socket(PF_INET,SOCK_DGRAM)"); + goto err; + } + + return global; + +err: + capwap_global_deinit(global); + return NULL; +} + + +static void capwap_global_deinit(void *priv) +{ + struct capwap_global *global = priv; + if (global == NULL) + return; + if (!dl_list_empty(&global->interfaces)) { + wpa_printf(MSG_ERROR, "capwap: %u interface(s) remain at " + "capwap_global_deinit", + dl_list_len(&global->interfaces)); + } + + if (global->netlink) + netlink_deinit(global->netlink); + if (global->capwap) + genl_family_put(global->capwap); + + + nl_destroy_cache(&global->nl_cache); + nl_destroy_handles(&global->nl); + + if (global->nl_event) { + eloop_unregister_read_sock( + nl_socket_get_fd(global->nl_event)); + nl_destroy_cache(&global->nl_event_cache); + nl_destroy_handles(&global->nl_event); + } + + nl_cb_put(global->nl_cb); + + if (global->ioctl_sock >= 0) + close(global->ioctl_sock); + + os_free(global); +} + + +static const char * capwap_get_radio_name(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + return drv->phyname; +} + + +static int capwap_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, + const u8 *pmkid) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(bss->drv, msg, 0, cmd); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + if (pmkid) + NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid); + if (bssid) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + + return send_and_recv_msgs(bss->drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int capwap_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) +{ + struct i802_bss *bss = priv; + wpa_printf(MSG_DEBUG, "capwap: Add PMKID for " MACSTR, MAC2STR(bssid)); + return capwap_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid); +} + + +static int capwap_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) +{ + struct i802_bss *bss = priv; + wpa_printf(MSG_DEBUG, "capwap: Delete PMKID for " MACSTR, + MAC2STR(bssid)); + return capwap_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid); +} + + +static int capwap_flush_pmkid(void *priv) +{ + struct i802_bss *bss = priv; + wpa_printf(MSG_DEBUG, "capwap: Flush PMKIDs"); + return capwap_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL); +} + + +static void capwap_set_rekey_info(void *priv, const u8 *kek, const u8 *kck, + const u8 *replay_ctr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nlattr *replay_nested; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return; + + capwap_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); + if (!replay_nested) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek); + NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck); + NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN, + replay_ctr); + + nla_nest_end(msg, replay_nested); + + send_and_recv_msgs(drv, msg, NULL, NULL); + return; + nla_put_failure: + nlmsg_free(msg); +} + + +static void capwap_send_null_frame(struct i802_bss *bss, const u8 *own_addr, + const u8 *addr, int qos) +{ + /* send data frame to poll STA and check whether + * this frame is ACKed */ + struct { + struct ieee80211_hdr hdr; + u16 qos_ctl; + } STRUCT_PACKED nulldata; + size_t size; + + /* Send data frame to poll STA and check whether this frame is ACKed */ + + os_memset(&nulldata, 0, sizeof(nulldata)); + + if (qos) { + nulldata.hdr.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_QOS_NULL); + size = sizeof(nulldata); + } else { + nulldata.hdr.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_NULLFUNC); + size = sizeof(struct ieee80211_hdr); + } + + nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); + os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); + os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + + if (wpa_driver_capwap_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0, + 0, 0) < 0) + wpa_printf(MSG_DEBUG, "capwap_send_null_frame: Failed to " + "send poll frame"); +} + +static void capwap_poll_client(void *priv, const u8 *own_addr, const u8 *addr, + int qos) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + + if (!drv->poll_command_supported) { + capwap_send_null_frame(bss, own_addr, addr, qos); + return; + } + + msg = nlmsg_alloc(); + if (!msg) + return; + + capwap_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + send_and_recv_msgs(drv, msg, NULL, NULL); + return; + nla_put_failure: + nlmsg_free(msg); +} + + +static int capwap_set_power_save(struct i802_bss *bss, int enabled) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, + enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED); + return send_and_recv_msgs(bss->drv, msg, NULL, NULL); +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int capwap_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps, + int ctwindow) +{ + struct i802_bss *bss = priv; + + wpa_printf(MSG_DEBUG, "capwap: set_p2p_powersave (legacy_ps=%d " + "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow); + + if (opp_ps != -1 || ctwindow != -1) + return -1; /* Not yet supported */ + + if (legacy_ps == -1) + return 0; + if (legacy_ps != 0 && legacy_ps != 1) + return -1; /* Not yet supported */ + + return capwap_set_power_save(bss, legacy_ps); +} + + +#ifdef CONFIG_TDLS + +static int capwap_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, + u8 dialog_token, u16 status_code, + const u8 *buf, size_t len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + if (!dst) + return -EINVAL; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); + NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); + NLA_PUT(msg, NL80211_ATTR_IE, len, buf); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + +static int capwap_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer) +{ + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + struct nl_msg *msg; + enum nl80211_tdls_operation capwap_oper; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) + return -EOPNOTSUPP; + + switch (oper) { + case TDLS_DISCOVERY_REQ: + capwap_oper = NL80211_TDLS_DISCOVERY_REQ; + break; + case TDLS_SETUP: + capwap_oper = NL80211_TDLS_SETUP; + break; + case TDLS_TEARDOWN: + capwap_oper = NL80211_TDLS_TEARDOWN; + break; + case TDLS_ENABLE_LINK: + capwap_oper = NL80211_TDLS_ENABLE_LINK; + break; + case TDLS_DISABLE_LINK: + capwap_oper = NL80211_TDLS_DISABLE_LINK; + break; + case TDLS_ENABLE: + return 0; + case TDLS_DISABLE: + return 0; + default: + return -EINVAL; + } + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + capwap_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER); + NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, capwap_oper); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +#endif /* CONFIG TDLS */ + +void AC_inject_frame_in_hostapd(void *priv, u8 *buf, int len){ + + struct i802_bss *bss = priv; + struct wpa_driver_capwap_data *drv = bss->drv; + + int ret; + int datarate = 0, ssi_signal = 0; + int failed = 0, rxflags = 0; + + + if (len < 24) { + perror("recv"); + return; + } + + int type = AC_get_Type(buf ,len ); + + + if( type == WLAN_FC_TYPE_DATA ){ + + if( isEAPOL_Frame(buf, len) ){ + if(isCallBackFrame(buf,len,generic_ac_info.own_mac_addr)) { + wpa_printf(MSG_DEBUG, "EAPOL Data Frame 4 (%d)\n",len); + handle_tx_callback(drv->ctx, buf ,len , !failed); + }else{ + wpa_printf(MSG_DEBUG, "EAPOL Data Frame 6 (%d)\n",len); + AC_handle_eapol(drv,buf,len); + } + }else{ + handle_frame(drv, buf , len , datarate, ssi_signal); + } + + int stype = AC_get_SubType(buf ,len ); + + /* Per ora scarto i pacchetti PROBE REQUEST */ + if(stype == WLAN_FC_STYPE_PROBE_REQ) { + return; + } + + if(isCallBackFrame(buf,len,generic_ac_info.own_mac_addr)) { + handle_tx_callback(drv->ctx, buf ,len , !failed); + + if( stype == WLAN_FC_STYPE_ASSOC_RESP || stype == WLAN_FC_STYPE_REASSOC_RESP ){ + ipc_send_add_station(generic_ac_info.fd_ipc,buf,len); + } + }else{ + handle_frame(drv, buf , len , datarate, ssi_signal); + + if( stype == WLAN_FC_STYPE_DISASSOC ){ + ipc_send_del_station(generic_ac_info.fd_ipc, buf, len); + } + } + }else{ + wpa_printf(MSG_ERROR,"Error: invalid/control 802.11 Type "); + } + +} + +#ifdef ANDROID + +typedef struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +static int drv_errors = 0; + +static void wpa_driver_send_hang_msg(struct wpa_driver_capwap_data *drv) +{ + drv_errors++; + if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv_errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } +} + + +static int android_priv_cmd(struct i802_bss *bss, const char *cmd) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + char buf[MAX_DRV_CMD_SIZE]; + int ret; + + os_memset(&ifr, 0, sizeof(ifr)); + os_memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + os_memset(buf, 0, sizeof(buf)); + os_strlcpy(buf, cmd, sizeof(buf)); + + priv_cmd.buf = buf; + priv_cmd.used_len = sizeof(buf); + priv_cmd.total_len = sizeof(buf); + ifr.ifr_data = &priv_cmd; + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s: failed to issue private commands", + __func__); + wpa_driver_send_hang_msg(drv); + return ret; + } + + drv_errors = 0; + return 0; +} + + +static int android_pno_start(struct i802_bss *bss, + struct wpa_driver_scan_params *params) +{ + struct wpa_driver_capwap_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + int ret = 0, i = 0, bp; + char buf[WEXT_PNO_MAX_COMMAND_SIZE]; + + bp = WEXT_PNOSETUP_HEADER_SIZE; + os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); + buf[bp++] = WEXT_PNO_TLV_PREFIX; + buf[bp++] = WEXT_PNO_TLV_VERSION; + buf[bp++] = WEXT_PNO_TLV_SUBVERSION; + buf[bp++] = WEXT_PNO_TLV_RESERVED; + + while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { + /* Check that there is enough space needed for 1 more SSID, the + * other sections and null termination */ + if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) + break; + wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + buf[bp++] = WEXT_PNO_SSID_SECTION; + buf[bp++] = params->ssids[i].ssid_len; + os_memcpy(&buf[bp], params->ssids[i].ssid, + params->ssids[i].ssid_len); + bp += params->ssids[i].ssid_len; + i++; + } + + buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", + WEXT_PNO_SCAN_INTERVAL); + bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; + + buf[bp++] = WEXT_PNO_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_REPEAT); + bp += WEXT_PNO_REPEAT_LENGTH; + + buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", + WEXT_PNO_MAX_REPEAT); + bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; + + memset(&ifr, 0, sizeof(ifr)); + memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + priv_cmd.buf = buf; + priv_cmd.used_len = bp; + priv_cmd.total_len = bp; + ifr.ifr_data = &priv_cmd; + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", + ret); + wpa_driver_send_hang_msg(drv); + return ret; + } + + drv_errors = 0; + + return android_priv_cmd(bss, "PNOFORCE 1"); +} + + +static int android_pno_stop(struct i802_bss *bss) +{ + return android_priv_cmd(bss, "PNOFORCE 0"); +} + +#endif /* ANDROID */ + + +static int driver_capwap_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_set_key(ifname, bss, alg, addr, key_idx, + set_tx, seq, seq_len, key, key_len); +} + + +static int driver_capwap_scan2(void *priv, + struct wpa_driver_scan_params *params) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_scan(bss, params); +} + + +static int driver_capwap_deauthenticate(void *priv, const u8 *addr, + int reason_code) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_deauthenticate(bss, addr, reason_code); +} + + +static int driver_capwap_authenticate(void *priv, + struct wpa_driver_auth_params *params) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_authenticate(bss, params); +} + + +static void driver_capwap_deinit(void *priv) +{ + struct i802_bss *bss = priv; + wpa_driver_capwap_deinit(bss); +} + + +static int driver_capwap_if_remove(void *priv, enum wpa_driver_if_type type, + const char *ifname) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_if_remove(bss, type, ifname); +} + + +static int driver_capwap_send_mlme(void *priv, const u8 *data, + size_t data_len, int noack) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_send_mlme(bss, data, data_len, noack, + 0, 0, 0, 0); +} + + +static int driver_capwap_sta_remove(void *priv, const u8 *addr) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_sta_remove(bss, addr); +} + + +#if defined(HOSTAPD) || defined(CONFIG_AP) +static int driver_capwap_set_sta_vlan(void *priv, const u8 *addr, + const char *ifname, int vlan_id) +{ + struct i802_bss *bss = priv; + return i802_set_sta_vlan(bss, addr, ifname, vlan_id); +} +#endif /* HOSTAPD || CONFIG_AP */ + + +static int driver_capwap_read_sta_data(void *priv, + struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct i802_bss *bss = priv; + return i802_read_sta_data(bss, data, addr); +} + + +static int driver_capwap_send_action(void *priv, unsigned int freq, + unsigned int wait_time, + const u8 *dst, const u8 *src, + const u8 *bssid, + const u8 *data, size_t data_len, + int no_cck) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_send_action(bss, freq, wait_time, dst, src, + bssid, data, data_len, no_cck); +} + + +static int driver_capwap_probe_req_report(void *priv, int report) +{ + struct i802_bss *bss = priv; + return wpa_driver_capwap_probe_req_report(bss, report); +} + + +const struct wpa_driver_ops wpa_driver_capwap_ops = { + .name = "capwap", + .desc = "Linux capwap/cfg80211", + .get_bssid = wpa_driver_capwap_get_bssid, + .get_ssid = wpa_driver_capwap_get_ssid, + .set_key = driver_capwap_set_key, + .scan2 = driver_capwap_scan2, + .sched_scan = wpa_driver_capwap_sched_scan, + .stop_sched_scan = wpa_driver_capwap_stop_sched_scan, + .get_scan_results2 = wpa_driver_capwap_get_scan_results, + .deauthenticate = driver_capwap_deauthenticate, + .authenticate = driver_capwap_authenticate, + .associate = wpa_driver_capwap_associate, + .global_init = capwap_global_init, + .global_deinit = capwap_global_deinit, + .init2 = wpa_driver_capwap_init, + .deinit = driver_capwap_deinit, + .get_capa = wpa_driver_capwap_get_capa, + .set_operstate = wpa_driver_capwap_set_operstate, + .set_supp_port = wpa_driver_capwap_set_supp_port, + .set_country = wpa_driver_capwap_set_country, + .set_ap = wpa_driver_capwap_set_ap, + .if_add = wpa_driver_capwap_if_add, + .if_remove = driver_capwap_if_remove, + .send_mlme = driver_capwap_send_mlme, + .get_hw_feature_data = wpa_driver_capwap_get_hw_feature_data, + .sta_add = wpa_driver_capwap_sta_add, + .sta_remove = driver_capwap_sta_remove, + .hapd_send_eapol = wpa_driver_capwap_hapd_send_eapol, + .sta_set_flags = wpa_driver_capwap_sta_set_flags, + //.inject_frame_in_hostapd = AC_inject_frame_in_hostapd, +#ifdef HOSTAPD + .hapd_init = i802_init, + .hapd_deinit = i802_deinit, + .set_wds_sta = i802_set_wds_sta, +#endif /* HOSTAPD */ +#if defined(HOSTAPD) || defined(CONFIG_AP) + .get_seqnum = i802_get_seqnum, + .flush = i802_flush, + .get_inact_sec = i802_get_inact_sec, + .sta_clear_stats = i802_sta_clear_stats, + .set_rts = i802_set_rts, + .set_frag = i802_set_frag, + .set_tx_queue_params = i802_set_tx_queue_params, + .set_sta_vlan = driver_capwap_set_sta_vlan, + .sta_deauth = i802_sta_deauth, + .sta_disassoc = i802_sta_disassoc, +#endif /* HOSTAPD || CONFIG_AP */ + .read_sta_data = driver_capwap_read_sta_data, + .set_freq = i802_set_freq, + .send_action = driver_capwap_send_action, + .send_action_cancel_wait = wpa_driver_capwap_send_action_cancel_wait, + .remain_on_channel = wpa_driver_capwap_remain_on_channel, + .cancel_remain_on_channel = + wpa_driver_capwap_cancel_remain_on_channel, + .probe_req_report = driver_capwap_probe_req_report, + .deinit_ap = wpa_driver_capwap_deinit_ap, + .deinit_p2p_cli = wpa_driver_capwap_deinit_p2p_cli, + .resume = wpa_driver_capwap_resume, + .send_ft_action = capwap_send_ft_action, + .signal_monitor = capwap_signal_monitor, + .signal_poll = capwap_signal_poll, + .send_frame = capwap_send_frame, + .shared_freq = wpa_driver_capwap_shared_freq, + .set_param = capwap_set_param, + .get_radio_name = capwap_get_radio_name, + .add_pmkid = capwap_add_pmkid, + .remove_pmkid = capwap_remove_pmkid, + .flush_pmkid = capwap_flush_pmkid, + .set_rekey_info = capwap_set_rekey_info, + .poll_client = capwap_poll_client, + .set_p2p_powersave = capwap_set_p2p_powersave, +#ifdef CONFIG_TDLS + .send_tdls_mgmt = capwap_send_tdls_mgmt, + .tdls_oper = capwap_tdls_oper, +#endif /* CONFIG_TDLS */ + .stop_ap = wpa_driver_capwap_stop_ap, +}; diff -purN hostapd-20130302/src/drivers/driver.h hostapd-20130302-linux/src/drivers/driver.h --- hostapd-20130302/src/drivers/driver.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/driver.h 2013-07-04 11:17:51.000000000 -0400 @@ -19,6 +19,7 @@ #define WPA_SUPPLICANT_DRIVER_VERSION 4 +#include "drivers/nl80211_copy.h" #include "common/defs.h" #define HOSTAPD_CHAN_DISABLED 0x00000001 @@ -363,6 +364,13 @@ struct wpa_driver_associate_params { */ int freq; + int beacon_interval; + int fixed_freq; + unsigned char rates[NL80211_MAX_SUPP_RATES]; + int mcast_rate; + int ht_set; + unsigned int htmode; + /** * bg_scan_period - Background scan period in seconds, 0 to disable * background scan, or -1 to indicate no change to default driver @@ -982,6 +990,8 @@ struct wpa_init_params { int use_pae_group_addr; char **bridge; size_t num_bridge; + char *tap; + char *br_name; u8 *own_addr; /* buffer for writing own MAC address */ }; @@ -1223,6 +1233,15 @@ struct wpa_driver_ops { */ int (*deauthenticate)(void *priv, const u8 *addr, int reason_code); + /** + * disassociate - Benunets added for capwap + */ + int (*disassociate)(void *priv, const u8 *addr, + int reason_code); + + int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates, + int mode); + /** * associate - Request driver to associate * @priv: private driver interface data @@ -2071,6 +2090,9 @@ struct wpa_driver_ops { */ int (*probe_req_report)(void *priv, int report); + + int (*stop_ap)(void *priv); + /** * deinit_ap - Deinitialize AP mode * @priv: Private driver interface data @@ -3726,8 +3748,8 @@ union wpa_event_data { * Driver wrapper code should call this function whenever an event is received * from the driver. */ -void wpa_supplicant_event(void *ctx, enum wpa_event_type event, - union wpa_event_data *data); +extern void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); /* diff -purN hostapd-20130302/src/drivers/driver_madwifi.c hostapd-20130302-linux/src/drivers/driver_madwifi.c --- hostapd-20130302/src/drivers/driver_madwifi.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/driver_madwifi.c 2013-07-04 11:17:51.000000000 -0400 @@ -453,7 +453,9 @@ wpa_driver_madwifi_set_key(const char *i memset(&wk, 0, sizeof(wk)); wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; + wk.ik_flags = IEEE80211_KEY_RECV; + if (set_tx) + wk.ik_flags |= IEEE80211_KEY_XMIT; if (addr == NULL || is_broadcast_ether_addr(addr)) { memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); wk.ik_keyix = key_idx; @@ -465,6 +467,20 @@ wpa_driver_madwifi_set_key(const char *i wk.ik_keylen = key_len; memcpy(wk.ik_keydata, key, key_len); +#ifdef WORDS_BIGENDIAN +#define WPA_KEY_RSC_LEN 8 + { + size_t i; + u8 tmp[WPA_KEY_RSC_LEN]; + os_memset(tmp, 0, sizeof(tmp)); + for (i = 0; i < seq_len; i++) + tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i]; + os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN); + } +#else /* WORDS_BIGENDIAN */ + os_memcpy(&wk.ik_keyrsc, seq, seq_len); +#endif /* WORDS_BIGENDIAN */ + ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" diff -purN hostapd-20130302/src/drivers/driver_nl80211.c hostapd-20130302-linux/src/drivers/driver_nl80211.c --- hostapd-20130302/src/drivers/driver_nl80211.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/driver_nl80211.c 2013-07-07 03:22:14.000000000 -0400 @@ -10,6 +10,7 @@ * See README for more details. */ + #include "includes.h" #include #include @@ -127,7 +128,7 @@ static struct nl_handle * nl_create_hand } if (genl_connect(handle)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " + wpa_printf(MSG_DEBUG, "nl80211: Failed to connect to generic " "netlink (%s)", dbg); nl80211_handle_destroy(handle); return NULL; @@ -218,7 +219,9 @@ struct wpa_driver_nl80211_data { int if_removed; int if_disabled; int ignore_if_down_event; +#ifdef CONFIG_RFKILL struct rfkill_data *rfkill; +#endif struct wpa_driver_capa capa; int has_capability; @@ -897,6 +900,10 @@ static void wpa_driver_nl80211_event_rtm return; } + if (ifi->ifi_family == AF_BRIDGE && + drv->nlmode != NL80211_IFTYPE_AP) + return; + wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " "(%s%s%s%s)", drv->operstate, ifi->ifi_flags, @@ -1004,6 +1011,10 @@ static void wpa_driver_nl80211_event_rtm attrlen = len; attr = (struct rtattr *) buf; + if (ifi->ifi_family == AF_BRIDGE && + drv->nlmode != NL80211_IFTYPE_AP) + return; + rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { @@ -2959,7 +2970,7 @@ static int wpa_driver_nl80211_init_nl(st return 0; } - +#ifdef CONFIG_RFKILL static void wpa_driver_nl80211_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); @@ -2982,6 +2993,7 @@ static void wpa_driver_nl80211_rfkill_un } /* rtnetlink ifup handler will report interface as enabled */ } +#endif /* CONFIG_RFKILL */ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv) @@ -3110,7 +3122,9 @@ static void * wpa_driver_nl80211_init(vo void *global_priv) { struct wpa_driver_nl80211_data *drv; +#ifdef CONFIG_RFKILL struct rfkill_config *rcfg; +#endif struct i802_bss *bss; if (global_priv == NULL) @@ -3129,6 +3143,12 @@ static void * wpa_driver_nl80211_init(vo drv->monitor_sock = -1; drv->eapol_tx_sock = -1; drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; + drv->nlmode = NL80211_IFTYPE_STATION; + +#ifdef HOSTAPD + drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); + drv->if_indices = drv->default_if_indices; +#endif if (wpa_driver_nl80211_init_nl(drv)) { os_free(drv); @@ -3140,6 +3160,7 @@ static void * wpa_driver_nl80211_init(vo nl80211_get_phy_name(drv); +#ifdef CONFIG_RFKILL rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL) goto failed; @@ -3152,6 +3173,7 @@ static void * wpa_driver_nl80211_init(vo wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available"); os_free(rcfg); } +#endif /* CONFIG_RFKILL */ if (wpa_driver_nl80211_finish_drv_init(drv)) goto failed; @@ -3441,22 +3463,19 @@ static void nl80211_mgmt_unsubscribe(str } +#ifdef CONFIG_RFKILL static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx) { wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); } - +#endif /* CONFIG_RFKILL */ static int -wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) +wpa_driver_nl80211_finish_drv_init_sta(struct wpa_driver_nl80211_data *drv, + int *send_rfkill_event) { struct i802_bss *bss = &drv->first_bss; - int send_rfkill_event = 0; - - drv->ifindex = if_nametoindex(bss->ifname); - drv->first_bss.ifindex = drv->ifindex; -#ifndef HOSTAPD /* * Make sure the interface starts up in station mode unless this is a * dynamically added interface (e.g., P2P) that was already configured @@ -3470,13 +3489,16 @@ wpa_driver_nl80211_finish_drv_init(struc } if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { +#ifdef CONFIG_RFKILL if (rfkill_is_blocked(drv->rfkill)) { wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " "interface '%s' due to rfkill", bss->ifname); drv->if_disabled = 1; - send_rfkill_event = 1; - } else { + *send_rfkill_event = 1; + } else +#endif + { wpa_printf(MSG_ERROR, "nl80211: Could not set " "interface '%s' UP", bss->ifname); return -1; @@ -3485,7 +3507,19 @@ wpa_driver_nl80211_finish_drv_init(struc netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT); -#endif /* HOSTAPD */ +} + +static int +wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) +{ + struct i802_bss *bss = &drv->first_bss; + int send_rfkill_event = 0; + + drv->ifindex = if_nametoindex(bss->ifname); + drv->first_bss.ifindex = drv->ifindex; + + if (drv->nlmode == NL80211_IFTYPE_STATION) + wpa_driver_nl80211_finish_drv_init_sta(drv, &send_rfkill_event); if (wpa_driver_nl80211_capa(drv)) return -1; @@ -3495,24 +3529,28 @@ wpa_driver_nl80211_finish_drv_init(struc return -1; if (send_rfkill_event) { +#ifdef CONFIG_RFKILL eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, drv, drv->ctx); +#endif } return 0; } -static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) +static int wpa_driver_nl80211_del_bss_beacon(struct i802_bss *bss) { + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; + bss->beacon_set = 0; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: @@ -3520,6 +3558,21 @@ static int wpa_driver_nl80211_del_beacon return -ENOBUFS; } +static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) +{ + struct i802_bss *bss; + + for (bss = &drv->first_bss; bss; bss = bss->next) + wpa_driver_nl80211_del_bss_beacon(bss); + + return 0; +} + +static int wpa_driver_nl80211_stop_ap(void *priv) +{ + struct i802_bss *bss = priv; + return wpa_driver_nl80211_del_beacon(bss->drv); +} /** * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface @@ -3582,7 +3635,9 @@ static void wpa_driver_nl80211_deinit(st netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, IF_OPER_UP); +#ifdef CONFIG_RFKILL rfkill_deinit(drv->rfkill); +#endif eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); @@ -6752,7 +6807,7 @@ static int wpa_driver_nl80211_ibss(struc struct wpa_driver_associate_params *params) { struct nl_msg *msg; - int ret = -1; + int ret = -1, i; int count = 0; wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); @@ -6785,6 +6840,53 @@ retry: wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + if (params->fixed_freq) { + wpa_printf(MSG_DEBUG, " * fixed_freq"); + NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED); + } + + if (params->beacon_interval > 0) { + wpa_printf(MSG_DEBUG, " * beacon_interval=%d", + params->beacon_interval); + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, + params->beacon_interval); + } + + if (params->rates[0] > 0) { + wpa_printf(MSG_DEBUG, " * basic_rates:"); + i = 0; + while (i < NL80211_MAX_SUPP_RATES && + params->rates[i] > 0) { + wpa_printf(MSG_DEBUG, " %.1f", + (double)params->rates[i] / 2); + i++; + } + NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, i, + params->rates); + } + + if (params->mcast_rate > 0) { + wpa_printf(MSG_DEBUG, " * mcast_rates=%.1f", + (double)params->mcast_rate / 10); + NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, params->mcast_rate); + } + + if (params->ht_set) { + switch(params->htmode) { + case NL80211_CHAN_HT20: + wpa_printf(MSG_DEBUG, " * ht=HT20"); + break; + case NL80211_CHAN_HT40PLUS: + wpa_printf(MSG_DEBUG, " * ht=HT40+"); + break; + case NL80211_CHAN_HT40MINUS: + wpa_printf(MSG_DEBUG, " * ht=HT40-"); + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + params->htmode); + } + ret = nl80211_set_conn_keys(params, msg); if (ret) goto nla_put_failure; @@ -7292,8 +7394,6 @@ static int wpa_driver_nl80211_set_mode(s ret = nl80211_set_mode(drv, drv->ifindex, nlmode); if (ret == -EACCES) break; - res = linux_set_iface_flags(drv->global->ioctl_sock, - bss->ifname, 1); if (res && !ret) ret = -1; else if (ret != -EBUSY) @@ -7309,6 +7409,7 @@ static int wpa_driver_nl80211_set_mode(s "interface is down"); drv->nlmode = nlmode; drv->ignore_if_down_event = 1; + linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); } done: @@ -8013,8 +8114,6 @@ static void *i802_init(struct hostapd_da br_ifindex = 0; } - drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); - drv->if_indices = drv->default_if_indices; for (i = 0; i < params->num_bridge; i++) { if (params->bridge[i]) { ifindex = if_nametoindex(params->bridge[i]); @@ -9512,4 +9611,5 @@ const struct wpa_driver_ops wpa_driver_n .send_tdls_mgmt = nl80211_send_tdls_mgmt, .tdls_oper = nl80211_tdls_oper, #endif /* CONFIG_TDLS */ + .stop_ap = wpa_driver_nl80211_stop_ap, }; diff -purN hostapd-20130302/src/drivers/drivers.c hostapd-20130302-linux/src/drivers/drivers.c --- hostapd-20130302/src/drivers/drivers.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/drivers.c 2013-07-06 06:05:42.000000000 -0400 @@ -7,7 +7,11 @@ */ #include "includes.h" +#include "common.h" +#include "driver.h" +void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); #ifdef CONFIG_DRIVER_WEXT extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ @@ -15,6 +19,9 @@ extern struct wpa_driver_ops wpa_driver_ #ifdef CONFIG_DRIVER_NL80211 extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ #endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_CAPWAP +extern struct wpa_driver_ops wpa_driver_capwap_ops; /* benunets capwap driver */ +#endif #ifdef CONFIG_DRIVER_HOSTAP extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ #endif /* CONFIG_DRIVER_HOSTAP */ @@ -56,6 +63,9 @@ struct wpa_driver_ops *wpa_drivers[] = #ifdef CONFIG_DRIVER_NL80211 &wpa_driver_nl80211_ops, #endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_CAPWAP + &wpa_driver_capwap_ops, /* benunets capwap driver */ +#endif #ifdef CONFIG_DRIVER_HOSTAP &wpa_driver_hostap_ops, #endif /* CONFIG_DRIVER_HOSTAP */ diff -purN hostapd-20130302/src/drivers/drivers.c.orig hostapd-20130302-linux/src/drivers/drivers.c.orig --- hostapd-20130302/src/drivers/drivers.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/drivers.c.orig 2013-07-04 11:17:51.000000000 -0400 @@ -0,0 +1,100 @@ +/* + * Driver interface list + * Copyright (c) 2004-2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" +#include "common.h" +#include "driver.h" + +void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); + +#ifdef CONFIG_DRIVER_WEXT +extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ +#endif /* CONFIG_DRIVER_WEXT */ +#ifdef CONFIG_DRIVER_NL80211 +extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ +#endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_CAPWAP_WTP +extern struct wpa_driver_ops wpa_driver_capwap_wtp_ops; /* benunets capwap driver */ +#endif +#ifdef CONFIG_DRIVER_HOSTAP +extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ +#endif /* CONFIG_DRIVER_HOSTAP */ +#ifdef CONFIG_DRIVER_MADWIFI +extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */ +#endif /* CONFIG_DRIVER_MADWIFI */ +#ifdef CONFIG_DRIVER_BSD +extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ +#endif /* CONFIG_DRIVER_BSD */ +#ifdef CONFIG_DRIVER_OPENBSD +extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */ +#endif /* CONFIG_DRIVER_OPENBSD */ +#ifdef CONFIG_DRIVER_NDIS +extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ +#endif /* CONFIG_DRIVER_NDIS */ +#ifdef CONFIG_DRIVER_WIRED +extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ +#endif /* CONFIG_DRIVER_WIRED */ +#ifdef CONFIG_DRIVER_TEST +extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */ +#endif /* CONFIG_DRIVER_TEST */ +#ifdef CONFIG_DRIVER_ROBOSWITCH +/* driver_roboswitch.c */ +extern struct wpa_driver_ops wpa_driver_roboswitch_ops; +#endif /* CONFIG_DRIVER_ROBOSWITCH */ +#ifdef CONFIG_DRIVER_ATHEROS +extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ +#endif /* CONFIG_DRIVER_ATHEROS */ +#ifdef CONFIG_DRIVER_NONE +extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ +#endif /* CONFIG_DRIVER_NONE */ + + +struct wpa_driver_ops *wpa_drivers[] = +{ +#ifdef CONFIG_DRIVER_WEXT + &wpa_driver_wext_ops, +#endif /* CONFIG_DRIVER_WEXT */ +#ifdef CONFIG_DRIVER_NL80211 + &wpa_driver_nl80211_ops, +#endif /* CONFIG_DRIVER_NL80211 */ +#ifdef CONFIG_DRIVER_CAPWAP_WTP + &wpa_driver_capwap_wtp_ops, /* benunets capwap driver */ +#endif +#ifdef CONFIG_DRIVER_HOSTAP + &wpa_driver_hostap_ops, +#endif /* CONFIG_DRIVER_HOSTAP */ +#ifdef CONFIG_DRIVER_MADWIFI + &wpa_driver_madwifi_ops, +#endif /* CONFIG_DRIVER_MADWIFI */ +#ifdef CONFIG_DRIVER_BSD + &wpa_driver_bsd_ops, +#endif /* CONFIG_DRIVER_BSD */ +#ifdef CONFIG_DRIVER_OPENBSD + &wpa_driver_openbsd_ops, +#endif /* CONFIG_DRIVER_OPENBSD */ +#ifdef CONFIG_DRIVER_NDIS + &wpa_driver_ndis_ops, +#endif /* CONFIG_DRIVER_NDIS */ +#ifdef CONFIG_DRIVER_WIRED + &wpa_driver_wired_ops, +#endif /* CONFIG_DRIVER_WIRED */ +#ifdef CONFIG_DRIVER_TEST + &wpa_driver_test_ops, +#endif /* CONFIG_DRIVER_TEST */ +#ifdef CONFIG_DRIVER_ROBOSWITCH + &wpa_driver_roboswitch_ops, +#endif /* CONFIG_DRIVER_ROBOSWITCH */ +#ifdef CONFIG_DRIVER_ATHEROS + &wpa_driver_atheros_ops, +#endif /* CONFIG_DRIVER_ATHEROS */ +#ifdef CONFIG_DRIVER_NONE + &wpa_driver_none_ops, +#endif /* CONFIG_DRIVER_NONE */ + NULL +}; diff -purN hostapd-20130302/src/drivers/drivers.mak hostapd-20130302-linux/src/drivers/drivers.mak --- hostapd-20130302/src/drivers/drivers.mak 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/drivers.mak 2013-07-06 06:06:37.000000000 -0400 @@ -20,7 +20,7 @@ endif ifdef CONFIG_DRIVER_NL80211 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 DRV_OBJS += ../src/drivers/driver_nl80211.o -DRV_OBJS += ../src/utils/radiotap.o +NEED_RADIOTAP=y NEED_SME=y NEED_AP_MLME=y NEED_NETLINK=y @@ -138,6 +138,47 @@ DRV_WPA_OBJS += ../src/drivers/driver_we NEED_RFKILL=y endif +ifdef CONFIG_DRIVER_CAPWAP +DRV_CFLAGS += -DCONFIG_DRIVER_CAPWAP +DRV_OBJS += ../src/drivers/driver_capwap.o +NEED_RADIOTAP=y +NEED_SME=y +NEED_AP_MLME=y +NEED_FAKE_NETLINK=y +NEED_LINUX_FAKE_IOCTL=y +NEED_CAPWAP_MGMT_FRAME_AC=y +NEED_CAPWAP_IPC_AC=y +NEED_RFKILL=y + +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +else + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif + + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif +endif +ifdef NEED_FAKE_NETLINK +DRV_OBJS += ../src/drivers/netlink_fake.o +endif + +ifdef NEED_LINUX_FAKE_IOCTL +DRV_OBJS += ../src/drivers/linux_ioctl_fake.o +endif +endif + +ifdef NEED_RADIOTAP +DRV_OBJS += ../src/utils/radiotap.o +endif + ifdef NEED_NETLINK DRV_OBJS += ../src/drivers/netlink.o endif @@ -150,6 +191,26 @@ ifdef NEED_RFKILL DRV_OBJS += ../src/drivers/rfkill.o endif +ifdef NEED_CAPWAP_MGMT_FRAME_WTP +DRV_OBJS += ../src/capwap/capwap_mgmt_frame_wtp.o +endif + +ifdef NEED_CAPWAP_MGMT_FRAME_AC +DRV_OBJS += ../src/capwap/capwap_mgmt_frame_ac.o +endif + +ifdef NEED_CAPWAP_IPC_WTP +DRV_OBJS += ../src/capwap/ipc_capwap_wtp.o +endif + +ifdef NEED_CAPWAP_IPC_AC +DRV_OBJS += ../src/capwap/ipc_capwap_ac.o +endif + +ifdef NEED_SWITCH_8023 +DRV_OBJS += ../src/capwap/switch_8023_80211.o +endif + ifdef CONFIG_VLAN_NETLINK ifdef CONFIG_FULL_DYNAMIC_VLAN ifdef CONFIG_LIBNL32 diff -purN hostapd-20130302/src/drivers/drivers.mk hostapd-20130302-linux/src/drivers/drivers.mk --- hostapd-20130302/src/drivers/drivers.mk 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/drivers.mk 2013-07-06 06:06:37.000000000 -0400 @@ -18,9 +18,9 @@ DRV_OBJS += src/drivers/driver_wired.c endif ifdef CONFIG_DRIVER_NL80211 -DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 +DRV_CFLAGS += -I/usr/include -DCONFIG_DRIVER_NL80211 -D_GNU_SOURCE DRV_OBJS += src/drivers/driver_nl80211.c -DRV_OBJS += src/utils/radiotap.c +NEED_RADIOTAP=y NEED_SME=y NEED_AP_MLME=y NEED_NETLINK=y @@ -45,6 +45,74 @@ else endif endif +ifdef CONFIG_DRIVER_CAPWAP +DRV_CFLAGS += -DCONFIG_DRIVER_CAPWAP +DRV_OBJS += src/drivers/driver_capwap.c +NEED_RADIOTAP=y +NEED_SME=y +NEED_AP_MLME=y +NEED_FAKE_NETLINK=y +NEED_LINUX_FAKE_IOCTL=y +NEED_CAPWAP_MGMT_FRAME_AC=y +NEED_CAPWAP_IPC_AC=y +NEED_RFKILL=y +ifdef CONFIG_LIBNL32 + DRV_LIBS += -lnl-3 + DRV_LIBS += -lnl-genl-3 + DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +else + ifdef CONFIG_LIBNL_TINY + DRV_LIBS += -lnl-tiny + else + DRV_LIBS += -lnl + endif + + ifdef CONFIG_LIBNL20 + DRV_LIBS += -lnl-genl + DRV_CFLAGS += -DCONFIG_LIBNL20 + endif +endif +ifdef NEED_RADIOTAP +DRV_OBJS += src/utils/radiotap.c +endif + +ifdef NEED_NETLINK +DRV_OBJS += src/drivers/netlink.c +endif + +ifdef NEED_FAKE_NETLINK +DRV_OBJS += src/drivers/netlink_fake.c +endif + +ifdef NEED_LINUX_IOCTL +DRV_OBJS += src/drivers/linux_ioctl.c +endif + +ifdef NEED_LINUX_FAKE_IOCTL +DRV_OBJS += src/drivers/linux_ioctl_fake.c +endif + +ifdef NEED_RFKILL +DRV_OBJS += src/drivers/rfkill.c +endif + +ifdef NEED_CAPWAP_MGMT_FRAME_WTP +DRV_OBJS += src/capwap/capwap_mgmt_frame_wtp.c +endif + +ifdef NEED_CAPWAP_MGMT_FRAME_AC +DRV_OBJS += src/capwap/capwap_mgmt_frame_ac.c +endif + +ifdef NEED_CAPWAP_IPC_WTP +DRV_OBJS += src/capwap/ipc_capwap_wtp.c +endif + +ifdef NEED_CAPWAP_IPC_AC +DRV_OBJS += src/capwap/ipc_capwap_ac.c +endif +endif + ifdef CONFIG_DRIVER_BSD ifndef CONFIG_L2_PACKET CONFIG_L2_PACKET=freebsd @@ -138,6 +206,10 @@ DRV_WPA_OBJS += src/drivers/driver_wext. NEED_RFKILL=y endif +ifdef NEED_RADIOTAP +DRV_OBJS += src/utils/radiotap.c +endif + ifdef NEED_NETLINK DRV_OBJS += src/drivers/netlink.c endif @@ -150,6 +222,26 @@ ifdef NEED_RFKILL DRV_OBJS += src/drivers/rfkill.c endif +ifdef NEED_CAPWAP_MGMT_FRAME_WTP +DRV_OBJS += src/capwap/capwap_mgmt_frame_wtp.c +endif + +ifdef NEED_CAPWAP_MGMT_FRAME_AC +DRV_OBJS += src/capwap/capwap_mgmt_frame_ac.c +endif + +ifdef NEED_CAPWAP_IPC_WTP +DRV_OBJS += src/capwap/ipc_capwap_wtp.c +endif + +ifdef NEED_CAPWAP_IPC_AC +DRV_OBJS += src/capwap/ipc_capwap_ac.c +endif + +ifdef NEED_SWITCH_8023 +DRV_OBJS += src/capwap/switch_8023_80211.c +endif + ifdef CONFIG_DRIVER_CUSTOM DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM endif diff -purN hostapd-20130302/src/drivers/driver_wext.c hostapd-20130302-linux/src/drivers/driver_wext.c --- hostapd-20130302/src/drivers/driver_wext.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/driver_wext.c 2013-07-04 11:17:51.000000000 -0400 @@ -742,7 +742,7 @@ static void wpa_driver_wext_event_rtm_de } } - +#ifdef CONFIG_RFKILL static void wpa_driver_wext_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); @@ -764,7 +764,7 @@ static void wpa_driver_wext_rfkill_unblo } /* rtnetlink ifup handler will report interface as enabled */ } - +#endif /* CONFIG_RFKILL */ static void wext_get_phy_name(struct wpa_driver_wext_data *drv) { @@ -810,7 +810,9 @@ void * wpa_driver_wext_init(void *ctx, c { struct wpa_driver_wext_data *drv; struct netlink_config *cfg; +#ifdef CONFIG_RFKILL struct rfkill_config *rcfg; +#endif char path[128]; struct stat buf; @@ -845,6 +847,7 @@ void * wpa_driver_wext_init(void *ctx, c goto err2; } +#ifdef CONFIG_RFKILL rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL) goto err3; @@ -857,6 +860,7 @@ void * wpa_driver_wext_init(void *ctx, c wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); os_free(rcfg); } +#endif /* CONFIG_RFKILL */ drv->mlme_sock = -1; @@ -874,7 +878,9 @@ void * wpa_driver_wext_init(void *ctx, c return drv; err3: +#ifdef CONFIG_RFKILL rfkill_deinit(drv->rfkill); +#endif netlink_deinit(drv->netlink); err2: close(drv->ioctl_sock); @@ -884,10 +890,12 @@ err1: } +#ifdef CONFIG_RFKILL static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) { wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); } +#endif /* CONFIG_RFKILL */ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) @@ -895,13 +903,16 @@ static int wpa_driver_wext_finish_drv_in int send_rfkill_event = 0; if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { +#ifdef CONFIG_RFKILL if (rfkill_is_blocked(drv->rfkill)) { wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " "interface '%s' due to rfkill", drv->ifname); drv->if_disabled = 1; send_rfkill_event = 1; - } else { + } else +#endif + { wpa_printf(MSG_ERROR, "WEXT: Could not set " "interface '%s' UP", drv->ifname); return -1; @@ -949,8 +960,10 @@ static int wpa_driver_wext_finish_drv_in 1, IF_OPER_DORMANT); if (send_rfkill_event) { +#ifdef CONFIG_RFKILL eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, drv, drv->ctx); +#endif } return 0; @@ -980,7 +993,9 @@ void wpa_driver_wext_deinit(void *priv) netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); netlink_deinit(drv->netlink); +#ifdef CONFIG_RFKILL rfkill_deinit(drv->rfkill); +#endif if (drv->mlme_sock >= 0) eloop_unregister_read_sock(drv->mlme_sock); diff -purN hostapd-20130302/src/drivers/driver_wext.h hostapd-20130302-linux/src/drivers/driver_wext.h --- hostapd-20130302/src/drivers/driver_wext.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/driver_wext.h 2013-07-04 11:17:51.000000000 -0400 @@ -22,7 +22,9 @@ struct wpa_driver_wext_data { int ifindex2; int if_removed; int if_disabled; +#ifdef CONFIG_RFKILL struct rfkill_data *rfkill; +#endif u8 *assoc_req_ies; size_t assoc_req_ies_len; u8 *assoc_resp_ies; diff -purN hostapd-20130302/src/drivers/linux_ioctl_fake.c hostapd-20130302-linux/src/drivers/linux_ioctl_fake.c --- hostapd-20130302/src/drivers/linux_ioctl_fake.c 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/linux_ioctl_fake.c 2013-07-06 06:06:29.000000000 -0400 @@ -0,0 +1,137 @@ +/* + * Linux ioctl helper functions for driver wrappers + * Copyright (c) 2002-2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + + +#include "utils/includes.h" +#include +#include +#include + +#include "utils/common.h" +#include "linux_ioctl_fake.h" + + + +int linux_set_fake_iface_flags(int sock, const char *ifname, int dev_up){ + + return 0; +} + +int linux_iface_fake_up(int sock, const char *ifname){ + + return 0; +} + +int linux_get_fake_ifhwaddr(int sock, const char *ifname, u8 *addr){ + + int i=2; + + if(i==0){ // TP-LINK (Atheros) + addr[0]=0xB0; + addr[1]=0x48; + addr[2]=0x7A; + addr[3]=0x93; + addr[4]=0x90; + addr[5]=0xF8; + + }else if(i==1){// D-Link + addr[0]=0x28; + addr[1]=0x10; + addr[2]=0x7B; + addr[3]=0x44; + addr[4]=0xd0; + addr[5]=0xB1; + + }else if(i==2){// TP-LINK (Atheros) + addr[0]=0xAA; + addr[1]=0xBB; + addr[2]=0xCC; + addr[3]=0xDD; + addr[4]=0xEE; + addr[5]=0xFF; + + } + + return 0; +} + +int linux_set_fake_ifhwaddr(int sock, const char *ifname, u8 *addr){ + + int i=2; + + if(i==0){ // TP-LINK (Atheros) + addr[0]=0xB0; + addr[1]=0x48; + addr[2]=0x7A; + addr[3]=0x93; + addr[4]=0x90; + addr[5]=0xF8; + + }else if(i==1){// D-Link + addr[0]=0x28; + addr[1]=0x10; + addr[2]=0x7B; + addr[3]=0x44; + addr[4]=0xd0; + addr[5]=0xB1; + + }else if(i==2){// TP-LINK (Atheros) + addr[0]=0xAA; + addr[1]=0xBB; + addr[2]=0xCC; + addr[3]=0xDD; + addr[4]=0xEE; + addr[5]=0xFF; + + } + + return 0; +} + + +#ifndef SIOCBRADDBR +#define SIOCBRADDBR 0x89a0 +#endif +#ifndef SIOCBRDELBR +#define SIOCBRDELBR 0x89a1 +#endif +#ifndef SIOCBRADDIF +#define SIOCBRADDIF 0x89a2 +#endif +#ifndef SIOCBRDELIF +#define SIOCBRDELIF 0x89a3 +#endif + + +int linux_br_fake_add(int sock, const char *brname){ + return 0; +} + +int linux_br_fake_del(int sock, const char *brname){ + return 0; +} + +int linux_br_fake_add_if(int sock, const char *brname, const char *ifname){ + return 0; +} + +int linux_br_fake_del_if(int sock, const char *brname, const char *ifname){ + return 0; +} + +int linux_br_fake_get(char *brname, const char *ifname){ + return 0; +} + + diff -purN hostapd-20130302/src/drivers/linux_ioctl_fake.h hostapd-20130302-linux/src/drivers/linux_ioctl_fake.h --- hostapd-20130302/src/drivers/linux_ioctl_fake.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/linux_ioctl_fake.h 2013-07-06 06:06:29.000000000 -0400 @@ -0,0 +1,28 @@ +/* + * Linux ioctl helper functions for driver wrappers + * Copyright (c) 2002-2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef LINUX_IOCTL_H +#define LINUX_IOCTL_H + +int linux_set_iface_flags(int sock, const char *ifname, int dev_up); +int linux_iface_up(int sock, const char *ifname); +int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr); +int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr); +int linux_br_add(int sock, const char *brname); +int linux_br_del(int sock, const char *brname); +int linux_br_add_if(int sock, const char *brname, const char *ifname); +int linux_br_del_if(int sock, const char *brname, const char *ifname); +int linux_br_get(char *brname, const char *ifname); + +#endif /* LINUX_IOCTL_H */ diff -purN hostapd-20130302/src/drivers/netlink_fake.c hostapd-20130302-linux/src/drivers/netlink_fake.c --- hostapd-20130302/src/drivers/netlink_fake.c 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/netlink_fake.c 2013-07-06 06:06:29.000000000 -0400 @@ -0,0 +1,82 @@ +/* + * Netlink helper functions for driver wrappers + * Copyright (c) 2002-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "priv_netlink.h" +#include "netlink_fake.h" + + + +struct netlink_data { + struct netlink_config *cfg; + int sock; +}; + + +static void netlink_receive_link(struct netlink_data *netlink, + void (*cb)(void *ctx, struct ifinfomsg *ifi, + u8 *buf, size_t len), + struct nlmsghdr *h) +{ + + return; +} + + +static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx) +{ + return; +} + + +struct netlink_data * netlink_fake_init(struct netlink_config *cfg) +{ + + struct netlink_data *netlink; + struct sockaddr_nl local; + + netlink = os_zalloc(sizeof(*netlink)); + if (netlink == NULL) + return NULL; + + netlink->cfg = cfg; + + netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + + os_memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_groups = RTMGRP_LINK; + + eloop_register_read_sock(netlink->sock, netlink_receive, netlink, + NULL); + + return netlink; + +} + + +void netlink_fake_deinit(struct netlink_data *netlink) +{ + return; +} + +int netlink_fake_send_oper_ifla(struct netlink_data *netlink, int ifindex, + int linkmode, int operstate){ + + return 0; +} diff -purN hostapd-20130302/src/drivers/netlink_fake.h hostapd-20130302-linux/src/drivers/netlink_fake.h --- hostapd-20130302/src/drivers/netlink_fake.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/drivers/netlink_fake.h 2013-07-07 03:48:41.000000000 -0400 @@ -0,0 +1,34 @@ +/* + * Netlink helper functions for driver wrappers + * Copyright (c) 2002-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef NETLINK_FAKE_H +#define NETLINK_FAKE_H + +struct netlink_data; +struct ifinfomsg; + +struct netlink_config { + void *ctx; + void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, + size_t len); + void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, + size_t len); +}; + +struct netlink_data * netlink_fake_init(struct netlink_config *cfg); +void netlink_fake_deinit(struct netlink_data *netlink); +int netlink_fake_send_oper_ifla(struct netlink_data *netlink, int ifindex, + int linkmode, int operstate); + +#endif /* NETLINK_H */ diff -purN hostapd-20130302/src/Makefile hostapd-20130302-linux/src/Makefile --- hostapd-20130302/src/Makefile 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/Makefile 2013-07-06 06:04:50.000000000 -0400 @@ -1,4 +1,4 @@ -SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps +SUBDIRS=capwap ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps all: for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done diff -purN hostapd-20130302/src/rsn_supp/wpa.c hostapd-20130302-linux/src/rsn_supp/wpa.c --- hostapd-20130302/src/rsn_supp/wpa.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/rsn_supp/wpa.c 2013-07-04 11:17:51.000000000 -0400 @@ -1848,6 +1848,8 @@ static u32 wpa_key_mgmt_suite(struct wpa } +#ifdef CONFIG_CTRL_IFACE_MIB + #define RSN_SUITE "%02x-%02x-%02x-%d" #define RSN_SUITE_ARG(s) \ ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff @@ -1931,6 +1933,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch return (int) len; } +#endif #endif /* CONFIG_CTRL_IFACE */ diff -purN hostapd-20130302/src/tls/x509v3.c hostapd-20130302-linux/src/tls/x509v3.c --- hostapd-20130302/src/tls/x509v3.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/tls/x509v3.c 2013-07-04 11:17:51.000000000 -0400 @@ -1848,6 +1848,9 @@ int x509_certificate_chain_validate(stru if (chain_trusted) continue; +#ifdef NO_TIMESTAMP_CHECK + disable_time_checks = 1; +#endif if (!disable_time_checks && ((unsigned long) now.sec < (unsigned long) cert->not_before || diff -purN hostapd-20130302/src/utils/build_features.h hostapd-20130302-linux/src/utils/build_features.h --- hostapd-20130302/src/utils/build_features.h 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/src/utils/build_features.h 2013-07-04 11:17:51.000000000 -0400 @@ -0,0 +1,17 @@ +#ifndef BUILD_FEATURES_H +#define BUILD_FEATURES_H + +static inline int has_feature(const char *feat) +{ +#ifdef IEEE8021X_EAPOL + if (!strcmp(feat, "eap")) + return 1; +#endif +#ifdef IEEE80211N + if (!strcmp(feat, "11n")) + return 1; +#endif + return 0; +} + +#endif /* BUILD_FEATURES_H */ diff -purN hostapd-20130302/src/utils/eloop.h hostapd-20130302-linux/src/utils/eloop.h --- hostapd-20130302/src/utils/eloop.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/utils/eloop.h 2013-07-04 11:17:51.000000000 -0400 @@ -17,6 +17,7 @@ #ifndef ELOOP_H #define ELOOP_H +#include "os.h" /** * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts */ diff -purN hostapd-20130302/src/utils/wpa_debug.c hostapd-20130302-linux/src/utils/wpa_debug.c --- hostapd-20130302/src/utils/wpa_debug.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/utils/wpa_debug.c 2013-07-04 11:17:51.000000000 -0400 @@ -201,7 +201,7 @@ void wpa_debug_close_linux_tracing(void) * * Note: New line '\n' is added to the end of the text when printing to stdout. */ -void wpa_printf(int level, const char *fmt, ...) +void _wpa_printf(int level, const char *fmt, ...) { va_list ap; @@ -248,8 +248,8 @@ void wpa_printf(int level, const char *f } -static void _wpa_hexdump(int level, const char *title, const u8 *buf, - size_t len, int show) +void _wpa_hexdump(int level, const char *title, const u8 *buf, + size_t len, int show) { size_t i; @@ -375,20 +375,9 @@ static void _wpa_hexdump(int level, cons #endif /* CONFIG_ANDROID_LOG */ } -void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) -{ - _wpa_hexdump(level, title, buf, len, 1); -} - - -void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) -{ - _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); -} - -static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, - size_t len, int show) +void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, + size_t len, int show) { size_t i, llen; const u8 *pos = buf; @@ -495,19 +484,6 @@ static void _wpa_hexdump_ascii(int level } -void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) -{ - _wpa_hexdump_ascii(level, title, buf, len, 1); -} - - -void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, - size_t len) -{ - _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); -} - - #ifdef CONFIG_DEBUG_FILE static char *last_path = NULL; #endif /* CONFIG_DEBUG_FILE */ @@ -591,7 +567,7 @@ void wpa_msg_register_ifname_cb(wpa_msg_ } -void wpa_msg(void *ctx, int level, const char *fmt, ...) +void _wpa_msg(void *ctx, int level, const char *fmt, ...) { va_list ap; char *buf; @@ -625,7 +601,7 @@ void wpa_msg(void *ctx, int level, const } -void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +void _wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) { va_list ap; char *buf; diff -purN hostapd-20130302/src/utils/wpa_debug.h hostapd-20130302-linux/src/utils/wpa_debug.h --- hostapd-20130302/src/utils/wpa_debug.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/src/utils/wpa_debug.h 2013-07-04 11:17:51.000000000 -0400 @@ -15,7 +15,7 @@ * use these for debugging purposes. */ enum { - MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR + MSG_EXCESSIVE, MSG_MSGDUMP, MSG_ERROR, MSG_INFO, MSG_WARNING, MSG_DEBUG }; #ifdef CONFIG_NO_STDOUT_DEBUG @@ -43,6 +43,17 @@ int wpa_debug_open_file(const char *path int wpa_debug_reopen_file(void); void wpa_debug_close_file(void); +/* internal */ +void _wpa_hexdump(int level, const char *title, const u8 *buf, + size_t len, int show); +void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, + size_t len, int show); +extern int wpa_debug_show_keys; + +#ifndef CONFIG_MSG_MIN_PRIORITY +#define CONFIG_MSG_MIN_PRIORITY 0 +#endif + /** * wpa_debug_printf_timestamp - Print timestamp for debug output * @@ -63,9 +74,15 @@ void wpa_debug_print_timestamp(void); * * Note: New line '\n' is added to the end of the text when printing to stdout. */ -void wpa_printf(int level, const char *fmt, ...) +void _wpa_printf(int level, const char *fmt, ...) PRINTF_FORMAT(2, 3); +#define wpa_printf(level, ...) \ + do { \ + if (level >= CONFIG_MSG_MIN_PRIORITY) \ + _wpa_printf(level, __VA_ARGS__); \ + } while(0) + /** * wpa_hexdump - conditional hex dump * @level: priority level (MSG_*) of the message @@ -77,7 +94,13 @@ PRINTF_FORMAT(2, 3); * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump. */ -void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); +static inline void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) +{ + if (level < CONFIG_MSG_MIN_PRIORITY) + return; + + _wpa_hexdump(level, title, buf, len, 1); +} static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) @@ -99,7 +122,13 @@ static inline void wpa_hexdump_buf(int l * like wpa_hexdump(), but by default, does not include secret keys (passwords, * etc.) in debug output. */ -void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); +static inline void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) +{ + if (level < CONFIG_MSG_MIN_PRIORITY) + return; + + _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); +} static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) @@ -121,8 +150,14 @@ static inline void wpa_hexdump_buf_key(i * the hex numbers and ASCII characters (for printable range) are shown. 16 * bytes per line will be shown. */ -void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, - size_t len); +static inline void wpa_hexdump_ascii(int level, const char *title, + const u8 *buf, size_t len) +{ + if (level < CONFIG_MSG_MIN_PRIORITY) + return; + + _wpa_hexdump_ascii(level, title, buf, len, 1); +} /** * wpa_hexdump_ascii_key - conditional hex dump, hide keys @@ -138,8 +173,14 @@ void wpa_hexdump_ascii(int level, const * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by * default, does not include secret keys (passwords, etc.) in debug output. */ -void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, - size_t len); +static inline void wpa_hexdump_ascii_key(int level, const char *title, + const u8 *buf, size_t len) +{ + if (level < CONFIG_MSG_MIN_PRIORITY) + return; + + _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); +} /* * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce @@ -172,7 +213,12 @@ void wpa_hexdump_ascii_key(int level, co * * Note: New line '\n' is added to the end of the text when printing to stdout. */ -void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); +void _wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); +#define wpa_msg(ctx, level, ...) \ + do { \ + if (level >= CONFIG_MSG_MIN_PRIORITY) \ + _wpa_msg(ctx, level, __VA_ARGS__); \ + } while(0) /** * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors @@ -186,8 +232,13 @@ void wpa_msg(void *ctx, int level, const * attached ctrl_iface monitors. In other words, it can be used for frequent * events that do not need to be sent to syslog. */ -void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +void _wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); +#define wpa_msg_ctrl(ctx, level, ...) \ + do { \ + if (level >= CONFIG_MSG_MIN_PRIORITY) \ + _wpa_msg_ctrl(ctx, level, __VA_ARGS__); \ + } while(0) typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, size_t len); diff -purN hostapd-20130302/wpa_supplicant/bss.c hostapd-20130302-linux/wpa_supplicant/bss.c --- hostapd-20130302/wpa_supplicant/bss.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/bss.c 2013-07-04 11:17:51.000000000 -0400 @@ -11,6 +11,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "drivers/driver.h" #include "wpa_supplicant_i.h" #include "config.h" @@ -227,6 +228,8 @@ struct wpa_bss * wpa_bss_get(struct wpa_ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, struct os_time *fetch_time) { + struct ieee80211_ht_capabilities *capab; + struct ieee802_11_elems elems; os_time_t usec; dst->flags = src->flags; @@ -239,6 +242,12 @@ static void wpa_bss_copy_res(struct wpa_ dst->level = src->level; dst->tsf = src->tsf; + memset(&elems, 0, sizeof(elems)); + ieee802_11_parse_elems((u8 *) (src + 1), src->ie_len, &elems, 0); + capab = (struct ieee80211_ht_capabilities *) elems.ht_capabilities; + if (capab) + dst->ht_capab = le_to_host16(capab->ht_capabilities_info); + dst->last_update.sec = fetch_time->sec; dst->last_update.usec = fetch_time->usec; dst->last_update.sec -= src->age / 1000; diff -purN hostapd-20130302/wpa_supplicant/bss.h hostapd-20130302-linux/wpa_supplicant/bss.h --- hostapd-20130302/wpa_supplicant/bss.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/bss.h 2013-07-04 11:17:51.000000000 -0400 @@ -69,6 +69,8 @@ struct wpa_bss { u8 ssid[32]; /** Length of SSID */ size_t ssid_len; + /** HT caapbilities */ + u16 ht_capab; /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */ int freq; /** Beacon interval in TUs (host byte order) */ diff -purN hostapd-20130302/wpa_supplicant/.config hostapd-20130302-linux/wpa_supplicant/.config --- hostapd-20130302/wpa_supplicant/.config 1969-12-31 19:00:00.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/.config 2013-06-22 15:54:23.000000000 -0400 @@ -0,0 +1,408 @@ +# Example wpa_supplicant build time configuration +# +# This file lists the configuration options that are used when building the +# hostapd binary. All lines starting with # are ignored. Configuration option +# lines must be commented out complete, if they are not to be included, i.e., +# just setting VARIABLE=n is not disabling that variable. +# +# This file is included in Makefile, so variables like CFLAGS and LIBS can also +# be modified from here. In most cases, these lines should use += in order not +# to override previous values of the variables. + + +# Uncomment following two lines and fix the paths if you have installed OpenSSL +# or GnuTLS in non-default location +#CFLAGS += -I/usr/local/openssl/include +#LIBS += -L/usr/local/openssl/lib + +# Some Red Hat versions seem to include kerberos header files from OpenSSL, but +# the kerberos files are not in the default include path. Following line can be +# used to fix build issues on such systems (krb5.h not found). +#CFLAGS += -I/usr/include/kerberos + +# Example configuration for various cross-compilation platforms + +#### sveasoft (e.g., for Linksys WRT54G) ###################################### +#CC=mipsel-uclibc-gcc +#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc +#CFLAGS += -Os +#CPPFLAGS += -I../src/include -I../../src/router/openssl/include +#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl +############################################################################### + +#### openwrt (e.g., for Linksys WRT54G) ####################################### +#CC=mipsel-uclibc-gcc +#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc +#CFLAGS += -Os +#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \ +# -I../WRT54GS/release/src/include +#LIBS = -lssl +############################################################################### + + +# Driver interface for Host AP driver +CONFIG_DRIVER_HOSTAP=y + +# Driver interface for Agere driver +#CONFIG_DRIVER_HERMES=y +# Change include directories to match with the local setup +#CFLAGS += -I../../hcf -I../../include -I../../include/hcf +#CFLAGS += -I../../include/wireless + +# Driver interface for madwifi driver +# Deprecated; use CONFIG_DRIVER_WEXT=y instead. +#CONFIG_DRIVER_MADWIFI=y +# Set include directory to the madwifi source tree +#CFLAGS += -I../../madwifi + +# Driver interface for ndiswrapper +# Deprecated; use CONFIG_DRIVER_WEXT=y instead. +#CONFIG_DRIVER_NDISWRAPPER=y + +# Driver interface for Atmel driver +# CONFIG_DRIVER_ATMEL=y + +# Driver interface for old Broadcom driver +# Please note that the newer Broadcom driver ("hybrid Linux driver") supports +# Linux wireless extensions and does not need (or even work) with the old +# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver. +#CONFIG_DRIVER_BROADCOM=y +# Example path for wlioctl.h; change to match your configuration +#CFLAGS += -I/opt/WRT54GS/release/src/include + +# Driver interface for Intel ipw2100/2200 driver +# Deprecated; use CONFIG_DRIVER_WEXT=y instead. +#CONFIG_DRIVER_IPW=y + +# Driver interface for Ralink driver +#CONFIG_DRIVER_RALINK=y + +# Driver interface for generic Linux wireless extensions +CONFIG_DRIVER_WEXT=y + +# Driver interface for Linux drivers using the nl80211 kernel interface +CONFIG_DRIVER_NL80211=y + +# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) +#CONFIG_DRIVER_BSD=y +#CFLAGS += -I/usr/local/include +#LIBS += -L/usr/local/lib +#LIBS_p += -L/usr/local/lib +#LIBS_c += -L/usr/local/lib + +# Driver interface for Windows NDIS +#CONFIG_DRIVER_NDIS=y +#CFLAGS += -I/usr/include/w32api/ddk +#LIBS += -L/usr/local/lib +# For native build using mingw +#CONFIG_NATIVE_WINDOWS=y +# Additional directories for cross-compilation on Linux host for mingw target +#CFLAGS += -I/opt/mingw/mingw32/include/ddk +#LIBS += -L/opt/mingw/mingw32/lib +#CC=mingw32-gcc +# By default, driver_ndis uses WinPcap for low-level operations. This can be +# replaced with the following option which replaces WinPcap calls with NDISUIO. +# However, this requires that WZC is disabled (net stop wzcsvc) before starting +# wpa_supplicant. +# CONFIG_USE_NDISUIO=y + +# Driver interface for development testing +#CONFIG_DRIVER_TEST=y + +# Include client MLME (management frame processing) for test driver +# This can be used to test MLME operations in hostapd with the test interface. +# space. +#CONFIG_CLIENT_MLME=y + +# Driver interface for wired Ethernet drivers +CONFIG_DRIVER_WIRED=y + +# Driver interface for the Broadcom RoboSwitch family +#CONFIG_DRIVER_ROBOSWITCH=y + +# Driver interface for no driver (e.g., WPS ER only) +#CONFIG_DRIVER_NONE=y + +# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is +# included) +CONFIG_IEEE8021X_EAPOL=y + +# EAP-MD5 +CONFIG_EAP_MD5=y + +# EAP-MSCHAPv2 +CONFIG_EAP_MSCHAPV2=y + +# EAP-TLS +CONFIG_EAP_TLS=y + +# EAL-PEAP +CONFIG_EAP_PEAP=y + +# EAP-TTLS +CONFIG_EAP_TTLS=y + +# EAP-FAST +# Note: Default OpenSSL package does not include support for all the +# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, +# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch) +# to add the needed functions. +#CONFIG_EAP_FAST=y + +# EAP-GTC +CONFIG_EAP_GTC=y + +# EAP-OTP +CONFIG_EAP_OTP=y + +# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) +#CONFIG_EAP_SIM=y + +# EAP-PSK (experimental; this is _not_ needed for WPA-PSK) +#CONFIG_EAP_PSK=y + +# EAP-PAX +#CONFIG_EAP_PAX=y + +# LEAP +CONFIG_EAP_LEAP=y + +# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) +#CONFIG_EAP_AKA=y + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# Enable USIM simulator (Milenage) for EAP-AKA +#CONFIG_USIM_SIMULATOR=y + +# EAP-SAKE +#CONFIG_EAP_SAKE=y + +# EAP-GPSK +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-TNC and related Trusted Network Connect support (experimental) +#CONFIG_EAP_TNC=y + +# Wi-Fi Protected Setup (WPS) +CONFIG_WPS=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +CONFIG_PKCS12=y + +# Smartcard support (i.e., private key on a smartcard), e.g., with openssl +# engine. +CONFIG_SMARTCARD=y + +# PC/SC interface for smartcards (USIM, GSM SIM) +# Enable this if EAP-SIM or EAP-AKA is included +#CONFIG_PCSC=y + +# Development testing +#CONFIG_EAPOL_TEST=y + +# Select control interface backend for external programs, e.g, wpa_cli: +# unix = UNIX domain sockets (default for Linux/*BSD) +# udp = UDP sockets using localhost (127.0.0.1) +# named_pipe = Windows Named Pipe (default for Windows) +# y = use default (backwards compatibility) +# If this option is commented out, control interface is not included in the +# build. +CONFIG_CTRL_IFACE=y + +# Include support for GNU Readline and History Libraries in wpa_cli. +# When building a wpa_cli binary for distribution, please note that these +# libraries are licensed under GPL and as such, BSD license may not apply for +# the resulting binary. +#CONFIG_READLINE=y + +# Remove debugging code that is printing out debug message to stdout. +# This can be used to reduce the size of the wpa_supplicant considerably +# if debugging code is not needed. The size reduction can be around 35% +# (e.g., 90 kB). +#CONFIG_NO_STDOUT_DEBUG=y + +# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save +# 35-50 kB in code size. +#CONFIG_NO_WPA=y + +# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to +# save about 1 kB in code size when building only WPA-Personal (no EAP support) +# or 6 kB if building for WPA-Enterprise. +#CONFIG_NO_WPA2=y + +# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support +# This option can be used to reduce code size by removing support for +# converting ASCII passphrases into PSK. If this functionality is removed, the +# PSK can only be configured as the 64-octet hexstring (e.g., from +# wpa_passphrase). This saves about 0.5 kB in code size. +#CONFIG_NO_WPA_PASSPHRASE=y + +# Disable scan result processing (ap_mode=1) to save code size by about 1 kB. +# This can be used if ap_scan=1 mode is never enabled. +#CONFIG_NO_SCAN_PROCESSING=y + +# Select configuration backend: +# file = text file (e.g., wpa_supplicant.conf; note: the configuration file +# path is given on command line, not here; this option is just used to +# select the backend that allows configuration files to be used) +# winreg = Windows registry (see win_example.reg for an example) +CONFIG_BACKEND=file + +# Remove configuration write functionality (i.e., to allow the configuration +# file to be updated based on runtime configuration changes). The runtime +# configuration can still be changed, the changes are just not going to be +# persistent over restarts. This option can be used to reduce code size by +# about 3.5 kB. +#CONFIG_NO_CONFIG_WRITE=y + +# Remove support for configuration blobs to reduce code size by about 1.5 kB. +#CONFIG_NO_CONFIG_BLOBS=y + +# Select program entry point implementation: +# main = UNIX/POSIX like main() function (default) +# main_winsvc = Windows service (read parameters from registry) +# main_none = Very basic example (development use only) +#CONFIG_MAIN=main + +# Select wrapper for operatins system and C library specific functions +# unix = UNIX/POSIX like systems (default) +# win32 = Windows systems +# none = Empty template +#CONFIG_OS=unix + +# Select event loop implementation +# eloop = select() loop (default) +# eloop_win = Windows events and WaitForMultipleObject() loop +# eloop_none = Empty template +#CONFIG_ELOOP=eloop + +# Select layer 2 packet implementation +# linux = Linux packet socket (default) +# pcap = libpcap/libdnet/WinPcap +# freebsd = FreeBSD libpcap +# winpcap = WinPcap with receive thread +# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y) +# none = Empty template +#CONFIG_L2_PACKET=linux + +# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) +CONFIG_PEERKEY=y + +# IEEE 802.11w (management frame protection) +# This version is an experimental implementation based on IEEE 802.11w/D1.0 +# draft and is subject to change since the standard has not yet been finalized. +# Driver support is also needed for IEEE 802.11w. +CONFIG_IEEE80211W=y + +# Select TLS implementation +# openssl = OpenSSL (default) +# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA) +# internal = Internal TLSv1 implementation (experimental) +# none = Empty template +CONFIG_TLS=internal + +# Whether to enable TLS/IA support, which is required for EAP-TTLSv1. +# You need CONFIG_TLS=gnutls for this to have any effect. Please note that +# even though the core GnuTLS library is released under LGPL, this extra +# library uses GPL and as such, the terms of GPL apply to the combination +# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not +# apply for distribution of the resulting binary. +#CONFIG_GNUTLS_EXTRA=y + +# If CONFIG_TLS=internal is used, additional library and include paths are +# needed for LibTomMath. Alternatively, an integrated, minimal version of +# LibTomMath can be used. See beginning of libtommath.c for details on benefits +# and drawbacks of this option. +CONFIG_INTERNAL_LIBTOMMATH=y +#ifndef CONFIG_INTERNAL_LIBTOMMATH +#LTM_PATH=/usr/src/libtommath-0.39 +#CFLAGS += -I$(LTM_PATH) +#LIBS += -L$(LTM_PATH) +#LIBS_p += -L$(LTM_PATH) +#endif +# At the cost of about 4 kB of additional binary size, the internal LibTomMath +# can be configured to include faster routines for exptmod, sqr, and div to +# speed up DH and RSA calculation considerably +CONFIG_INTERNAL_LIBTOMMATH_FAST=y + +# Include NDIS event processing through WMI into wpa_supplicant/wpasvc. +# This is only for Windows builds and requires WMI-related header files and +# WbemUuid.Lib from Platform SDK even when building with MinGW. +#CONFIG_NDIS_EVENTS_INTEGRATED=y +#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" + +# Add support for old DBus control interface +# (fi.epitest.hostap.WPASupplicant) +#CONFIG_CTRL_IFACE_DBUS=y + +# Add support for new DBus control interface +# (fi.w1.hostap.wpa_supplicant1) +#CONFIG_CTRL_IFACE_DBUS_NEW=y + +# Add introspection support for new DBus control interface +#CONFIG_CTRL_IFACE_DBUS_INTRO=y + +# Add support for loading EAP methods dynamically as shared libraries. +# When this option is enabled, each EAP method can be either included +# statically (CONFIG_EAP_=y) or dynamically (CONFIG_EAP_=dyn). +# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to +# be loaded in the beginning of the wpa_supplicant configuration file +# (see load_dynamic_eap parameter in the example file) before being used in +# the network blocks. +# +# Note that some shared parts of EAP methods are included in the main program +# and in order to be able to use dynamic EAP methods using these parts, the +# main program must have been build with the EAP method enabled (=y or =dyn). +# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries +# unless at least one of them was included in the main build to force inclusion +# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included +# in the main build to be able to load these methods dynamically. +# +# Please also note that using dynamic libraries will increase the total binary +# size. Thus, it may not be the best option for targets that have limited +# amount of memory/flash. +#CONFIG_DYNAMIC_EAP_METHODS=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) +#CONFIG_IEEE80211R=y + +# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) +#CONFIG_DEBUG_FILE=y + +# Enable privilege separation (see README 'Privilege separation' for details) +#CONFIG_PRIVSEP=y + +# Enable mitigation against certain attacks against TKIP by delaying Michael +# MIC error reports by a random amount of time between 0 and 60 seconds +#CONFIG_DELAYED_MIC_ERROR_REPORT=y + +# Enable tracing code for developer debugging +# This tracks use of memory allocations and other registrations and reports +# incorrect use with a backtrace of call (or allocation) location. +#CONFIG_WPA_TRACE=y +# For BSD, comment out these. +#LIBS += -lexecinfo +#LIBS_p += -lexecinfo +#LIBS_c += -lexecinfo + +# Use libbfd to get more details for developer debugging +# This enables use of libbfd to get more detailed symbols for the backtraces +# generated by CONFIG_WPA_TRACE=y. +#CONFIG_WPA_TRACE_BFD=y +# For BSD, comment out these. +#LIBS += -lbfd -liberty -lz +#LIBS_p += -lbfd -liberty -lz +#LIBS_c += -lbfd -liberty -lz + +NEED_80211_COMMON=y + +CONFIG_IBSS_RSN=y diff -purN hostapd-20130302/wpa_supplicant/config.c hostapd-20130302-linux/wpa_supplicant/config.c --- hostapd-20130302/wpa_supplicant/config.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/config.c 2013-07-04 11:17:51.000000000 -0400 @@ -14,6 +14,7 @@ #include "rsn_supp/wpa.h" #include "eap_peer/eap.h" #include "p2p/p2p.h" +#include "drivers/nl80211_copy.h" #include "config.h" @@ -1369,6 +1370,162 @@ static char * wpa_config_write_p2p_clien #endif /* CONFIG_P2P */ +static int wpa_config_parse_mcast_rate(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + ssid->mcast_rate = (int)(strtod(value, NULL) * 10); + + return 0; +} + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_mcast_rate(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value; + int res; + + if (!ssid->mcast_rate == 0) + return NULL; + + value = os_malloc(6); /* longest: 300.0 */ + if (value == NULL) + return NULL; + res = os_snprintf(value, 5, "%.1f", (double)ssid->mcast_rate / 10); + if (res < 0) { + os_free(value); + return NULL; + } + return value; +} +#endif /* NO_CONFIG_WRITE */ + +static int wpa_config_parse_htmode(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int i; + static const struct { + const char *name; + unsigned int val; + } htmap[] = { + { .name = "HT20", .val = NL80211_CHAN_HT20, }, + { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, }, + { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, }, + { .name = "NOHT", .val = NL80211_CHAN_NO_HT, }, + }; + ssid->ht_set = 0;; + for (i = 0; i < 4; i++) { + if (strcasecmp(htmap[i].name, value) == 0) { + ssid->htmode = htmap[i].val; + ssid->ht_set = 1; + break; + } + } + + return 0; +} + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_htmode(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value; + int res; + + value = os_malloc(6); /* longest: HT40+ */ + if (value == NULL) + return NULL; + + switch(ssid->htmode) { + case NL80211_CHAN_HT20: + res = os_snprintf(value, 4, "HT20"); + break; + case NL80211_CHAN_HT40PLUS: + res = os_snprintf(value, 5, "HT40+"); + break; + case NL80211_CHAN_HT40MINUS: + res = os_snprintf(value, 5, "HT40-"); + break; + case NL80211_CHAN_NO_HT: + res = os_snprintf(value, 4, "NOHT"); + break; + default: + os_free(value); + return NULL; + } + + if (res < 0) { + os_free(value); + return NULL; + } + + return value; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_rates(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int i; + char *pos, *r, *sptr, *end; + double rate; + + pos = (char *)value; + r = strtok_r(pos, ",", &sptr); + i = 0; + while (pos && i < NL80211_MAX_SUPP_RATES) { + rate = 0.0; + if (r) + rate = strtod(r, &end); + ssid->rates[i] = rate * 2; + if (*end != '\0' || rate * 2 != ssid->rates[i]) + return 1; + + i++; + r = strtok_r(NULL, ",", &sptr); + } + + return 0; +} + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_rates(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value, *pos; + int res, i; + + if (ssid->rates[0] <= 0) + return NULL; + + value = os_malloc(6 * NL80211_MAX_SUPP_RATES + 1); + if (value == NULL) + return NULL; + pos = value; + for (i = 0; i < NL80211_MAX_SUPP_RATES - 1; i++) { + res = os_snprintf(pos, 6, "%.1f,", (double)ssid->rates[i] / 2); + if (res < 0) { + os_free(value); + return NULL; + } + pos += res; + } + res = os_snprintf(pos, 6, "%.1f", + (double)ssid->rates[NL80211_MAX_SUPP_RATES - 1] / 2); + if (res < 0) { + os_free(value); + return NULL; + } + + value[6 * NL80211_MAX_SUPP_RATES] = '\0'; + return value; +} +#endif /* NO_CONFIG_WRITE */ + /* Helper macros for network block parser */ #ifdef OFFSET @@ -1546,6 +1703,10 @@ static const struct parse_data ssid_fiel { INT(ap_max_inactivity) }, { INT(dtim_period) }, { INT(beacon_int) }, + { INT_RANGE(fixed_freq, 0, 1) }, + { FUNC(rates) }, + { FUNC(mcast_rate) }, + { FUNC(htmode) }, }; #undef OFFSET diff -purN hostapd-20130302/wpa_supplicant/config_ssid.h hostapd-20130302-linux/wpa_supplicant/config_ssid.h --- hostapd-20130302/wpa_supplicant/config_ssid.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/config_ssid.h 2013-07-04 11:17:51.000000000 -0400 @@ -11,6 +11,7 @@ #include "common/defs.h" #include "eap_peer/eap_config.h" +#include "drivers/nl80211_copy.h" #define MAX_SSID_LEN 32 @@ -571,6 +572,12 @@ struct wpa_ssid { * dereferences since it may not be updated in all cases. */ void *parent_cred; + + int fixed_freq; + unsigned char rates[NL80211_MAX_SUPP_RATES]; + double mcast_rate; + int ht_set; + unsigned int htmode; }; #endif /* CONFIG_SSID_H */ diff -purN hostapd-20130302/wpa_supplicant/ctrl_iface.c hostapd-20130302-linux/wpa_supplicant/ctrl_iface.c --- hostapd-20130302/wpa_supplicant/ctrl_iface.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/ctrl_iface.c 2013-07-04 11:17:51.000000000 -0400 @@ -4933,6 +4933,7 @@ char * wpa_supplicant_ctrl_iface_process reply_len = -1; } else if (os_strncmp(buf, "NOTE ", 5) == 0) { wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); +#ifdef CONFIG_CTRL_IFACE_MIB } else if (os_strcmp(buf, "MIB") == 0) { reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); if (reply_len >= 0) { @@ -4944,6 +4945,7 @@ char * wpa_supplicant_ctrl_iface_process else reply_len += res; } +#endif } else if (os_strncmp(buf, "STATUS", 6) == 0) { reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); @@ -5350,6 +5352,7 @@ char * wpa_supplicant_ctrl_iface_process reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); #ifdef CONFIG_AP +#ifdef CONFIG_CTRL_IFACE_MIB } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "STA ", 4) == 0) { @@ -5358,6 +5361,7 @@ char * wpa_supplicant_ctrl_iface_process } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, reply_size); +#endif } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15)) reply_len = -1; diff -purN hostapd-20130302/wpa_supplicant/events.c hostapd-20130302-linux/wpa_supplicant/events.c --- hostapd-20130302/wpa_supplicant/events.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/events.c 2013-07-04 11:17:51.000000000 -0400 @@ -2333,8 +2333,8 @@ static void wpa_supplicant_event_unprot_ } -void wpa_supplicant_event(void *ctx, enum wpa_event_type event, - union wpa_event_data *data) +void supplicant_event(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) { struct wpa_supplicant *wpa_s = ctx; u16 reason_code = 0; diff -purN hostapd-20130302/wpa_supplicant/main.c hostapd-20130302-linux/wpa_supplicant/main.c --- hostapd-20130302/wpa_supplicant/main.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/main.c 2013-07-04 11:17:51.000000000 -0400 @@ -12,6 +12,7 @@ #endif /* __linux__ */ #include "common.h" +#include "build_features.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -25,7 +26,7 @@ static void usage(void) "usage:\n" " wpa_supplicant [-BddhKLqqstuvW] [-P] " "[-g] \\\n" - " -i -c [-C] [-D] " + " -i -c [-C] [-D] [-H]" "[-p] \\\n" " [-b] [-f] [-e] " "\\\n" @@ -67,6 +68,7 @@ static void usage(void) #endif /* CONFIG_DEBUG_LINUX_TRACING */ printf(" -t = include timestamp in debug messages\n" " -h = show this help text\n" + " -H = connect to a hostapd instance to manage state changes\n" " -L = show license (BSD)\n" " -o = override driver parameter for new interfaces\n" " -O = override ctrl_interface parameter for new interfaces\n" @@ -155,7 +157,7 @@ int main(int argc, char *argv[]) for (;;) { c = getopt(argc, argv, - "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW"); + "b:Bc:C:D:de:f:g:hH:i:KLNo:O:p:P:qsTtuv::W"); if (c < 0) break; switch (c) { @@ -199,6 +201,9 @@ int main(int argc, char *argv[]) usage(); exitcode = 0; goto out; + case 'H': + iface->hostapd_ctrl = optarg; + break; case 'i': iface->ifname = optarg; break; @@ -244,8 +249,12 @@ int main(int argc, char *argv[]) break; #endif /* CONFIG_DBUS */ case 'v': - printf("%s\n", wpa_supplicant_version); - exitcode = 0; + if (optarg) { + exitcode = !has_feature(optarg); + } else { + printf("%s\n", wpa_supplicant_version); + exitcode = 0; + } goto out; case 'W': params.wait_for_monitor++; diff -purN hostapd-20130302/wpa_supplicant/Makefile hostapd-20130302-linux/wpa_supplicant/Makefile --- hostapd-20130302/wpa_supplicant/Makefile 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/Makefile 2013-07-06 06:13:59.000000000 -0400 @@ -13,7 +13,12 @@ PKG_CONFIG ?= pkg-config CFLAGS += -I../src CFLAGS += -I../src/utils +ifdef MULTICALL +CFLAGS += -DMULTICALL +endif + -include .config +-include $(if $(MULTICALL),../hostapd/.config) BINALL=wpa_supplicant wpa_cli @@ -75,6 +80,10 @@ OBJS_c = wpa_cli.o ../src/common/wpa_ctr OBJS_c += ../src/utils/wpa_debug.o OBJS_c += ../src/utils/common.o +ifdef MULTICALL +OBJS += ../src/common/wpa_ctrl.o +endif + ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS CONFIG_OS=win32 @@ -704,6 +713,10 @@ ifdef CONFIG_DYNAMIC_EAP_METHODS CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS LIBS += -ldl -rdynamic endif +else + ifdef MULTICALL + OBJS += ../src/eap_common/eap_common.o + endif endif ifdef CONFIG_AP @@ -712,9 +725,11 @@ NEED_EAP_COMMON=y NEED_RSN_AUTHENTICATOR=y CFLAGS += -DCONFIG_AP OBJS += ap.o +ifndef MULTICALL CFLAGS += -DCONFIG_NO_RADIUS CFLAGS += -DCONFIG_NO_ACCOUNTING CFLAGS += -DCONFIG_NO_VLAN +endif OBJS += ../src/ap/hostapd.o OBJS += ../src/ap/wpa_auth_glue.o OBJS += ../src/ap/utils.o @@ -739,6 +754,9 @@ ifdef CONFIG_WNM OBJS += ../src/ap/wnm_ap.o endif ifdef CONFIG_CTRL_IFACE +ifdef CONFIG_CTRL_IFACE_MIB +CFLAGS += -DCONFIG_CTRL_IFACE_MIB +endif OBJS += ../src/ap/ctrl_iface_ap.o endif @@ -769,10 +787,18 @@ endif ifdef CONFIG_HS20 OBJS += ../src/ap/hs20.o endif +else + ifdef MULTICALL + OBJS += ../src/eap_server/eap_server.o + OBJS += ../src/eap_server/eap_server_identity.o + OBJS += ../src/eap_server/eap_server_methods.o + endif endif ifdef NEED_RSN_AUTHENTICATOR +ifndef MULTICALL CFLAGS += -DCONFIG_NO_RADIUS +endif NEED_AES_WRAP=y OBJS += ../src/ap/wpa_auth.o OBJS += ../src/ap/wpa_auth_ie.o @@ -1521,6 +1547,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv) $(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config +wpa_supplicant_multi.a: .config $(BCHECK) $(OBJS) $(EXTRA_progs) + $(Q)$(CC) -c -o wpa_supplicant_multi.o -Dmain=wpa_supplicant_main $(CFLAGS) main.c + @$(E) " CC " $< + @rm -f $@ + @$(AR) cr $@ wpa_supplicant_multi.o $(OBJS) + wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs) $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) @$(E) " LD " $@ @@ -1591,6 +1623,12 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2. %@.service: %.service.arg.in sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ +dump_cflags: + @echo -n $(CFLAGS) " " + +dump_ldflags: + @echo -n $(LDFLAGS) $(LIBS) $(EXTRALIBS) " " + wpa_supplicant.exe: wpa_supplicant mv -f $< $@ wpa_cli.exe: wpa_cli diff -purN hostapd-20130302/wpa_supplicant/wpa_priv.c hostapd-20130302-linux/wpa_supplicant/wpa_priv.c --- hostapd-20130302/wpa_supplicant/wpa_priv.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/wpa_priv.c 2013-07-04 11:17:51.000000000 -0400 @@ -819,8 +819,8 @@ static void wpa_priv_send_ft_response(st } -void wpa_supplicant_event(void *ctx, enum wpa_event_type event, - union wpa_event_data *data) +static void supplicant_event(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) { struct wpa_priv_interface *iface = ctx; @@ -962,6 +962,7 @@ int main(int argc, char *argv[]) if (os_program_init()) return -1; + wpa_supplicant_event = supplicant_event; wpa_priv_fd_workaround(); for (;;) { diff -purN hostapd-20130302/wpa_supplicant/wpa_supplicant.c hostapd-20130302-linux/wpa_supplicant/wpa_supplicant.c --- hostapd-20130302/wpa_supplicant/wpa_supplicant.c 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/wpa_supplicant.c 2013-07-04 11:17:51.000000000 -0400 @@ -107,6 +107,55 @@ extern int wpa_debug_show_keys; extern int wpa_debug_timestamp; extern struct wpa_driver_ops *wpa_drivers[]; +#ifdef MULTICALL +static int hostapd_stop(struct wpa_supplicant *wpa_s) +{ + const char *cmd = "DOWN"; + char buf[256]; + int len = sizeof(buf); + + if (wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL) < 0) { + wpa_printf(MSG_ERROR, "\nFailed to stop hostapd AP interfaces\n"); + return -1; + } + return 0; +} + +static int hostapd_reload(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + char *cmd = NULL; + char buf[256]; + int len = sizeof(buf); + int channel, hw_mode; + int ret; + + if (!bss) + return; + + if (bss->freq < 4000) { + hw_mode = HOSTAPD_MODE_IEEE80211G; + channel = (bss->freq - 2407) / 5; + } else { + hw_mode = HOSTAPD_MODE_IEEE80211A; + channel = (bss->freq - 5000) / 5; + } + + if (asprintf(&cmd, "UPDATE channel=%d sec_chan=0 hw_mode=%d ieee80211n=%d", + channel, hw_mode, !!bss->ht_capab) < 0) { + return -1; + } + + ret = wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL); + free(cmd); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "\nFailed to reload hostapd AP interfaces\n"); + return -1; + } + return 0; +} +#endif + /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -676,8 +725,16 @@ void wpa_supplicant_set_state(struct wpa #endif /* CONFIG_P2P */ sme_sched_obss_scan(wpa_s, 1); +#ifdef MULTICALL + if (wpa_s->hostapd) + hostapd_reload(wpa_s, wpa_s->current_bss); +#endif } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING || state == WPA_ASSOCIATED) { +#ifdef MULTICALL + if (wpa_s->hostapd) + hostapd_stop(wpa_s); +#endif wpa_s->new_connection = 1; wpa_drv_set_operstate(wpa_s, 0); #ifndef IEEE8021X_EAPOL @@ -1513,15 +1570,26 @@ void wpa_supplicant_associate(struct wpa params.ssid_len = ssid->ssid_len; } - if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set && - wpa_s->conf->ap_scan == 2) { - params.bssid = ssid->bssid; - params.fixed_bssid = 1; + if (ssid->mode == WPAS_MODE_IBSS) { + if (ssid->bssid_set && wpa_s->conf->ap_scan == 2) { + params.bssid = ssid->bssid; + params.fixed_bssid = 1; + } + if (ssid->frequency > 0 && params.freq == 0) + /* Initial channel for IBSS */ + params.freq = ssid->frequency; + params.fixed_freq = ssid->fixed_freq; + params.beacon_interval = ssid->beacon_int; + i = 0; + while (i < NL80211_MAX_SUPP_RATES) { + params.rates[i] = ssid->rates[i]; + i++; + } + params.mcast_rate = ssid->mcast_rate; + params.ht_set = ssid->ht_set; + params.htmode = ssid->htmode; } - if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 && - params.freq == 0) - params.freq = ssid->frequency; /* Initial channel for IBSS */ params.wpa_ie = wpa_ie; params.wpa_ie_len = wpa_ie_len; params.pairwise_suite = cipher_pairwise; @@ -2416,7 +2484,7 @@ static struct wpa_supplicant * wpa_suppl if (wpa_s == NULL) return NULL; wpa_s->scan_req = INITIAL_SCAN_REQ; - wpa_s->scan_interval = 5; + wpa_s->scan_interval = 1; wpa_s->new_connection = 1; wpa_s->parent = wpa_s; wpa_s->sched_scanning = 0; @@ -2778,6 +2846,21 @@ static int wpa_supplicant_init_iface(str os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname, sizeof(wpa_s->bridge_ifname)); } +#ifdef MULTICALL + if (iface->hostapd_ctrl) { + char *cmd = "DOWN"; + char buf[256]; + int len = sizeof(buf); + + wpa_s->hostapd = wpa_ctrl_open(iface->hostapd_ctrl); + if (!wpa_s->hostapd) { + wpa_printf(MSG_ERROR, "\nFailed to connect to hostapd\n"); + return -1; + } + if (hostapd_stop(wpa_s) < 0) + return -1; + } +#endif /* RSNA Supplicant Key Management - INITIALIZE */ eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); @@ -2972,6 +3055,9 @@ static void wpa_supplicant_deinit_iface( } } +extern void supplicant_event(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); + /** * wpa_supplicant_add_iface - Add a new network interface @@ -3164,6 +3250,7 @@ struct wpa_global * wpa_supplicant_init( wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb); #endif /* CONFIG_NO_WPA_MSG */ + wpa_supplicant_event = supplicant_event; wpa_debug_open_file(params->wpa_debug_file_path); if (params->wpa_debug_syslog) wpa_debug_open_syslog(); diff -purN hostapd-20130302/wpa_supplicant/wpa_supplicant_i.h hostapd-20130302-linux/wpa_supplicant/wpa_supplicant_i.h --- hostapd-20130302/wpa_supplicant/wpa_supplicant_i.h 2013-03-04 09:34:02.000000000 -0500 +++ hostapd-20130302-linux/wpa_supplicant/wpa_supplicant_i.h 2013-07-04 11:17:51.000000000 -0400 @@ -96,6 +96,8 @@ struct wpa_interface { * receiving of EAPOL frames from an additional interface. */ const char *bridge_ifname; + + const char *hostapd_ctrl; }; /** @@ -305,6 +307,8 @@ struct wpa_supplicant { #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ char bridge_ifname[16]; + struct wpa_ctrl *hostapd; + char *confname; struct wpa_config *conf; int countermeasures; ================================================ FILE: hostapd_wrapper/hostapd2/hostapd_linux.conf ================================================ ##### hostapd configuration file ############################################## # Empty lines and lines starting with # are ignored # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for # management frames); ath0 for madwifi interface=wlan0 # In case of madwifi, atheros, and nl80211 driver interfaces, an additional # configuration parameter, bridge, may be used to notify hostapd if the # interface is included in a bridge. This parameter is not used with Host AP # driver. If the bridge parameter is not set, the drivers will automatically # figure out the bridge interface (assuming sysfs is enabled and mounted to # /sys) and this parameter may not be needed. # # For nl80211, this parameter can be used to request the AP interface to be # added to the bridge automatically (brctl may refuse to do this before hostapd # has been started to change the interface mode). If needed, the bridge # interface is also created. #bridge=br0 # Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd); # default: hostap). nl80211 is used with all Linux mac80211 drivers. # Use driver=none if building hostapd as a standalone RADIUS server that does # not control any wireless/wired driver. # driver=hostap driver=capwap # hostapd event logger configuration # # Two output method: syslog and stdout (only usable if not forking to # background). # # Module bitfield (ORed bitfield of modules that will be logged; -1 = all # modules): # bit 0 (1) = IEEE 802.11 # bit 1 (2) = IEEE 802.1X # bit 2 (4) = RADIUS # bit 3 (8) = WPA # bit 4 (16) = driver interface # bit 5 (32) = IAPP # bit 6 (64) = MLME # # Levels (minimum value for logged events): # 0 = verbose debugging # 1 = debugging # 2 = informational messages # 3 = notification # 4 = warning # logger_syslog=-1 logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 # Dump file for state information (on SIGUSR1) dump_file=/tmp/hostapd.dump # Interface for separate control program. If this is specified, hostapd # will create this directory and a UNIX domain socket for listening to requests # from external programs (CLI/GUI, etc.) for status information and # configuration. The socket file will be named based on the interface name, so # multiple hostapd processes/interfaces can be run at the same time if more # than one interface is used. # /var/run/hostapd is the recommended directory for sockets and by default, # hostapd_cli will use it when trying to connect with hostapd. ctrl_interface=/var/run/hostapd # Access control for the control interface can be configured by setting the # directory to allow only members of a group to use sockets. This way, it is # possible to run hostapd as root (since it needs to change network # configuration and open raw sockets) and still allow GUI/CLI components to be # run as non-root users. However, since the control interface can be used to # change the network configuration, this access needs to be protected in many # cases. By default, hostapd is configured to use gid 0 (root). If you # want to allow non-root users to use the contron interface, add a new group # and change this value to match with that group. Add users that should have # control interface access to this group. # # This variable can be a group name or gid. #ctrl_interface_group=wheel ctrl_interface_group=0 ##### IEEE 802.11 related configuration ####################################### # SSID to be used in IEEE 802.11 management frames ssid=SET_BY_LINUX_HOSTAPDCONF_FILE # Country code (ISO/IEC 3166-1). Used to set regulatory domain. # Set as needed to indicate country in which device is operating. # This can limit available channels and transmit power. #country_code=US # Enable IEEE 802.11d. This advertises the country_code and the set of allowed # channels and transmit power levels based on the regulatory limits. The # country_code setting must be configured with the correct country for # IEEE 802.11d functions. # (default: 0 = disabled) #ieee80211d=1 # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, # Default: IEEE 802.11b hw_mode=b # Channel number (IEEE 802.11) # (default: 0, i.e., not set) # Please note that some drivers do not use this value from hostapd and the # channel will need to be configured separately with iwconfig. channel=1 # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 # DTIM (delivery traffic information message) period (range 1..255): # number of beacons between DTIMs (1 = every beacon includes DTIM element) # (default: 2) dtim_period=2 # Maximum number of stations allowed in station table. New stations will be # rejected after the station table is full. IEEE 802.11 has a limit of 2007 # different association IDs, so this number should not be larger than that. # (default: 2007) max_num_sta=255 # RTS/CTS threshold; 2347 = disabled (default); range 0..2347 # If this field is not included in hostapd.conf, hostapd will not control # RTS threshold and 'iwconfig wlan# rts ' can be used to set it. rts_threshold=2347 # Fragmentation threshold; 2346 = disabled (default); range 256..2346 # If this field is not included in hostapd.conf, hostapd will not control # fragmentation threshold and 'iwconfig wlan# frag ' can be used to set # it. fragm_threshold=2346 # Rate configuration # Default is to enable all rates supported by the hardware. This configuration # item allows this list be filtered so that only the listed rates will be left # in the list. If the list is empty, all rates are used. This list can have # entries that are not in the list of rates the hardware supports (such entries # are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110. # If this item is present, at least one rate have to be matching with the rates # hardware supports. # default: use the most common supported rate setting for the selected # hw_mode (i.e., this line can be removed from configuration file in most # cases) #supported_rates=10 20 55 110 60 90 120 180 240 360 480 540 # Basic rate set configuration # List of rates (in 100 kbps) that are included in the basic rate set. # If this item is not included, usually reasonable default set is used. #basic_rates=10 20 #basic_rates=10 20 55 110 #basic_rates=60 120 240 # Short Preamble # This parameter can be used to enable optional use of short preamble for # frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance. # This applies only to IEEE 802.11b-compatible networks and this should only be # enabled if the local hardware supports use of short preamble. If any of the # associated STAs do not support short preamble, use of short preamble will be # disabled (and enabled when such STAs disassociate) dynamically. # 0 = do not allow use of short preamble (default) # 1 = allow use of short preamble preamble=1 # Station MAC address -based authentication # Please note that this kind of access control requires a driver that uses # hostapd to take care of management frame processing and as such, this can be # used with driver=hostap or driver=nl80211, but not with driver=madwifi. # 0 = accept unless in deny list # 1 = deny unless in accept list # 2 = use external RADIUS server (accept/deny lists are searched first) macaddr_acl=0 # Accept/deny lists are read from separate files (containing list of # MAC addresses, one per line). Use absolute path name to make sure that the # files can be read on SIGHUP configuration reloads. #accept_mac_file=/etc/hostapd.accept #deny_mac_file=/etc/hostapd.deny # IEEE 802.11 specifies two authentication algorithms. hostapd can be # configured to allow both of these or only one. Open system authentication # should be used with IEEE 802.1X. # Bit fields of allowed authentication algorithms: # bit 0 = Open System Authentication # bit 1 = Shared Key Authentication (requires WEP) auth_algs=1 # Send empty SSID in beacons and ignore probe request frames that do not # specify full SSID, i.e., require stations to know SSID. # default: disabled (0) # 1 = send empty (length=0) SSID in beacon and ignore probe request for # broadcast SSID # 2 = clear SSID (ASCII 0), but keep the original length (this may be required # with some clients that do not support empty SSID) and ignore probe # requests for broadcast SSID ignore_broadcast_ssid=0 # TX queue parameters (EDCF / bursting) # tx_queue__ # queues: data0, data1, data2, data3, after_beacon, beacon # (data0 is the highest priority queue) # parameters: # aifs: AIFS (default 2) # cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023) # cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin # burst: maximum length (in milliseconds with precision of up to 0.1 ms) for # bursting # # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # These parameters are used by the access point when transmitting frames # to the clients. # # Low priority / AC_BK = background #tx_queue_data3_aifs=7 #tx_queue_data3_cwmin=15 #tx_queue_data3_cwmax=1023 #tx_queue_data3_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0 # # Normal priority / AC_BE = best effort #tx_queue_data2_aifs=3 #tx_queue_data2_cwmin=15 #tx_queue_data2_cwmax=63 #tx_queue_data2_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0 # # High priority / AC_VI = video #tx_queue_data1_aifs=1 #tx_queue_data1_cwmin=7 #tx_queue_data1_cwmax=15 #tx_queue_data1_burst=3.0 # Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0 # # Highest priority / AC_VO = voice #tx_queue_data0_aifs=1 #tx_queue_data0_cwmin=3 #tx_queue_data0_cwmax=7 #tx_queue_data0_burst=1.5 # Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3 # 802.1D Tag (= UP) to AC mappings # WMM specifies following mapping of data frames to different ACs. This mapping # can be configured using Linux QoS/tc and sch_pktpri.o module. # 802.1D Tag 802.1D Designation Access Category WMM Designation # 1 BK AC_BK Background # 2 - AC_BK Background # 0 BE AC_BE Best Effort # 3 EE AC_BE Best Effort # 4 CL AC_VI Video # 5 VI AC_VI Video # 6 VO AC_VO Voice # 7 NC AC_VO Voice # Data frames with no priority information: AC_BE # Management frames: AC_VO # PS-Poll frames: AC_BE # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # for 802.11a or 802.11g networks # These parameters are sent to WMM clients when they associate. # The parameters will be used by WMM clients for frames transmitted to the # access point. # # note - txop_limit is in units of 32microseconds # note - acm is admission control mandatory flag. 0 = admission control not # required, 1 = mandatory # note - here cwMin and cmMax are in exponent form. the actual cw value used # will be (2^n)-1 where n is the value given here # wmm_enabled=1 # # WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] # Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver) #uapsd_advertisement_enabled=1 # # Low priority / AC_BK = background wmm_ac_bk_cwmin=4 wmm_ac_bk_cwmax=10 wmm_ac_bk_aifs=7 wmm_ac_bk_txop_limit=0 wmm_ac_bk_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=10 # # Normal priority / AC_BE = best effort wmm_ac_be_aifs=3 wmm_ac_be_cwmin=4 wmm_ac_be_cwmax=10 wmm_ac_be_txop_limit=0 wmm_ac_be_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=7 # # High priority / AC_VI = video wmm_ac_vi_aifs=2 wmm_ac_vi_cwmin=3 wmm_ac_vi_cwmax=4 wmm_ac_vi_txop_limit=94 wmm_ac_vi_acm=0 # Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188 # # Highest priority / AC_VO = voice wmm_ac_vo_aifs=2 wmm_ac_vo_cwmin=2 wmm_ac_vo_cwmax=3 wmm_ac_vo_txop_limit=47 wmm_ac_vo_acm=0 # Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 # Static WEP key configuration # # The key number to use when transmitting. # It must be between 0 and 3, and the corresponding key must be set. # default: not set #wep_default_key=0 # The WEP keys to use. # A key may be a quoted string or unquoted hexadecimal digits. # The key length should be 5, 13, or 16 characters, or 10, 26, or 32 # digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or # 128-bit (152-bit) WEP is used. # Only the default key must be supplied; the others are optional. # default: not set #wep_key0=123456789a #wep_key1="vwxyz" #wep_key2=0102030405060708090a0b0c0d #wep_key3=".2.4.6.8.0.23" # Station inactivity limit # # If a station does not send anything in ap_max_inactivity seconds, an # empty data frame is sent to it in order to verify whether it is # still in range. If this frame is not ACKed, the station will be # disassociated and then deauthenticated. This feature is used to # clear station table of old entries when the STAs move out of the # range. # # The station can associate again with the AP if it is still in range; # this inactivity poll is just used as a nicer way of verifying # inactivity; i.e., client will not report broken connection because # disassociation frame is not sent immediately without first polling # the STA with a data frame. # default: 300 (i.e., 5 minutes) #ap_max_inactivity=300 # Disassociate stations based on excessive transmission failures or other # indications of connection loss. This depends on the driver capabilities and # may not be available with all drivers. disassoc_low_ack=1 # Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to # remain asleep). Default: 65535 (no limit apart from field size) #max_listen_interval=100 # WDS (4-address frame) mode with per-station virtual interfaces # (only supported with driver=nl80211) # This mode allows associated stations to use 4-address frames to allow layer 2 # bridging to be used. #wds_sta=1 # If bridge parameter is set, the WDS STA interface will be added to the same # bridge by default. This can be overridden with the wds_bridge parameter to # use a separate bridge. #wds_bridge=wds-br0 # Client isolation can be used to prevent low-level bridging of frames between # associated stations in the BSS. By default, this bridging is allowed. #ap_isolate=1 ##### IEEE 802.11n related configuration ###################################### # ieee80211n: Whether IEEE 802.11n (HT) is enabled # 0 = disabled (default) # 1 = enabled # Note: You will also need to enable WMM for full HT functionality. #ieee80211n=1 # ht_capab: HT capabilities (list of flags) # LDPC coding capability: [LDPC] = supported # Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary # channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz # with secondary channel below the primary channel # (20 MHz only if neither is set) # Note: There are limits on which channels can be used with HT40- and # HT40+. Following table shows the channels that may be available for # HT40- and HT40+ use per IEEE 802.11n Annex J: # freq HT40- HT40+ # 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan) # 5 GHz 40,48,56,64 36,44,52,60 # (depending on the location, not all of these channels may be available # for use) # Please note that 40 MHz channels may switch their primary and secondary # channels if needed or creation of 40 MHz channel maybe rejected based # on overlapping BSSes. These changes are done automatically when hostapd # is setting up the 40 MHz channel. # Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC] # (SMPS disabled if neither is set) # HT-greenfield: [GF] (disabled if not set) # Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) # Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) # Tx STBC: [TX-STBC] (disabled if not set) # Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial # streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC # disabled if none of these set # HT-delayed Block Ack: [DELAYED-BA] (disabled if not set) # Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not # set) # DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) # PSMP support: [PSMP] (disabled if not set) # L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) #ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] # Require stations to support HT PHY (reject association if they do not) #require_ht=1 ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization ieee8021x=1 # IEEE 802.1X/EAPOL version # hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL # version 2. However, there are many client implementations that do not handle # the new version number correctly (they seem to drop the frames completely). # In order to make hostapd interoperate with these clients, the version number # can be set to the older version (1) with this configuration value. #eapol_version=2 # Optional displayable message sent with EAP Request-Identity. The first \0 # in this string will be converted to ASCII-0 (nul). This can be used to # separate network info (comma separated list of attribute=value pairs); see, # e.g., RFC 4284. #eap_message=hello #eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com # WEP rekeying (disabled if key lengths are not set or are set to 0) # Key lengths for default/broadcast and individual/unicast keys: # 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits) # 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits) #wep_key_len_broadcast=5 #wep_key_len_unicast=5 # Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once) #wep_rekey_period=300 # EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if # only broadcast keys are used) eapol_key_index_workaround=1 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable # reauthentication). #eap_reauth_period=3600 # Use PAE group address (01:80:c2:00:00:03) instead of individual target # address when sending EAPOL frames with driver=wired. This is the most common # mechanism used in wired authentication, but it also requires that the port # is only used by one station. #use_pae_group_addr=1 ##### Integrated EAP server ################################################### # Optionally, hostapd can be configured to use an integrated EAP server # to process EAP authentication locally without need for an external RADIUS # server. This functionality can be used both as a local authentication server # for IEEE 802.1X/EAPOL and as a RADIUS server for other devices. # Use integrated EAP server instead of external RADIUS authentication # server. This is also needed if hostapd is configured to act as a RADIUS # authentication server. eap_server=0 # Path for EAP server user database #eap_user_file=/etc/hostapd.eap_user # CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS #ca_cert=/etc/hostapd.ca.pem # Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS #server_cert=/etc/hostapd.server.pem # Private key matching with the server certificate for EAP-TLS/PEAP/TTLS # This may point to the same file as server_cert if both certificate and key # are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be # used by commenting out server_cert and specifying the PFX file as the # private_key. #private_key=/etc/hostapd.server.prv # Passphrase for private key #private_key_passwd=secret passphrase # Enable CRL verification. # Note: hostapd does not yet support CRL downloading based on CDP. Thus, a # valid CRL signed by the CA is required to be included in the ca_cert file. # This can be done by using PEM format for CA certificate and CRL and # concatenating these into one file. Whenever CRL changes, hostapd needs to be # restarted to take the new CRL into use. # 0 = do not verify CRLs (default) # 1 = check the CRL of the user certificate # 2 = check all CRLs in the certificate path #check_crl=1 # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an # ephemeral DH key exchange. In most cases, the default RSA authentication does # not use this configuration. However, it is possible setup RSA to use # ephemeral DH key exchange. In addition, ciphers with DSA keys always use # ephemeral DH keys. This can be used to achieve forward secrecy. If the file # is in DSA parameters format, it will be automatically converted into DH # params. This parameter is required if anonymous EAP-FAST is used. # You can generate DH parameters file with OpenSSL, e.g., # "openssl dhparam -out /etc/hostapd.dh.pem 1024" #dh_file=/etc/hostapd.dh.pem # Fragment size for EAP methods #fragment_size=1400 # Configuration data for EAP-SIM database/authentication gateway interface. # This is a text string in implementation specific format. The example # implementation in eap_sim_db.c uses this as the UNIX domain socket name for # the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:" # prefix. #eap_sim_db=unix:/tmp/hlr_auc_gw.sock # Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, # random value. It is configured as a 16-octet value in hex format. It can be # generated, e.g., with the following command: # od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' ' #pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f # EAP-FAST authority identity (A-ID) # A-ID indicates the identity of the authority that issues PACs. The A-ID # should be unique across all issuing servers. In theory, this is a variable # length field, but due to some existing implementations requiring A-ID to be # 16 octets in length, it is strongly recommended to use that length for the # field to provid interoperability with deployed peer implementations. This # field is configured in hex format. #eap_fast_a_id=101112131415161718191a1b1c1d1e1f # EAP-FAST authority identifier information (A-ID-Info) # This is a user-friendly name for the A-ID. For example, the enterprise name # and server name in a human-readable format. This field is encoded as UTF-8. #eap_fast_a_id_info=test server # Enable/disable different EAP-FAST provisioning modes: #0 = provisioning disabled #1 = only anonymous provisioning allowed #2 = only authenticated provisioning allowed #3 = both provisioning modes allowed (default) #eap_fast_prov=3 # EAP-FAST PAC-Key lifetime in seconds (hard limit) #pac_key_lifetime=604800 # EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard # limit). The server will generate a new PAC-Key when this number of seconds # (or fewer) of the lifetime remains. #pac_key_refresh_time=86400 # EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND # (default: 0 = disabled). #eap_sim_aka_result_ind=1 # Trusted Network Connect (TNC) # If enabled, TNC validation will be required before the peer is allowed to # connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other # EAP method is enabled, the peer will be allowed to connect without TNC. #tnc=1 ##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) ####################### # Interface to be used for IAPP broadcast packets #iapp_interface=eth0 ##### RADIUS client configuration ############################################# # for IEEE 802.1X with external Authentication Server, IEEE 802.11 # authentication with external ACL for MAC addresses, and accounting # The own IP address of the access point (used as NAS-IP-Address) own_ip_addr=127.0.0.1 # Optional NAS-Identifier string for RADIUS messages. When used, this should be # a unique to the NAS within the scope of the RADIUS server. For example, a # fully qualified domain name can be used here. # When using IEEE 802.11r, nas_identifier must be set and must be between 1 and # 48 octets long. nas_identifier=OpenWrt # RADIUS authentication server auth_server_addr=31.1.1.1 auth_server_port=1812 auth_server_shared_secret=SharedSecret # RADIUS accounting server #acct_server_addr=127.0.0.1 #acct_server_port=1813 #acct_server_shared_secret=secret # Secondary RADIUS servers; to be used if primary one does not reply to # RADIUS packets. These are optional and there can be more than one secondary # server listed. #auth_server_addr=127.0.0.2 #auth_server_port=1812 #auth_server_shared_secret=secret2 # #acct_server_addr=127.0.0.2 #acct_server_port=1813 #acct_server_shared_secret=secret2 # Retry interval for trying to return to the primary RADIUS server (in # seconds). RADIUS client code will automatically try to use the next server # when the current server is not replying to requests. If this interval is set, # primary server will be retried after configured amount of time even if the # currently used secondary server is still working. #radius_retry_primary_interval=600 # Interim accounting update interval # If this is set (larger than 0) and acct_server is configured, hostapd will # send interim accounting updates every N seconds. Note: if set, this overrides # possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this # value should not be configured in hostapd.conf, if RADIUS server is used to # control the interim interval. # This value should not be less 600 (10 minutes) and must not be less than # 60 (1 minute). #radius_acct_interim_interval=600 # Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN # is used for the stations. This information is parsed from following RADIUS # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value # VLANID as a string). vlan_file option below must be configured if dynamic # VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be # used to set static client MAC address to VLAN ID mapping. # 0 = disabled (default) # 1 = option; use default interface if RADIUS server does not include VLAN ID # 2 = required; reject authentication if RADIUS server does not include VLAN ID #dynamic_vlan=0 # VLAN interface list for dynamic VLAN mode is read from a separate text file. # This list is used to map VLAN ID from the RADIUS server to a network # interface. Each station is bound to one interface in the same way as with # multiple BSSIDs or SSIDs. Each line in this text file is defining a new # interface and the line must include VLAN ID and interface name separated by # white space (space or tab). #vlan_file=/etc/hostapd.vlan # Interface where 802.1q tagged packets should appear when a RADIUS server is # used to determine which VLAN a station is on. hostapd creates a bridge for # each VLAN. Then hostapd adds a VLAN interface (associated with the interface # indicated by 'vlan_tagged_interface') and the appropriate wireless interface # to the bridge. #vlan_tagged_interface=eth0 ##### RADIUS authentication server configuration ############################## # hostapd can be used as a RADIUS authentication server for other hosts. This # requires that the integrated EAP server is also enabled and both # authentication services are sharing the same configuration. # File name of the RADIUS clients configuration for the RADIUS server. If this # commented out, RADIUS server is disabled. #radius_server_clients=/etc/hostapd.radius_clients # The UDP port number for the RADIUS authentication server #radius_server_auth_port=1812 # Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API) #radius_server_ipv6=1 ##### WPA/IEEE 802.11i configuration ########################################## # Enable WPA. Setting this variable configures the AP to require WPA (either # WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either # wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. # For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), # RADIUS authentication server must be configured, and WPA-EAP must be included # in wpa_key_mgmt. # This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) # and/or WPA2 (full IEEE 802.11i/RSN): # bit0 = WPA # bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) wpa=2 # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase # (8..63 characters) that will be converted to PSK. This conversion uses SSID # so the PSK changes when ASCII passphrase is used and the SSID is changed. # wpa_psk (dot11RSNAConfigPSKValue) # wpa_passphrase (dot11RSNAConfigPSKPassPhrase) #wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef #wpa_passphrase=secret passphrase # Optionally, WPA PSKs can be read from a separate text file (containing list # of (PSK,MAC address) pairs. This allows more than one PSK to be configured. # Use absolute path name to make sure that the files can be read on SIGHUP # configuration reloads. #wpa_psk_file=/etc/hostapd.wpa_psk # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The # entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be # added to enable SHA256-based stronger algorithms. # (dot11RSNAConfigAuthenticationSuitesTable) wpa_key_mgmt=WPA-EAP # Set of accepted cipher suites (encryption algorithms) for pairwise keys # (unicast packets). This is a space separated list of algorithms: # CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] # TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] # Group cipher suite (encryption algorithm for broadcast and multicast frames) # is automatically selected based on this configuration. If only CCMP is # allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, # TKIP will be used as the group cipher. # (dot11RSNAConfigPairwiseCiphersTable) # Pairwise cipher for WPA (v1) (default: TKIP) wpa_pairwise=CCMP # Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) #rsn_pairwise=CCMP # Time interval for rekeying GTK (broadcast/multicast encryption keys) in # seconds. (dot11RSNAConfigGroupRekeyTime) #wpa_group_rekey=600 # Rekey GTK when any STA that possesses the current GTK is leaving the BSS. # (dot11RSNAConfigGroupRekeyStrict) #wpa_strict_rekey=1 # Time interval for rekeying GMK (master key used internally to generate GTKs # (in seconds). #wpa_gmk_rekey=86400 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of # PTK to mitigate some attacks against TKIP deficiencies. #wpa_ptk_rekey=600 # Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up # roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN # authentication and key handshake before actually associating with a new AP. # (dot11RSNAPreauthenticationEnabled) #rsn_preauth=1 # # Space separated list of interfaces from which pre-authentication frames are # accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all # interface that are used for connections to other APs. This could include # wired interfaces and WDS links. The normal wireless data interface towards # associated stations (e.g., wlan0) should not be added, since # pre-authentication is only used with APs other than the currently associated # one. #rsn_preauth_interfaces=eth0 # peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is # allowed. This is only used with RSN/WPA2. # 0 = disabled (default) # 1 = enabled #peerkey=1 # ieee80211w: Whether management frame protection (MFP) is enabled # 0 = disabled (default) # 1 = optional # 2 = required #ieee80211w=0 # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) # (maximum time to wait for a SA Query response) # dot11AssociationSAQueryMaximumTimeout, 1...4294967295 #assoc_sa_query_max_timeout=1000 # Association SA Query retry timeout (in TU = 1.024 ms; for MFP) # (time between two subsequent SA Query requests) # dot11AssociationSAQueryRetryTimeout, 1...4294967295 #assoc_sa_query_retry_timeout=201 # disable_pmksa_caching: Disable PMKSA caching # This parameter can be used to disable caching of PMKSA created through EAP # authentication. RSN preauthentication may still end up using PMKSA caching if # it is enabled (rsn_preauth=1). # 0 = PMKSA caching enabled (default) # 1 = PMKSA caching disabled disable_pmksa_caching=0 # okc: Opportunistic Key Caching (aka Proactive Key Caching) # Allow PMK cache to be shared opportunistically among configured interfaces # and BSSes (i.e., all configurations within a single hostapd process). # 0 = disabled (default) # 1 = enabled okc=0 ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) # MDID is used to indicate a group of APs (within an ESS, i.e., sharing the # same SSID) between which a STA can use Fast BSS Transition. # 2-octet identifier as a hex string. #mobility_domain=a1b2 # PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID) # 1 to 48 octet identifier. # This is configured with nas_identifier (see RADIUS client section above). # Default lifetime of the PMK-RO in minutes; range 1..65535 # (dot11FTR0KeyLifetime) #r0_key_lifetime=10000 # PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID) # 6-octet identifier as a hex string. #r1_key_holder=000102030405 # Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535) # (dot11FTReassociationDeadline) #reassociation_deadline=1000 # List of R0KHs in the same Mobility Domain # format: <128-bit key as hex string> # This list is used to map R0KH-ID (NAS Identifier) to a destination MAC # address when requesting PMK-R1 key from the R0KH that the STA used during the # Initial Mobility Domain Association. #r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f #r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff # And so on.. One line per R0KH. # List of R1KHs in the same Mobility Domain # format: <128-bit key as hex string> # This list is used to map R1KH-ID to a destination MAC address when sending # PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD # that can request PMK-R1 keys. #r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f #r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff # And so on.. One line per R1KH. # Whether PMK-R1 push is enabled at R0KH # 0 = do not push PMK-R1 to all configured R1KHs (default) # 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived #pmk_r1_push=1 ##### Neighbor table ########################################################## # Maximum number of entries kept in AP table (either for neigbor table or for # detecting Overlapping Legacy BSS Condition). The oldest entry will be # removed when adding a new entry that would make the list grow over this # limit. Note! WFA certification for IEEE 802.11g requires that OLBC is # enabled, so this field should not be set to 0 when using IEEE 802.11g. # default: 255 #ap_table_max_size=255 # Number of seconds of no frames received after which entries may be deleted # from the AP table. Since passive scanning is not usually performed frequently # this should not be set to very small value. In addition, there is no # guarantee that every scan cycle will receive beacon frames from the # neighboring APs. # default: 60 #ap_table_expiration_time=3600 ##### Wi-Fi Protected Setup (WPS) ############################################# # WPS state # 0 = WPS disabled (default) # 1 = WPS enabled, not configured # 2 = WPS enabled, configured #wps_state=2 # AP can be configured into a locked state where new WPS Registrar are not # accepted, but previously authorized Registrars (including the internal one) # can continue to add new Enrollees. #ap_setup_locked=1 # Universally Unique IDentifier (UUID; see RFC 4122) of the device # This value is used as the UUID for the internal WPS Registrar. If the AP # is also using UPnP, this value should be set to the device's UPnP UUID. # If not configured, UUID will be generated based on the local MAC address. #uuid=12345678-9abc-def0-1234-56789abcdef0 # Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs # that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the # default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of # per-device PSKs is recommended as the more secure option (i.e., make sure to # set wpa_psk_file when using WPS with WPA-PSK). # When an Enrollee requests access to the network with PIN method, the Enrollee # PIN will need to be entered for the Registrar. PIN request notifications are # sent to hostapd ctrl_iface monitor. In addition, they can be written to a # text file that could be used, e.g., to populate the AP administration UI with # pending PIN requests. If the following variable is set, the PIN requests will # be written to the configured file. #wps_pin_requests=/var/run/hostapd_wps_pin_requests # Device Name # User-friendly description of device; up to 32 octets encoded in UTF-8 #device_name=Wireless AP # Manufacturer # The manufacturer of the device (up to 64 ASCII characters) #manufacturer=Company # Model Name # Model of the device (up to 32 ASCII characters) #model_name=WAP # Model Number # Additional device description (up to 32 ASCII characters) #model_number=123 # Serial Number # Serial number of the device (up to 32 characters) #serial_number=12345 # Primary Device Type # Used format: -- # categ = Category as an integer value # OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for # default WPS OUI # subcateg = OUI-specific Sub Category as an integer value # Examples: # 1-0050F204-1 (Computer / PC) # 1-0050F204-2 (Computer / Server) # 5-0050F204-1 (Storage / NAS) # 6-0050F204-1 (Network Infrastructure / AP) #device_type=6-0050F204-1 # OS Version # 4-octet operating system version number (hex string) #os_version=01020300 # Config Methods # List of the supported configuration methods # Available methods: usba ethernet label display ext_nfc_token int_nfc_token # nfc_interface push_button keypad virtual_display physical_display # virtual_push_button physical_push_button #config_methods=label virtual_display virtual_push_button keypad # WPS capability discovery workaround for PBC with Windows 7 # Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting # as a Registrar and using M1 from the AP. The config methods attribute in that # message is supposed to indicate only the configuration method supported by # the AP in Enrollee role, i.e., to add an external Registrar. For that case, # PBC shall not be used and as such, the PushButton config method is removed # from M1 by default. If pbc_in_m1=1 is included in the configuration file, # the PushButton config method is left in M1 (if included in config_methods # parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label # in the AP). #pbc_in_m1=1 # Static access point PIN for initial configuration and adding Registrars # If not set, hostapd will not allow external WPS Registrars to control the # access point. The AP PIN can also be set at runtime with hostapd_cli # wps_ap_pin command. Use of temporary (enabled by user action) and random # AP PIN is much more secure than configuring a static AP PIN here. As such, # use of the ap_pin parameter is not recommended if the AP device has means for # displaying a random PIN. #ap_pin=12345670 # Skip building of automatic WPS credential # This can be used to allow the automatically generated Credential attribute to # be replaced with pre-configured Credential(s). #skip_cred_build=1 # Additional Credential attribute(s) # This option can be used to add pre-configured Credential attributes into M8 # message when acting as a Registrar. If skip_cred_build=1, this data will also # be able to override the Credential attribute that would have otherwise been # automatically generated based on network configuration. This configuration # option points to an external file that much contain the WPS Credential # attribute(s) as binary data. #extra_cred=hostapd.cred # Credential processing # 0 = process received credentials internally (default) # 1 = do not process received credentials; just pass them over ctrl_iface to # external program(s) # 2 = process received credentials internally and pass them over ctrl_iface # to external program(s) # Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and # extra_cred be used to provide the Credential data for Enrollees. # # wps_cred_processing=1 will disabled automatic updates of hostapd.conf file # both for Credential processing and for marking AP Setup Locked based on # validation failures of AP PIN. An external program is responsible on updating # the configuration appropriately in this case. #wps_cred_processing=0 # AP Settings Attributes for M7 # By default, hostapd generates the AP Settings Attributes for M7 based on the # current configuration. It is possible to override this by providing a file # with pre-configured attributes. This is similar to extra_cred file format, # but the AP Settings attributes are not encapsulated in a Credential # attribute. #ap_settings=hostapd.ap_settings # WPS UPnP interface # If set, support for external Registrars is enabled. #upnp_iface=br0 # Friendly Name (required for UPnP) # Short description for end use. Should be less than 64 characters. #friendly_name=WPS Access Point # Manufacturer URL (optional for UPnP) #manufacturer_url=http://www.example.com/ # Model Description (recommended for UPnP) # Long description for end user. Should be less than 128 characters. #model_description=Wireless Access Point # Model URL (optional for UPnP) #model_url=http://www.example.com/model/ # Universal Product Code (optional for UPnP) # 12-digit, all-numeric code that identifies the consumer package. #upc=123456789012 ##### Wi-Fi Direct (P2P) ###################################################### # Enable P2P Device management #manage_p2p=1 # Allow cross connection #allow_cross_connection=1 #### TDLS (IEEE 802.11z-2010) ################################################# # Prohibit use of TDLS in this BSS #tdls_prohibit=1 # Prohibit use of TDLS Channel Switching in this BSS #tdls_prohibit_chan_switch=1 ##### IEEE 802.11v-2011 ####################################################### # Time advertisement # 0 = disabled (default) # 2 = UTC time at which the TSF timer is 0 #time_advertisement=2 # Local time zone as specified in 8.3 of IEEE Std 1003.1-2004: # stdoffset[dst[offset][,start[/time],end[/time]]] #time_zone=EST5 ##### IEEE 802.11u-2011 ####################################################### # Enable Interworking service #interworking=1 # Access Network Type # 0 = Private network # 1 = Private network with guest access # 2 = Chargeable public network # 3 = Free public network # 4 = Personal device network # 5 = Emergency services only network # 14 = Test or experimental # 15 = Wildcard #access_network_type=0 # Whether the network provides connectivity to the Internet # 0 = Unspecified # 1 = Network provides connectivity to the Internet #internet=1 # Additional Step Required for Access # Note: This is only used with open network, i.e., ASRA shall ne set to 0 if # RSN is used. #asra=0 # Emergency services reachable #esr=0 # Unauthenticated emergency service accessible #uesa=0 # Venue Info (optional) # The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34. # Example values (group,type): # 0,0 = Unspecified # 1,7 = Convention Center # 1,13 = Coffee Shop # 2,0 = Unspecified Business # 7,1 Private Residence #venue_group=7 #venue_type=1 # Homogeneous ESS identifier (optional; dot11HESSID) # If set, this shall be identifical to one of the BSSIDs in the homogeneous # ESS and this shall be set to the same value across all BSSs in homogeneous # ESS. #hessid=02:03:04:05:06:07 # Roaming Consortium List # Arbitrary number of Roaming Consortium OIs can be configured with each line # adding a new OI to the list. The first three entries are available through # Beacon and Probe Response frames. Any additional entry will be available only # through ANQP queries. Each OI is between 3 and 15 octets and is configured a # a hexstring. #roaming_consortium=021122 #roaming_consortium=2233445566 ##### Multiple BSSID support ################################################## # # Above configuration is using the default interface (wlan#, or multi-SSID VLAN # interfaces). Other BSSIDs can be added by using separator 'bss' with # default interface name to be allocated for the data packets of the new BSS. # # hostapd will generate BSSID mask based on the BSSIDs that are # configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is # not the case, the MAC address of the radio must be changed before starting # hostapd (ifconfig wlan0 hw ether ). If a BSSID is configured for # every secondary BSS, this limitation is not applied at hostapd and other # masks may be used if the driver supports them (e.g., swap the locally # administered bit) # # BSSIDs are assigned in order to each BSS, unless an explicit BSSID is # specified using the 'bssid' parameter. # If an explicit BSSID is specified, it must be chosen such that it: # - results in a valid MASK that covers it and the dev_addr # - is not the same as the MAC address of the radio # - is not the same as any other explicitly specified BSSID # # Please note that hostapd uses some of the values configured for the first BSS # as the defaults for the following BSSes. However, it is recommended that all # BSSes include explicit configuration of all relevant configuration items. # #bss=wlan0_0 #ssid=test2 # most of the above items can be used here (apart from radio interface specific # items, like channel) #bss=wlan0_1 #bssid=00:13:10:95:fe:0b # ... ================================================ FILE: hostapd_wrapper/hostapd2/hostapd_linux_ac.conf ================================================ ip_daemon_ac=127.0.0.1 sock_path_ac=/tmp/ac_ipc_hostapd port_daemon_ac=5543 ================================================ FILE: hostapd_wrapper/hostapd2/linux-ac.sh ================================================ #/bin/sh cp -f hostapd_linux.conf /etc/hostapd.conf cp -f hostapd_linux_ac.conf /etc/hostapd_ac.conf apt-get -y purge libnl1 libnl2 hostapd apt-get -y autoremove rm -rf /tmp/hostapd-linux/ mkdir -p /tmp/hostapd-linux cp -f *.tar.* *.patch /tmp/hostapd-linux cd /tmp/hostapd-linux tar zxvf nl-tiny.tar.gz mv src nl-tiny cd nl-tiny/ rm -rf *.o make cp libnl-tiny.so /usr/lib cp -rf include/* /usr/include/ ldconfig -v | grep tiny cd .. rm -rf nl-tiny tar jxvf hostapd-20130302.tar.bz2 cd hostapd-20130302 patch -p1 < ../hostapd-20130302-linux.patch cd hostapd CFLAGS="-DCONFIG_LIBNL20 -D_GNU_SOURCE -DCONFIG_MSG_MIN_PRIORITY=3 -Os -pipe -fno-caller-saves -ffunction-sections -fdata-sections -DNETUDP" make CONFIG_DRIVER_NL80211=y CONFIG_DRIVER_MADWIFI= CONFIG_DRIVER_HOSTAP= CONFIG_IEEE80211N=y CONFIG_IEEE80211W=y CONFIG_DRIVER_WEXT= LIBS="-lm -lnl-tiny" BCHECK= hostapd hostapd_cli cp -f hostapd /usr/sbin/hostapd apt-get -y install iw cd ~ rm -rf /tmp/hostapd-linux ================================================ FILE: hostapd_wrapper/hostapd_ac.conf ================================================ ip_daemon_ac=127.0.0.1 sock_path_ac=/tmp/ac_ipc_hostapd port_daemon_ac=5543 ================================================ FILE: hostapd_wrapper/hostapd_wtp.conf ================================================ ip_daemon_wtp=127.0.0.1 port_daemon_wtp=6333 sock_pach_wtp=/tmp/wtp_ipc_hostapd ================================================ FILE: hostapd_wrapper/src/capwap/capwap_mgmt_frame_ac.c ================================================ #include "utils/includes.h" #include "utils/common.h" #include "radius/radius.h" #include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "crypto/random.h" #define MAC_LENGTH 6 #define HLEN_80211 24 #define HLEN_LLC 8 int same_mac( unsigned char *mac1, unsigned char *mac2){// return 0 int i; for(i=0;iaddr2, MAC_LENGTH); return HLEN_80211 + HLEN_LLC; } int isEAPOL_Frame( unsigned char *buf, int len){ unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; int i; for(i=0; i<6; i++)if(rfc1042_header[i]!=buf[i + HLEN_80211])return 0; return 1; } void stampa_mac(char *s, unsigned char *mac){ int i; wpa_printf(MSG_DEBUG,"%s",s); for(i=0; i<6; i++)wpa_printf(MSG_DEBUG,"%02X ",mac[i]); wpa_printf(MSG_DEBUG,"\n"); } void stamp_all_max( unsigned char *buf, unsigned char *own_mac){ struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *) buf; stampa_mac("addr1 ",hdr->addr1); stampa_mac("addr2 ",hdr->addr2); stampa_mac("addr3 ",hdr->addr3); stampa_mac("own_mac ", own_mac); } int isCallBackFrame( unsigned char *buf, int len, unsigned char *own_mac){ // return 1 if is it CALL Back Frame // return 0 if is NOT CALL Back Frame struct ieee80211_hdr *hdr; /* u16 fc; */ hdr = (struct ieee80211_hdr *) buf; /* capwap FIXME: needed? fc = le_to_host16(hdr->frame_control); */ if( same_mac(hdr->addr2,own_mac)==0 && same_mac(hdr->addr3,own_mac)==0 )return 1; return 0; } int AC_get_SubType( unsigned char *buf, int len){ struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); return WLAN_FC_GET_STYPE(fc); } int AC_get_Type( unsigned char *buf, int len){ struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); return WLAN_FC_GET_TYPE(fc); } ================================================ FILE: hostapd_wrapper/src/capwap/capwap_mgmt_frame_ac.h ================================================ #ifndef __CAPWAP_MGMT_FRAME_AC_H #define __CAPWAP_MGMT_FRAME_AC_H #include "drivers/driver.h" int GetEapol_Frame( unsigned char *sa, unsigned char *buf, int len); int isEAPOL_Frame( unsigned char *buf, int len); int isCallBackFrame( unsigned char *buf, int len, unsigned char *own_mac); int AC_get_SubType( unsigned char *buf, int len); int AC_get_Type( unsigned char *buf, int len); #endif ================================================ FILE: hostapd_wrapper/src/capwap/capwap_mgmt_frame_wtp.c ================================================ #include "utils/includes.h" #include "utils/common.h" #include "radius/radius.h" #include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "crypto/random.h" #include "p2p/p2p.h" #include "wps/wps.h" #include "ap/hostapd.h" #include "ap/ieee802_11.h" #include "ap/sta_info.h" #include "ap/accounting.h" #include "ap/tkip_countermeasures.h" #include "ap/iapp.h" #include "ap/ieee802_1x.h" #include "ap/wpa_auth.h" #include "ap/wmm.h" #include "ap/wps_hostapd.h" #include "ap/ap_drv_ops.h" #include "ap/ap_config.h" #define HAPD_BROADCAST ((struct hostapd_data *) -1) #define HLEN_80211 24 void WTP_handle_assoc_cb(struct hostapd_data *hapd,const struct ieee80211_mgmt *mgmt,size_t len, int reassoc, int ok){ wpa_printf(MSG_DEBUG,"WTP: WTP_handle_assoc_cb\n"); u16 status; struct sta_info *sta; int new_assoc = 1; if (!ok) { hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "did not acknowledge association response"); return; } if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : sizeof(mgmt->u.assoc_resp))) { printf("handle_assoc_cb(reassoc=%d) - too short payload " "(len=%lu)\n", reassoc, (unsigned long) len); return; } if (reassoc) status = le_to_host16(mgmt->u.reassoc_resp.status_code); else status = le_to_host16(mgmt->u.assoc_resp.status_code); ap_sta_add(hapd, mgmt->da); sta = ap_get_sta(hapd, mgmt->da); static unsigned char sup[4]={ 0x82 ,0x84 ,0x8B ,0x96 }; hostapd_sta_add(hapd, sta->addr, ( unsigned short)1, ( unsigned short)33, sup, 4, (u16)1, NULL, (u32)32931); return ; } struct hostapd_data * WTP_get_hapd_bssid(struct hostapd_iface *iface,const unsigned char *bssid){ size_t i; if (bssid == NULL) return NULL; if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) return HAPD_BROADCAST; for (i = 0; i < iface->num_bss; i++) { if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) return iface->bss[i]; } return NULL; } void WTP_handle_tx_callback_ASS_RES(void *ctx, unsigned char *buf, size_t len, int ok){ return; struct ieee80211_hdr *hdr; const struct ieee80211_mgmt *mgmt; u16 fc; union wpa_event_data event; struct hostapd_data *hapd=ctx; hdr = (struct ieee80211_hdr *) buf; mgmt = (const struct ieee80211_mgmt *) buf; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.tx_status.type = WLAN_FC_GET_TYPE(fc); event.tx_status.stype = WLAN_FC_GET_STYPE(fc); event.tx_status.dst = hdr->addr1; event.tx_status.data = buf; event.tx_status.data_len = len; event.tx_status.ack = ok; //hapd = WTP_get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); //if (hapd == NULL || hapd == HAPD_BROADCAST) // return; if(event.tx_status.stype==WLAN_FC_STYPE_ASSOC_RESP) WTP_handle_assoc_cb(hapd, mgmt, len, 0, ok); else WTP_handle_assoc_cb(hapd, mgmt, len, 1, ok); } int isEAPOL_Frame( unsigned char *buf, int len){ unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; int i; for(i=0; i<6; i++)if(rfc1042_header[i]!=buf[i + HLEN_80211])return 0; return 1; } int WTP_get_SubType( unsigned char *buf,int len){ struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); return WLAN_FC_GET_STYPE(fc); } int WTP_get_Type( unsigned char*buf,int len){ struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); return WLAN_FC_GET_TYPE(fc); } ================================================ FILE: hostapd_wrapper/src/capwap/capwap_mgmt_frame_wtp.h ================================================ #ifndef __CAPWAP_MGMT_FRAME_WTP_H #define __CAPWAP_MGMT_FRAME_WTP_H #include "drivers/driver.h" #include "ap/hostapd.h" void WTP_handle_assoc_cb(struct hostapd_data *hapd,const struct ieee80211_mgmt *mgmt,size_t len, int reassoc, int ok); void WTP_ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,u16 stype, int ok); struct hostapd_data * WTP_get_hapd_bssid(struct hostapd_iface *iface,const u8 *bssid); void WTP_hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,size_t len, u16 stype, int ok); void WTP_wpa_supplicant_event(void *ctx, enum wpa_event_type event,union wpa_event_data *data); int WTP_get_SubType(u8 *buf,int len); int WTP_get_Type(u8 *buf,int len); int isEAPOL_Frame( unsigned char *buf, int len); #endif ================================================ FILE: hostapd_wrapper/src/capwap/file_conf_ac.h ================================================ #define CONFIGFILE "hostapd_ac.conf" #define VARLENGTH 1024 struct config_ac { int ac_port; char ip_ac[50]; char path_unix_socket[50]; }config_ac; int max_(int integer1,int integer2){ if(integer1>integer2)return integer1; return integer2; } int countString(char string[]){ int cnt=0; for(cnt=0;string[cnt]!=0;cnt++); return cnt; } int isEqualString(char String1[],char String2[]){ int len1=countString(String1); int len2=countString(String2); int i; for( i=0;i=1)b=1; for(j=0;j<=strlen(rep)-1;j++){ if(String1[i+j]!=rep[j]){ b=0; break; } } if(b){ for(k=0;k0){ for(m=0;m<=strlen(String2)-1;++m,k++)tmp[k]=String2[m]; } for(l=i+j;l<=strlen(String1)-1;l++,k++)tmp[k]=String1[l]; tmp[k]=0; for(k=0;kip_ac, "%s", ss); }else if(StartWith(ss,"sock_path_ac")){ ReplaceString(ss, "sock_path_ac", ""); ReplaceString(ss, "=", ""); ReplaceString(ss, "\n", ""); ReplaceString(ss, " ", ""); sprintf(con_ac->path_unix_socket, "%s", ss); }else if(StartWith(ss,"port_daemon_ac")){ ReplaceString(ss, "port_daemon_ac",""); ReplaceString(ss, "\n", ""); ReplaceString(ss, " ", ""); ReplaceString(ss, "=", ""); con_ac->ac_port = atoi(ss); } } fclose(file); return; } ================================================ FILE: hostapd_wrapper/src/capwap/file_conf_wtp.h ================================================ #define CONFIGFILE "hostapd_wtp.conf" #define VARLENGTH 1024 struct config_wtp { int wtp_port; char ip_wtp[50]; char path_unix_socket[50]; }config_wtp; int max_(int integer1,int integer2){ if(integer1>integer2)return integer1; return integer2; } int countString(char string[]){ int cnt=0; for(cnt=0;string[cnt]!=0;cnt++); return cnt; } int isEqualString(char String1[],char String2[]){ int len1=countString(String1); int len2=countString(String2); int i; for( i=0;i=1)b=1; for(j=0;j<=strlen(rep)-1;j++){ if(String1[i+j]!=rep[j]){ b=0; break; } } if(b){ for(k=0;k0){ for(m=0;m<=strlen(String2)-1;++m,k++)tmp[k]=String2[m]; } for(l=i+j;l<=strlen(String1)-1;l++,k++)tmp[k]=String1[l]; tmp[k]=0; for(k=0;kip_wtp, "%s", ss); }else if(StartWith(ss,"sock_pach_wtp")){ ReplaceString(ss, "sock_pach_wtp", ""); ReplaceString(ss, "=", ""); ReplaceString(ss, "\n", ""); ReplaceString(ss, " ", ""); sprintf(con_wtp->path_unix_socket, "%s", ss); }else if(StartWith(ss,"port_daemon_wtp")){ ReplaceString(ss, "port_daemon_wtp",""); ReplaceString(ss, "\n", ""); ReplaceString(ss, " ", ""); ReplaceString(ss, "=", ""); con_wtp->wtp_port = atoi(ss); } } fclose(file); return; } ================================================ FILE: hostapd_wrapper/src/capwap/ipc_capwap_ac.c ================================================ #include #include #include #include #include #include #include #include #include "eloop.h" #include "utils/includes.h" #include "utils/common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "drivers/driver.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/ap_drv_ops.h" #include "ipc_capwap_ac.h" #include "file_conf_ac.h" #include "smac_code.h" #define MAX_BUF 3000 //#define LOCALUDP //#define NETUDP //#define USEIPV6 struct config_ac con_ac; unsigned char wlan0_capa[21]; int fd_con; int tot_len; char wlanbuf[MAX_BUF]; #if defined(LOCALUDP) struct sockaddr_un addr; struct sockaddr_un local; int rn; #else #if defined(USEIPV6) struct sockaddr_in6 client; struct sockaddr_in6 addr; #else struct sockaddr_in client; struct sockaddr_in addr; #endif #endif #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<conf->ssid.ssid_len; short key_len = (short) h->conf->ssid.wep.len[h->conf->ssid.wep.idx]; wpa_printf(MSG_DEBUG,"SSID: %s ssid_len:%d\n",h->conf->ssid.ssid,ssid_len); wpa_printf(MSG_DEBUG,"IDX:%d key_len:%d key:%s \n",h->conf->ssid.wep.idx,key_len,h->conf->ssid.wep.key[h->conf->ssid.wep.idx]); unsigned char A1 = 0; unsigned char A2 = 0; SETBIT(A1,7); //E (ESS) CLEARBIT(A1,6); //I (IBSS) CLEARBIT(A1,5); //C (CF Pollable) CLEARBIT(A1,4); //F (CF Pollable Request) if(params->privacy) SETBIT(A1,3); //P (Privacy) else CLEARBIT(A1,3); //P (Privacy) if(params->preamble) SETBIT(A1,2); //S (Sort Preamble) else CLEARBIT(A1,2); //S (Sort Preamble) CLEARBIT(A1,1); //B (PBCC) CLEARBIT(A1,0); //A (Channel Agility) CLEARBIT(A2,7); //I (IBSS) CLEARBIT(A2,6); //I (IBSS) if(params->short_slot_time) SETBIT(A2,5); //I (IBSS) else CLEARBIT(A2,5); //I (IBSS) CLEARBIT(A2,4); //I (IBSS) CLEARBIT(A2,3); //I (IBSS) CLEARBIT(A2,2); //I (IBSS) CLEARBIT(A2,1); //I (IBSS) CLEARBIT(A2,0); //I (IBSS) tot_len = 19 + ssid_len + key_len; unsigned char buf[tot_len]; wpa_printf(MSG_DEBUG,"Tot Len:%d \n",tot_len); buf[0] = 0; // Radio ID buf[1] = 0; // WLAN ID buf[2] = A1; // Flags Part1 buf[3] = A2; // Flags Part2 buf[4] = h->conf->ssid.wep.idx; // Key Index if(params->privacy) buf[5] = 1; // Key Status else buf[5] = 0; // Key Status wpa_printf(MSG_DEBUG,"keylen: %d \n",key_len); //memcpy(buf+6, &key_len, 1); //memcpy(buf+7, &key_len, 1); buf[6] = *(&key_len + 1); // Key Length Part1 buf[7] = *(&key_len + 0); // Key Length Part2 wpa_printf(MSG_DEBUG,"keylen: %d %02X %02X \n",key_len,buf[6],buf[7]); if( key_len ) memcpy( buf + 8, h->conf->ssid.wep.key[h->conf->ssid.wep.idx], key_len); buf[8+key_len] = 0; // Group TSC Part1 buf[9+key_len] = 0; // Group TSC Part2 buf[10+key_len] = 0; // Group TSC Part3 buf[11+key_len] = 0; // Group TSC Part4 buf[12+key_len] = 0; // Group TSC Part5 buf[13+key_len] = 0; // Group TSC Part6 buf[14+key_len] = 0; // QoS if(params->privacy) buf[15+key_len] = 1; // Auth Type else buf[15+key_len] = 0; // Auth Type buf[16+key_len] = 1; // Mac Mode buf[17+key_len] = 2; // Tunnel Mode buf[18+key_len] = 1; // Suppress SSID memcpy(buf + key_len + 19, h->conf->ssid.ssid, ssid_len); int i; for(i=0; iframe_control); if( WLAN_FC_GET_STYPE(fc)==WLAN_FC_STYPE_ASSOC_RESP ){ status = le_to_host16(mgmt->u.assoc_resp.status_code); }else if( WLAN_FC_GET_STYPE(fc)==WLAN_FC_STYPE_REASSOC_RESP){ status = le_to_host16(mgmt->u.reassoc_resp.status_code); }else{ wpa_printf(MSG_ERROR, "Error: ipc_send_add_station\n"); return; } if(status == 0){ memcpy(cmd,mgmt->da,6); send_response(fd, SET_ADDR, cmd, 6); } } void ipc_send_del_station(int fd, u8 *buf, int len){ u16 fc; unsigned char cmd[6]; struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); if( WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_DISASSOC ){ wpa_printf(MSG_DEBUG,"Il pacchetto non e' di tipo DISASSOC\n"); return; } wpa_printf(MSG_DEBUG,"DEL ADDR: %02X %02X %02X %02X %02X %02X \n",hdr->addr2[0],hdr->addr2[1],hdr->addr2[2],hdr->addr2[3],hdr->addr2[4],hdr->addr2[5]); memcpy(cmd,hdr->addr2,6); send_response(fd, DEL_ADDR, cmd, 6); } void ipc_send_80211_to_wtp(int fd, u8 *buf, int len){ send_response(fd, DATE_TO_WTP, buf, len); } void send_response(int fd, u8 code, u8 *buf, int len){ u8 tmp_buf[MAX_BUF]; tmp_buf[0] = code; int n; #if defined(LOCALUDP) sprintf(tmp_buf + 1, "%05d", rn); memcpy(tmp_buf + 6, buf, len); n = sendto(fd, tmp_buf, len + 6, 0, (struct sockaddr *)&addr, address_size); #else memcpy(tmp_buf + 1, buf, len); n = sendto(fd, tmp_buf, len + 1, 0, (struct sockaddr *)&addr, address_size); #endif if ( n < 0 ) { perror("send"); return; } } void management_recv(int fd, u8 code, u8 *buf, int len, void *hapd, void *inject_func){ truct hostapd_data *h = hapd; if(code == PING){ send_response(fd, PONG, buf, len); }else if (code == SEND_WLAN) { send_response(fd, ADD_WLAN, wlanbuf, tot_len); }else if( code==DATE_TO_AC ){ struct hostapd_data *h = hapd; void (*pointer_inject_frame_in_hostapd) (void*,unsigned char*,int); pointer_inject_frame_in_hostapd = inject_func; pointer_inject_frame_in_hostapd(h->drv_priv, buf, len); //hostapd_inject_frame_in_hostapd(h, buf, len); }else{ wpa_printf(MSG_DEBUG,"ERROR IPC: received unrecognizedcode: %d\n",code); } } void recv_request(int fd,void *hapd, void *inject_func) { unsigned char str[MAX_BUF]; int n; #if defined(LOCALUDP) n = recvfrom(fd, str, MAX_BUF, 0, (struct sockaddr *)&local, &address_size); #else n = recvfrom(fd, str, MAX_BUF, 0, (struct sockaddr *)&addr, &address_size); #endif if(n<=0){ end_ipc(fd); return; } management_recv(fd, str[0], str + 1, n -1, hapd, inject_func); } int open_socket() { int fd_ac; char buffer[100]; #if defined(LOCALUDP) srand((unsigned)time(0)); fd_ac = socket(AF_UNIX, SOCK_DGRAM, 0); #elif defined(NETUDP) #if defined(USEIPV6) fd_ac = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); #else fd_ac = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #endif #else #if defined(USEIPV6) fd_ac = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); #else fd_ac = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); #endif #endif #if defined(LOCALUDP) addr.sun_family = AF_UNIX; strcpy(addr.sun_path, con_ac.path_unix_socket); local.sun_family = AF_UNIX; while(1){ rn = rand()%100000; sprintf(local.sun_path, "%s%05d", con_ac.path_unix_socket, rn); if( bind(fd_ac, (struct sockaddr *)&local, strlen(local.sun_path) + sizeof(local.sun_family))==-1){ sleep(1); continue; } break; } wpa_printf(MSG_DEBUG,"Connect to %s from %s\n",addr.sun_path, local.sun_path); #else #if defined(USEIPV6) addr.sin6_family = AF_INET6; addr.sin6_port = con_ac.ac_port; inet_pton(AF_INET6, con_ac.ip_ac, &addr.sin6_addr); #else addr.sin_family = AF_INET; addr.sin_port = con_ac.ac_port; addr.sin_addr.s_addr = inet_addr(con_ac.ip_ac); #endif wpa_printf(MSG_DEBUG,"Try connecting to %s:%d\n",con_ac.ip_ac, con_ac.ac_port); #endif address_size = sizeof(addr); while(1){ #if defined(LOCALUDP) sprintf(buffer,"X%05dconnect",rn); #else sprintf(buffer,"Xconnect"); #endif buffer[0] = CONNECT; sendto(fd_ac, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, address_size); #if defined(LOCALUDP) recvfrom(fd_ac, buffer, sizeof(buffer), 0, (struct sockaddr *)&local, &address_size); #else recvfrom(fd_ac, buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &address_size); #endif if (buffer[0] == CONNECT_R){ break; }else{ sleep(0.5); } } return fd_ac; } void wait_capability_from_AC(int fd, void *hapd){ unsigned char buffer[10]; int n; sleep(0.5); do { #if defined(LOCALUDP) n = sprintf((char *)buffer, "X%05d", rn); #else n = sprintf((char *)buffer, "X"); #endif buffer[0] = WANT_GOLIVE; n = sendto(fd, buffer, n, 0, (struct sockaddr *)&addr, address_size); #if defined(LOCALUDP) n = recvfrom(fd, buffer, 10, 0, (struct sockaddr *)&local, &address_size); #else n = recvfrom(fd, buffer, 10, 0, (struct sockaddr *)&addr, &address_size); #endif if (n<=0) { end_ipc(fd); return; } switch (buffer[0]) { case SET_WTPRINFO: wpa_printf(MSG_DEBUG,"SET_WTPRINFO: %02X\n",buffer[1]); memcpy( wlan0_capa+8, buffer+1, 1); send_response(fd, SET_WTPRINFO_R, NULL, 0); break; case SET_RATES: wpa_printf(MSG_DEBUG,"SET_RATES: %02X %02X %02X %02X %02X %02X %02X %02X\n", buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8]); memcpy( wlan0_capa, buffer+1, 8); send_response(fd, SET_RATES_R, NULL, 0); break; case SET_MDC: wpa_printf(MSG_DEBUG,"SET_MDC: %02X %02X %02X %02X %02X %02X\n", buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]); memcpy( wlan0_capa+9, buffer+1, 6); send_response(fd, SET_MDC_R, NULL, 0); break; case SET_MAC: wpa_printf(MSG_DEBUG,"SET_MAC: %02X %02X %02X %02X %02X %02X\n", buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]); memcpy( wlan0_capa+15, buffer+1, 6); send_response(fd, SET_MAC_R, NULL, 0); break; case GOLIVE: wpa_printf(MSG_DEBUG,"GOLIVE:\n"); send_response(fd, GOLIVE_R, NULL, 0); break; case HAVE_TO_WAIT: sleep(1); break; case CLOSE: end_ipc(fd); break; default: wpa_printf(MSG_DEBUG,"Unknow code (%d) received in CONNECTed Fase\n",buffer[0]); break; } } while (buffer[0] != GOLIVE); } int end_ipc(int fd){ ipc_send_CLOSE_to_AC(fd); if(fd>=0){ eloop_unregister_read_sock(fd); if(close(fd)<0 ){ return -1; } } if( fd_con>=0 ){ if(close(fd_con)<0 ){ } } return 0; } int start_ipc(void *hapd,void *inject_func){ ReadConfiguration(&con_ac); wpa_printf(MSG_DEBUG,"< DISCONNECTED >\n"); int sockfd = open_socket(); wpa_printf(MSG_DEBUG,"< CONNECTED >\n"); wait_capability_from_AC(sockfd, hapd); wpa_printf(MSG_DEBUG,"< LIVE >\n"); if(sockfd){ if (eloop_register_read_sock(sockfd, recv_request, hapd, inject_func)) { wpa_printf(MSG_ERROR, "Clould not register IPC socket start_ipc"); return 0; } } return sockfd; } ================================================ FILE: hostapd_wrapper/src/capwap/ipc_capwap_ac.h ================================================ #ifndef __IPC_CAPWAP_AC_H #define __IPC_CAPWAP_AC_H typedef void (* WTP_frame_inject)(void *, unsigned char *, int); void ipc_send_80211_to_wtp(int fd, u8 *buf, int len); int start_ipc(void *hapd, void *inject_func); int end_ipc(int fd); int capability_is_B(); int capability_get_num_modes(); int capability_get_num_channels(); int capability_get_rates(int *rate_arr); void capability_get_mac(unsigned char *buf); void prep_beacon(int fd,struct hostapd_data *hapd,struct wpa_driver_ap_params *params); void ipc_send_DEL_WLAN(int fd); void ipc_send_add_station(int fd, u8 *buf, int len); void ipc_send_del_station(int fd, u8 *buf, int len); void send_response(int fd, u8 code, u8 *buf, int len); #endif ================================================ FILE: hostapd_wrapper/src/capwap/ipc_capwap_wtp.c ================================================ #include #include #include #include #include #include #include #include #include #include #include #include "eloop.h" #include "utils/includes.h" #include "utils/common.h" #include "drivers/driver.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/ap_drv_ops.h" #include "ipc_capwap_wtp.h" #include "file_conf_wtp.h" #include "smac_code.h" #define MAX_BUF 3000 //#define LOCALUDP //#define NETUDP //#define NETSEQ //#define USEIPV6 struct pre_txq { unsigned char *buf; int len; int free; }; struct queue_qos { int queue_id; int cwmin; int cwmax; int aifs; int burst_time; }; struct wlan_state { int rts; int frag; struct hostapd_freq_params freq_params; struct queue_qos que[4]; }; struct config_wtp con_wtp; unsigned char wlan0_capa[21]; struct pre_txq buf_txq[8]; #if defined(LOCALUDP) struct sockaddr_un addr; struct sockaddr_un local; int rn; #else #if defined(USEIPV6) struct sockaddr_in6 addr; #else struct sockaddr_in addr; #endif #endif socklen_t address_size; struct wlan_state wl; int fd_con; struct sockaddr_un local, remote; static void send_response(int fd, u8 code, u8 *buf, int len); static void send_varesponse(int fd, u8 code, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); static void ipc_send_CLOSE_to_WTP(int fd) { unsigned char cmd[10]; send_response(fd, CLOSE, cmd, 10); } void ipc_send_80211_to_ac(int fd, u8 *buf, int len) { send_response(fd, DATE_TO_AC, buf, len); } static void send_varesponse(int fd, u8 code, const char *fmt, ...) { va_list args; char buf[1024]; int l; va_start(args, fmt); l = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); send_response(fd, code, (u8 *)buf, l); } static void send_response(int fd, u8 code, u8 *buf, int len) { u8 tmp_buf[MAX_BUF]; tmp_buf[0] = code; int n; #if defined(LOCALUDP) sprintf(tmp_buf + 1, "%05d", rn); memcpy(tmp_buf + 6, buf, len); n = sendto(fd, tmp_buf, len + 6, 0, (struct sockaddr *)&addr, address_size); #else memcpy(tmp_buf + 1, buf, len); n = sendto(fd, tmp_buf, len + 1, 0, (struct sockaddr *)&addr, address_size); #endif if ( n < 0 ) { perror("send"); return; } } /* HANDLE */ static void SET_RTS_handle(int fd, u8 *buf, int len, void *hapd) { struct hostapd_data *h = hapd; char tmp[MAX_BUF]; memcpy(tmp, buf, len); tmp[len] = 0; int rts = atoi(tmp); wpa_printf(MSG_DEBUG, "SER RTS: %d",rts); wl.rts = rts; int ret = hostapd_set_rts(h, rts); send_varesponse(fd, SET_RTS_R, "%d", ret); } static void GET_RTS_handle(int fd, u8 *buf, int len, void *hapd) { send_varesponse(fd, GET_RTS_R, "%d", wl.rts); } static void SET_FRAG_handle(int fd, u8 *buf, int len, void *hapd) { struct hostapd_data *h = hapd; char tmp[MAX_BUF]; memcpy(tmp,buf,len); tmp[len] = 0; int frag = atoi(tmp); wpa_printf(MSG_DEBUG, "SER FRAQ: %d",frag); wl.frag = frag; int ret = hostapd_set_frag(h, frag); send_varesponse(fd, SET_FRAG_R, "%d", ret); } static void GET_FRAG_handle(int fd, u8 *buf, int len, void *hapd) { send_varesponse(fd, GET_FRAG_R, "%d", wl.frag); } static void SET_FREQ_handle(int fd, u8 *buf, int len, void *hapd) { struct hostapd_data *h = hapd; char str[5][10]; int i,j=0; int cnt = 0; for(i=0; idriver->hapd_deinit ) h->driver->hapd_deinit(h->iface->bss[0]->drv_priv); hostapd_interface_free(h->iface); end_ipc(fd); exit(0); } static void ADD_WLAN_handle(int fd, u8 *buf, int len, void *hapd, unsigned char *ssid_p, int *ssid_len_p) { wpa_printf(MSG_DEBUG, "ADD WLAN: len:%d",len); int k; struct hostapd_data *h = hapd; wpa_printf(MSG_DEBUG, "Radio ID: %d",buf[0]); wpa_printf(MSG_DEBUG, "Wlan ID: %d",buf[1]); wpa_printf(MSG_DEBUG, "Flag 1: %02X",buf[2]); wpa_printf(MSG_DEBUG, "Flag 2: %02X",buf[3]); wpa_printf(MSG_DEBUG, "Key Index: %d",buf[4]); wpa_printf(MSG_DEBUG, "Key Status: %d",buf[5]); short key_len; *(&key_len + 1) = buf[6]; *(&key_len + 0) = buf[7]; //wpa_printf(MSG_DEBUG, "Keylen: %d",key_len); unsigned char key[key_len]; if(key_len){ memcpy(key, buf+8, key_len); //wpa_printf(MSG_DEBUG, "Key: %s",key); h->conf->ssid.wep.idx = 0; h->conf->ssid.wep.len[0] = key_len; h->conf->ssid.wep.keys_set = 1; h->conf->ssid.security_policy=SECURITY_STATIC_WEP; char tmp_key[128]; for(k=0; kconf->ssid.wep.key[0] = malloc(128); memcpy(h->conf->ssid.wep.key[0], tmp_key, key_len); } int key_len_int = (int) key_len; //wpa_printf(MSG_DEBUG, "key len %d",key_len_int); int pos_mac_mod = 16 + key_len_int; wpa_printf(MSG_DEBUG, "Mac Mode: %d",buf[pos_mac_mod]); wpa_printf(MSG_DEBUG, "Tunnel Mode: %02X",buf[17+key_len_int]); wpa_printf(MSG_DEBUG, "Suppress SSID: %02X",buf[18+key_len_int]); h->conf->mac_mode = buf[pos_mac_mod]; if( buf[18+key_len_int]!=0x00 ){ int ssid_len = len - 19 - key_len_int; char tmp_ssid[33]; wpa_printf(MSG_DEBUG, "SSID LEN: %d",ssid_len); for(k=0;kconf->ssid.ssid_len = ssid_len; memcpy(h->conf->ssid.ssid, tmp_ssid, ssid_len); } } static void management_recv(int fd, u8 code, u8 *buf, int len, void *hapd, void *inject_func) { switch (code) { case PING: send_response(fd, PONG, buf, len); break; case SET_RTS: SET_RTS_handle(fd, buf, len, hapd); break; case SET_FRAG: SET_FRAG_handle(fd, buf, len, hapd); break; case GET_RTS: GET_RTS_handle(fd, buf, len, hapd); break; case GET_FRAG: GET_FRAG_handle(fd, buf, len, hapd); break; case SET_FREQ: SET_FREQ_handle(fd, buf, len, hapd); break; case GET_FREQ: GET_FREQ_handle(fd, buf, len, hapd); break; case SET_TXQ: SET_TXQ_handle(fd, buf, len, hapd); break; case DATE_TO_WTP: ((WTP_frame_inject)inject_func)(((struct hostapd_data *)hapd)->drv_priv, buf, len); break; case SET_ADDR: SET_ADDR_handle(fd, buf, len, hapd); break; case DEL_ADDR: DEL_ADDR_handle(fd, buf, len, hapd); break; case DEL_WLAN: DEL_WLAN_handle(fd, buf, len, hapd); break; default: wpa_printf(MSG_ERROR, "ERROR IPC: received unrecognizedcode: %d",code); break; } } static void recv_request(int fd, void *hapd, void *inject_func) { unsigned char str[MAX_BUF]; int n; #if defined(LOCALUDP) n = recvfrom(fd, str, MAX_BUF, 0,(struct sockaddr *)&local, &address_size); #else n = recvfrom(fd, str, MAX_BUF, 0,(struct sockaddr *)&addr, &address_size); #endif if (n<=0) { end_ipc(fd); return; } management_recv(fd, str[0], str + 1, n -1, hapd, inject_func); } static int open_socket() { wpa_printf(MSG_DEBUG, "Ip:Port %s:%d %s",con_wtp.ip_wtp,con_wtp.wtp_port,con_wtp.path_unix_socket); int fd_wtp; char buffer[100]; #if defined(LOCALUDP) srand((unsigned)time(0)); fd_wtp = socket(AF_UNIX, SOCK_DGRAM, 0); #elif defined(NETUDP) #if defined(USEIPV6) fd_wtp = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); #else fd_wtp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #endif #else #if defined(USEIPV6) fd_wtp = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); #else fd_wtp = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); #endif #endif #if defined(LOCALUDP) addr.sun_family = AF_UNIX; strcpy(addr.sun_path, con_wtp.path_unix_socket); local.sun_family = AF_UNIX; while(1){ rn = rand()%100000; sprintf(local.sun_path, "%s%05d", con_wtp.path_unix_socket, rn); if (bind(fd_wtp, (struct sockaddr *)&local, strlen(local.sun_path) + sizeof(local.sun_family)) == -1) { sleep(1); continue; } break; } wpa_printf(MSG_DEBUG, "Try connecting to %s from %s",addr.sun_path, local.sun_path); #else #if defined(USEIPV6) addr.sin6_family = AF_INET6; addr.sin6_port = con_wtp.wtp_port; inet_pton(AF_INET6, con_wtp.ip_wtp, &addr.sin6_addr); #else addr.sin_family = AF_INET; addr.sin_port = con_wtp.wtp_port; addr.sin_addr.s_addr = inet_addr(con_wtp.ip_wtp); #endif wpa_printf(MSG_DEBUG, "Try connecting to %s:%d",con_wtp.ip_wtp,con_wtp.wtp_port); #endif address_size = sizeof(addr); wpa_printf(MSG_DEBUG, ""); while(1) { #if defined(LOCALUDP) sprintf(buffer,"Z%05dconnect",rn); #else sprintf(buffer,"Zconnect"); #endif buffer[0] = CONNECT; sendto(fd_wtp, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, address_size); recvfrom(fd_wtp, buffer, sizeof(buffer), 0,(struct sockaddr *)&local, &address_size); if(buffer[0] == CONNECT_R) break; sleep(1); } wpa_printf(MSG_DEBUG, ""); return fd_wtp; } int end_ipc(int fd) { wpa_printf(MSG_DEBUG, "Close IPC"); ipc_send_CLOSE_to_WTP(fd); if(fd>=0){ eloop_unregister_read_sock(fd); if (close(fd)<0) return -1; } if(fd_con>=0 ){ if(close(fd_con)<0 ){ } } return 0; } static void goto_preconnect(int fd, void *hapd){ unsigned char buf[MAX_BUF]; int n; do { /* Wait Packet */ #if defined(LOCALUDP) n = recvfrom(fd, buf, MAX_BUF, 0,(struct sockaddr *)&local, &address_size); #else n = recvfrom(fd, buf, MAX_BUF, 0,(struct sockaddr *)&addr, &address_size); #endif if (n <= 0){ end_ipc(fd); return; } switch(buf[0]) { case WTPRINFO: wpa_printf(MSG_DEBUG, "Command WTPRINFO in CONNECTED State"); send_response(fd, WTPRINFO_R, wlan0_capa + 8, 1); break; case GET_RATES: wpa_printf(MSG_DEBUG, "Command GET_RATES in CONNECTED State"); send_response(fd, GET_RATES_R, wlan0_capa, 8); break; case GET_MDC: wpa_printf(MSG_DEBUG, "Command GET_MDC in CONNECTED State"); send_response(fd, GET_MDC_R, wlan0_capa + 9, 6); break; case GET_MAC: wpa_printf(MSG_DEBUG, "Command GET_MAC in CONNECTED State"); send_response(fd, GET_MAC_R, wlan0_capa + 15, 6); break; case GOWAITWLAN: wpa_printf(MSG_DEBUG, "Command GOWAITWLAN in CONNECTED State"); send_response(fd, GOWAITWLAN_R, NULL, 0); break; default: wpa_printf(MSG_DEBUG, "Unknown Command %d in CONNECTED State", buf[0]); } } while (buf[0] != GOWAITWLAN); wpa_printf(MSG_DEBUG, ""); } static void wait_ADD_WLAN(int fd, unsigned char *ssid_p, int *ssid_len_p, void *hapd ) { unsigned char buf[MAX_BUF]; int n; do { /* Wait Packet until recv ADD WLAN */ #if defined(LOCALUDP) n = recvfrom(fd, buf, MAX_BUF, 0,(struct sockaddr *)&local, &address_size); #else n = recvfrom(fd, buf, MAX_BUF, 0,(struct sockaddr *)&addr, &address_size); #endif if(n<=0){ end_ipc(fd); return; } switch (buf[0]) { case ADD_WLAN: ADD_WLAN_handle(fd, buf+1, n-1, hapd, ssid_p, ssid_len_p); break; case DEL_WLAN: DEL_WLAN_handle(fd, NULL, 0, hapd); break; case SET_TXQ: add_in_SET_TXQ_handle( buf+1, n-1 ); break; default: wpa_printf(MSG_DEBUG, "Unknown Command in WAITWLAN State %d",buf[0]); } } while (buf[0] != ADD_WLAN); wpa_printf(MSG_DEBUG, ""); } int start_ipc(void *hapd, unsigned char *ssid_p, int *ssid_len_p, void *inject_func, unsigned char *cap_info) { memcpy( wlan0_capa, cap_info, 21); ReadConfiguration(&con_wtp); int sockfd = open_socket(); goto_preconnect(sockfd, hapd); wait_ADD_WLAN(sockfd, ssid_p, ssid_len_p, hapd); wl.frag = -1; wl.rts = -1; wl.freq_params.channel = 0; wl.freq_params.ht_enabled = 0; wl.freq_params.mode = 0; wl.freq_params.sec_channel_offset = 0; wl.freq_params.freq = 2452; wl.que[0].queue_id = 0; wl.que[0].cwmin = 3; wl.que[0].cwmax = 7; wl.que[0].aifs = 2; wl.que[1].queue_id = 1; wl.que[1].cwmin = 7; wl.que[1].cwmax = 15; wl.que[1].aifs = 2; wl.que[2].queue_id = 2; wl.que[2].cwmin = 15; wl.que[2].cwmax = 1023; wl.que[2].aifs = 3; wl.que[3].queue_id = 3; wl.que[3].cwmin = 31; wl.que[3].cwmax = 1023; wl.que[3].aifs = 7; if(sockfd){ if (eloop_register_read_sock(sockfd, recv_request, hapd, inject_func)) { wpa_printf(MSG_ERROR, "Clould not register IPC socket start_ipc"); return 0; } } wpa_printf(MSG_DEBUG, "SOCKET Created %d",sockfd); return sockfd; } ================================================ FILE: hostapd_wrapper/src/capwap/ipc_capwap_wtp.h ================================================ #ifndef __IPC_CAPWAP_WTP_H #define __IPC_CAPWAP_WTP_H typedef void (* WTP_frame_inject)(void *, unsigned char *, int); void ipc_send_80211_to_ac(int fd, u8 *buf, int len); void flush_SET_TXQ_handle(int fd, void *hapd); int start_ipc(void *hapd, unsigned char *, int *, void * inject_func, unsigned char *); int end_ipc(int fd); #endif ================================================ FILE: hostapd_wrapper/src/capwap/smac_code.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Sotiraq Sima (Sotiraq.Sima@gmail.com) * * * *******************************************************************************************/ #include enum { ERROR = 0, CLOSE = 1, PING = 2, // [2]ping PONG = 3,// [3]pong START_WLAN = 4, START_WLAN_R = 5, STOP_WLAN = 6, STOP_WLAN_R = 7, SET_FREQ = 8, // FREQ sec_channel_offset ht_enabled channel MODE ex. "[8]2462 0 0 11 0" SET_FREQ_R = 9, // 0 or 1 ex. "[9]0" GET_FREQ = 10, // ex. "[10]" GET_FREQ_R = 11, // ex. "[11]2462 0 0 11 0" SET_FRAG = 12, // Typically the range used for fragmentation threshold is 256-2346 (-1 == off) ex. "[12]2000" SET_FRAG_R = 13,// ex. "[13]0" GET_FRAG = 14, // ex. "[14]" (-1 == off) GET_FRAG_R = 15, // ex. "[15]2000" SET_BITRATE = 16, SET_BITRATE_R = 17, GET_BITRATE = 18, GET_BITRATE_R = 19, SET_RTS = 20, // 0-2347 (-1 == off) ex. "[20]100" (-1 == off) SET_RTS_R = 21,// ex. "[21]0" GET_RTS = 22, // ex. "]22]" (-1 == off) GET_RTS_R = 23, // ex. "[23]100" SET_TXPOWER = 24, SET_TXPOWER_R = 25, GET_TXPOWER = 26, GET_TXPOWER_R = 27, /* * VO - 0 CWMIN:3 CWMAX:7 AIFS:2 * VI - 1 CWMIN:7 CWMAX:15 AIFS:2 * BE - 2 CWMIN:15 CWMAX:1023 AIFS:3 * BK - 3 CWMIN:15 CWMAX:1023 AIFS:7 */ SET_TXQ = 28, SET_TXQ_R = 29, GET_TXQ = 30, GET_TXQ_R = 31, SET_ADDR = 32, SET_ADDR_R = 33, DEL_ADDR = 34, DEL_ADDR_R = 35, ADD_WLAN = 36, ADD_WLAN_R = 37, DEL_WLAN = 38, DEL_WLAN_R = 39, WTPRINFO = 40, WTPRINFO_R = 41, GET_RATES = 42, GET_RATES_R = 43, GET_MDC = 44, GET_MDC_R = 45, SET_WTPRINFO = 46, SET_WTPRINFO_R = 47, SET_RATES = 48, SET_RATES_R = 49, SET_MDC = 50, SET_MDC_R = 51, GOLIVE = 52, GOLIVE_R = 53, WANT_GOLIVE = 54, HAVE_TO_WAIT = 55, GET_MAC = 56, GET_MAC_R = 57, SET_MAC = 58, SET_MAC_R = 59, DATE_TO_WTP = 100, DATE_TO_AC = 101, CONNECT = 102, CONNECT_R = 103, GOWAITWLAN = 104, GOWAITWLAN_R = 105 }; ================================================ FILE: hostapd_wrapper/src/capwap/switch_8023_80211.c ================================================ #include "utils/includes.h" #include "utils/common.h" #include "radius/radius.h" #include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1< * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2007, Johannes Berg * Copyright (c) 2009-2010, Atheros Communications * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nl80211_copy.h" #include "common.h" #include "eloop.h" #include "utils/list.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "l2_packet/l2_packet.h" /* CAPWAP */ #include "netlink_fake.h" #include "linux_ioctl_fake.h" #include "capwap/capwap_mgmt_frame_ac.h" #include "capwap/ipc_capwap_ac.h" #include "radiotap.h" #include "radiotap_iter.h" #include "rfkill.h" #include "driver.h" struct priv_params params; #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<>= 22; port_bitmap[port / 32] &= ~(1 << (port % 32)); nl_handle_destroy(handle); } static inline int __genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache) { struct nl_cache *tmp = genl_ctrl_alloc_cache(h); if (!tmp) return -ENOMEM; *cache = tmp; return 0; } #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache #endif /* CONFIG_LIBNL20 */ struct capwap_handles { struct nl_handle *handle; struct nl_cache *cache; }; static int nl_create_handles(struct capwap_handles *handles, struct nl_cb *cb, const char *dbg) { if (!handles) return -1; handles->handle = capwap_handle_alloc(cb); if (handles->handle == NULL) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate netlink " "callbacks (%s)", dbg); return -1; } if (genl_connect(handles->handle)) { wpa_printf(MSG_ERROR, "capwap: Failed to connect to generic " "netlink (%s)", dbg); goto err; } if (genl_ctrl_alloc_cache(handles->handle, &handles->cache) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate generic " "netlink cache (%s)", dbg); goto err; } return 0; err: capwap_handle_destroy(handles->handle); return -1; } static void nl_destroy_handles(struct capwap_handles *handles) { if (handles->handle == NULL) return; nl_cache_free(handles->cache); capwap_handle_destroy(handles->handle); handles->handle = NULL; } #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ #endif #ifndef IFF_DORMANT #define IFF_DORMANT 0x20000 /* driver signals dormant */ #endif #ifndef IF_OPER_DORMANT #define IF_OPER_DORMANT 5 #endif #ifndef IF_OPER_UP #define IF_OPER_UP 6 #endif struct capwap_global { struct dl_list interfaces; int if_add_ifindex; struct netlink_data *netlink; struct nl_cb *nl_cb; struct capwap_handles nl; struct genl_family *capwap; int ioctl_sock; /* socket for ioctl() use */ }; static void capwap_global_deinit(void *priv); static void wpa_driver_capwap_deinit(void *priv); struct i802_bss { struct wpa_driver_capwap_data *drv; struct i802_bss *next; int ifindex; char ifname[IFNAMSIZ + 1]; char brname[IFNAMSIZ]; unsigned int beacon_set:1; unsigned int added_if_into_bridge:1; unsigned int added_bridge:1; }; struct wpa_driver_capwap_data { struct capwap_global *global; struct dl_list list; u8 addr[ETH_ALEN]; char phyname[32]; void *ctx; int ifindex; int if_removed; int if_disabled; int ignore_if_down_event; struct rfkill_data *rfkill; struct wpa_driver_capa capa; int has_capability; int operstate; int scan_complete_events; struct capwap_handles nl_event, nl_preq; u8 auth_bssid[ETH_ALEN]; u8 bssid[ETH_ALEN]; int associated; u8 ssid[32]; size_t ssid_len; enum nl80211_iftype nlmode; enum nl80211_iftype ap_scan_as_station; unsigned int assoc_freq; int monitor_sock; int monitor_ifidx; int no_monitor_iface_capab; unsigned int disabled_11b_rates:1; unsigned int pending_remain_on_chan:1; unsigned int in_interface_list:1; u64 remain_on_chan_cookie; u64 send_action_cookie; unsigned int last_mgmt_freq; unsigned int ap_oper_freq; struct wpa_driver_scan_filter *filter_ssids; size_t num_filter_ssids; struct i802_bss first_bss; #ifdef CONFIG_AP struct l2_packet_data *l2; #endif /* CONFIG_AP */ #ifdef HOSTAPD int eapol_sock; /* socket for EAPOL frames */ int default_if_indices[16]; int *if_indices; int num_if_indices; int last_freq; int last_freq_ht; #endif /* HOSTAPD */ }; static void wpa_driver_capwap_scan_timeout(void *eloop_ctx, void *timeout_ctx); static int wpa_driver_capwap_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode); static int wpa_driver_capwap_finish_drv_init(struct wpa_driver_capwap_data *drv); static int wpa_driver_capwap_mlme(struct wpa_driver_capwap_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change); static void capwap_remove_monitor_interface( struct wpa_driver_capwap_data *drv); static int capwap_send_frame_cmd(struct wpa_driver_capwap_data *drv, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, u64 *cookie, int no_cck); static int wpa_driver_capwap_probe_req_report(void *priv, int report); #ifdef HOSTAPD static void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); static void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); static int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); static int wpa_driver_capwap_if_remove(void *priv, enum wpa_driver_if_type type, const char *ifname); #else /* HOSTAPD */ static inline void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { } static inline void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { } static inline int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { return 0; } #endif /* HOSTAPD */ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq); static int capwap_disable_11b_rates(struct wpa_driver_capwap_data *drv, int ifindex, int disabled); static int capwap_leave_ibss(struct wpa_driver_capwap_data *drv); static int is_ap_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_AP || nlmode == NL80211_IFTYPE_P2P_GO); } static int is_sta_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_STATION || nlmode == NL80211_IFTYPE_P2P_CLIENT); } static int is_p2p_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_P2P_CLIENT || nlmode == NL80211_IFTYPE_P2P_GO); } struct capwap_bss_info_arg { struct wpa_driver_capwap_data *drv; struct wpa_scan_results *res; unsigned int assoc_freq; u8 assoc_bssid[ETH_ALEN]; }; static int bss_info_handler(struct nl_msg *msg, void *arg); /* capwap code */ static int ack_handler(struct nl_msg *msg, void *arg) { int *err = arg; *err = 0; return NL_STOP; } static int finish_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_SKIP; } static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; return NL_SKIP; } static int no_seq_check(struct nl_msg *msg, void *arg) { return NL_OK; } static int send_and_recv(struct wpa_driver_capwap_data *drv, struct nl_handle *nl_handle, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) { struct nl_cb *cb; int err = -ENOMEM; cb = nl_cb_clone(drv->global->nl_cb); if (!cb) goto out; err = nl_send_auto_complete(nl_handle, msg); if (err < 0) goto out; err = 1; nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); if (valid_handler) nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); while (err > 0) nl_recvmsgs(nl_handle, cb); out: nl_cb_put(cb); nlmsg_free(msg); return err; } static int send_and_recv_msgs(struct wpa_driver_capwap_data *drv, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) { return send_and_recv(drv, drv->global->nl.handle, msg, valid_handler, valid_data); } struct family_data { const char *group; int id; }; static int family_handler(struct nl_msg *msg, void *arg) { struct family_data *res = arg; struct nlattr *tb[CTRL_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *mcgrp; int i; nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[CTRL_ATTR_MCAST_GROUPS]) return NL_SKIP; nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), nla_len(mcgrp), NULL); if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID] || os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]), res->group, nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0) continue; res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); break; }; return NL_SKIP; } static int nl_get_multicast_id(struct wpa_driver_capwap_data *drv, const char *family, const char *group) { struct nl_msg *msg; int ret = -1; struct family_data res = { group, -ENOENT }; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->global->nl.handle, "nlctrl"), 0, 0, CTRL_CMD_GETFAMILY, 0); NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); ret = send_and_recv_msgs(drv, msg, family_handler, &res); msg = NULL; if (ret == 0) ret = res.id; nla_put_failure: nlmsg_free(msg); return ret; } static void * capwap_cmd(struct wpa_driver_capwap_data *drv, struct nl_msg *msg, int flags, uint8_t cmd) { return NULL; return genlmsg_put(msg, 0, 0, genl_family_get_id(drv->global->capwap), 0, flags, cmd, 0); } static int wpa_driver_capwap_get_bssid(void *priv, u8 *bssid) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!drv->associated) return -1; os_memcpy(bssid, drv->bssid, ETH_ALEN); return 0; } static int wpa_driver_capwap_get_ssid(void *priv, u8 *ssid) { wpa_printf(MSG_DEBUG,"> wpa_driver_capwap_get_ssid"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!drv->associated) return -1; os_memcpy(ssid, drv->ssid, drv->ssid_len); return drv->ssid_len; } static void wpa_driver_capwap_event_link(struct wpa_driver_capwap_data *drv, char *buf, size_t len, int del) { union wpa_event_data event; os_memset(&event, 0, sizeof(event)); if (len > sizeof(event.interface_status.ifname)) len = sizeof(event.interface_status.ifname) - 1; os_memcpy(event.interface_status.ifname, buf, len); event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : EVENT_INTERFACE_ADDED; wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", del ? "DEL" : "NEW", event.interface_status.ifname, del ? "removed" : "added"); if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) { if (del) { if (drv->if_removed) { wpa_printf(MSG_DEBUG, "capwap: if_removed " "already set - ignore event"); return; } drv->if_removed = 1; } else { if (if_nametoindex(drv->first_bss.ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Interface %s " "does not exist - ignore " "RTM_NEWLINK", drv->first_bss.ifname); return; } if (!drv->if_removed) { wpa_printf(MSG_DEBUG, "capwap: if_removed " "already cleared - ignore event"); return; } drv->if_removed = 0; } } wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } static int wpa_driver_capwap_own_ifname(struct wpa_driver_capwap_data *drv, u8 *buf, size_t len) { int attrlen, rta_len; struct rtattr *attr; attrlen = len; attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname) == 0) return 1; else break; } attr = RTA_NEXT(attr, attrlen); } return 0; } static int wpa_driver_capwap_own_ifindex(struct wpa_driver_capwap_data *drv, int ifindex, u8 *buf, size_t len) { if (drv->ifindex == ifindex) return 1; if (drv->if_removed && wpa_driver_capwap_own_ifname(drv, buf, len)) { drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname); wpa_printf(MSG_DEBUG, "capwap: Update ifindex for a removed " "interface"); wpa_driver_capwap_finish_drv_init(drv); return 1; } return 0; } static struct wpa_driver_capwap_data * capwap_find_drv(struct capwap_global *global, int idx, u8 *buf, size_t len) { struct wpa_driver_capwap_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_capwap_data, list) { if (wpa_driver_capwap_own_ifindex(drv, idx, buf, len) || have_ifidx(drv, idx)) return drv; } return NULL; } static void wpa_driver_capwap_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { struct capwap_global *global = ctx; struct wpa_driver_capwap_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; char namebuf[IFNAMSIZ]; drv = capwap_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { wpa_printf(MSG_DEBUG, "capwap: Ignore event for foreign " "ifindex %d", ifi->ifi_index); return; } wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " "(%s%s%s%s)", drv->operstate, ifi->ifi_flags, (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && linux_iface_up(drv->global->ioctl_sock, drv->first_bss.ifname) > 0) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface down " "event since interface %s is up", namebuf); return; } wpa_printf(MSG_DEBUG, "capwap: Interface down"); if (drv->ignore_if_down_event) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface down " "event generated by mode change"); drv->ignore_if_down_event = 0; } else { drv->if_disabled = 1; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); } } if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && linux_iface_up(drv->global->ioctl_sock, drv->first_bss.ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " "event since interface %s is down", namebuf); } else if (if_nametoindex(drv->first_bss.ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " "event since interface %s does not exist", drv->first_bss.ifname); } else if (drv->if_removed) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " "event since interface %s is marked " "removed", drv->first_bss.ifname); } else { wpa_printf(MSG_DEBUG, "capwap: Interface up"); drv->if_disabled = 0; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); } } /* * Some drivers send the association event before the operup event--in * this case, lifting operstate in wpa_driver_capwap_set_operstate() * fails. This will hit us when wpa_supplicant does not need to do * IEEE 802.1X authentication */ if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, IF_OPER_UP); attrlen = len; attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_capwap_event_link( drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 0); } else if (attr->rta_type == IFLA_MASTER) brid = nla_get_u32((struct nlattr *) attr); attr = RTA_NEXT(attr, attrlen); } if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been added to bridge */ if_indextoname(brid, namebuf); wpa_printf(MSG_DEBUG, "capwap: Add ifindex %u for bridge %s", brid, namebuf); add_ifidx(drv, brid); } } static void wpa_driver_capwap_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { struct capwap_global *global = ctx; struct wpa_driver_capwap_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; drv = capwap_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { wpa_printf(MSG_DEBUG, "capwap: Ignore dellink event for " "foreign ifindex %d", ifi->ifi_index); return; } attrlen = len; attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_capwap_event_link( drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 1); } else if (attr->rta_type == IFLA_MASTER) brid = nla_get_u32((struct nlattr *) attr); attr = RTA_NEXT(attr, attrlen); } if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; if_indextoname(brid, namebuf); wpa_printf(MSG_DEBUG, "capwap: Remove ifindex %u for bridge " "%s", brid, namebuf); del_ifidx(drv, brid); } } static void mlme_event_auth(struct wpa_driver_capwap_data *drv, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24 + sizeof(mgmt->u.auth)) { wpa_printf(MSG_DEBUG, "capwap: Too short association event " "frame"); return; } os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); os_memset(&event, 0, sizeof(event)); os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); if (len > 24 + sizeof(mgmt->u.auth)) { event.auth.ies = mgmt->u.auth.variable; event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); } wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); } static unsigned int capwap_get_assoc_freq(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; int ret; struct capwap_bss_info_arg arg; os_memset(&arg, 0, sizeof(arg)); msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "capwap: Operating frequency for the " "associated BSS from scan results: %u MHz", arg.assoc_freq); return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq; } wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return drv->assoc_freq; } static void mlme_event_assoc(struct wpa_driver_capwap_data *drv, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 status; mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24 + sizeof(mgmt->u.assoc_resp)) { wpa_printf(MSG_DEBUG, "capwap: Too short association event " "frame"); return; } status = le_to_host16(mgmt->u.assoc_resp.status_code); if (status != WLAN_STATUS_SUCCESS) { os_memset(&event, 0, sizeof(event)); event.assoc_reject.bssid = mgmt->bssid; if (len > 24 + sizeof(mgmt->u.assoc_resp)) { event.assoc_reject.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; event.assoc_reject.resp_ies_len = len - 24 - sizeof(mgmt->u.assoc_resp); } event.assoc_reject.status_code = status; wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } drv->associated = 1; os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); os_memset(&event, 0, sizeof(event)); if (len > 24 + sizeof(mgmt->u.assoc_resp)) { event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; event.assoc_info.resp_ies_len = len - 24 - sizeof(mgmt->u.assoc_resp); } event.assoc_info.freq = drv->assoc_freq; wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } static void mlme_event_connect(struct wpa_driver_capwap_data *drv, enum nl80211_commands cmd, struct nlattr *status, struct nlattr *addr, struct nlattr *req_ie, struct nlattr *resp_ie) { union wpa_event_data event; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* * Avoid reporting two association events that would confuse * the core code. */ wpa_printf(MSG_DEBUG, "capwap: Ignore connect event (cmd=%d) " "when using userspace SME", cmd); return; } os_memset(&event, 0, sizeof(event)); if (cmd == NL80211_CMD_CONNECT && nla_get_u16(status) != WLAN_STATUS_SUCCESS) { if (addr) event.assoc_reject.bssid = nla_data(addr); if (resp_ie) { event.assoc_reject.resp_ies = nla_data(resp_ie); event.assoc_reject.resp_ies_len = nla_len(resp_ie); } event.assoc_reject.status_code = nla_get_u16(status); wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } drv->associated = 1; if (addr) os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); if (req_ie) { event.assoc_info.req_ies = nla_data(req_ie); event.assoc_info.req_ies_len = nla_len(req_ie); } if (resp_ie) { event.assoc_info.resp_ies = nla_data(resp_ie); event.assoc_info.resp_ies_len = nla_len(resp_ie); } event.assoc_info.freq = capwap_get_assoc_freq(drv); wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } static void mlme_event_disconnect(struct wpa_driver_capwap_data *drv, struct nlattr *reason, struct nlattr *addr) { union wpa_event_data data; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* * Avoid reporting two disassociation events that could * confuse the core code. */ wpa_printf(MSG_DEBUG, "capwap: Ignore disconnect " "event when using userspace SME"); return; } drv->associated = 0; os_memset(&data, 0, sizeof(data)); if (reason) data.disassoc_info.reason_code = nla_get_u16(reason); wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); } static void mlme_timeout_event(struct wpa_driver_capwap_data *drv, enum nl80211_commands cmd, struct nlattr *addr) { union wpa_event_data event; enum wpa_event_type ev; if (nla_len(addr) != ETH_ALEN) return; wpa_printf(MSG_DEBUG, "capwap: MLME event %d; timeout with " MACSTR, cmd, MAC2STR((u8 *) nla_data(addr))); if (cmd == NL80211_CMD_AUTHENTICATE) ev = EVENT_AUTH_TIMED_OUT; else if (cmd == NL80211_CMD_ASSOCIATE) ev = EVENT_ASSOC_TIMED_OUT; else return; os_memset(&event, 0, sizeof(event)); os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); wpa_supplicant_event(drv->ctx, ev, &event); } static void mlme_event_mgmt(struct wpa_driver_capwap_data *drv, struct nlattr *freq, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 fc, stype; mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24) { wpa_printf(MSG_DEBUG, "capwap: Too short action frame"); return; } fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); os_memset(&event, 0, sizeof(event)); if (freq) { event.rx_action.freq = nla_get_u32(freq); drv->last_mgmt_freq = event.rx_action.freq; } if (stype == WLAN_FC_STYPE_ACTION) { event.rx_action.da = mgmt->da; event.rx_action.sa = mgmt->sa; event.rx_action.bssid = mgmt->bssid; event.rx_action.category = mgmt->u.action.category; event.rx_action.data = &mgmt->u.action.category + 1; event.rx_action.len = frame + len - event.rx_action.data; wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); } else { event.rx_mgmt.frame = frame; event.rx_mgmt.frame_len = len; wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } } static void mlme_event_action_tx_status(struct wpa_driver_capwap_data *drv, struct nlattr *cookie, const u8 *frame, size_t len, struct nlattr *ack) { union wpa_event_data event; const struct ieee80211_hdr *hdr; u16 fc; u64 cookie_val; if (!cookie) return; cookie_val = nla_get_u64(cookie); wpa_printf(MSG_DEBUG, "capwap: Action TX status: cookie=0%llx%s " "(ack=%d)", (long long unsigned int) cookie_val, cookie_val == drv->send_action_cookie ? " (match)" : " (unknown)", ack != NULL); if (cookie_val != drv->send_action_cookie) return; hdr = (const struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.tx_status.type = WLAN_FC_GET_TYPE(fc); event.tx_status.stype = WLAN_FC_GET_STYPE(fc); event.tx_status.dst = hdr->addr1; event.tx_status.data = frame; event.tx_status.data_len = len; event.tx_status.ack = ack != NULL; wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); } static void mlme_event_deauth_disassoc(struct wpa_driver_capwap_data *drv, enum wpa_event_type type, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; const u8 *bssid = NULL; u16 reason_code = 0; mgmt = (const struct ieee80211_mgmt *) frame; if (len >= 24) { bssid = mgmt->bssid; if (drv->associated != 0 && os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { /* * We have presumably received this deauth as a * response to a clear_state_mismatch() outgoing * deauth. Don't let it take us offline! */ wpa_printf(MSG_DEBUG, "capwap: Deauth received " "from Unknown BSSID " MACSTR " -- ignoring", MAC2STR(bssid)); return; } } drv->associated = 0; os_memset(&event, 0, sizeof(event)); /* Note: Same offset for Reason Code in both frame subtypes */ if (len >= 24 + sizeof(mgmt->u.deauth)) reason_code = le_to_host16(mgmt->u.deauth.reason_code); if (type == EVENT_DISASSOC) { event.disassoc_info.addr = bssid; event.disassoc_info.reason_code = reason_code; if (frame + len > mgmt->u.disassoc.variable) { event.disassoc_info.ie = mgmt->u.disassoc.variable; event.disassoc_info.ie_len = frame + len - mgmt->u.disassoc.variable; } } else { event.deauth_info.addr = bssid; event.deauth_info.reason_code = reason_code; if (frame + len > mgmt->u.deauth.variable) { event.deauth_info.ie = mgmt->u.deauth.variable; event.deauth_info.ie_len = frame + len - mgmt->u.deauth.variable; } } wpa_supplicant_event(drv->ctx, type, &event); } static void mlme_event_unprot_disconnect(struct wpa_driver_capwap_data *drv, enum wpa_event_type type, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 reason_code = 0; if (len < 24) return; mgmt = (const struct ieee80211_mgmt *) frame; os_memset(&event, 0, sizeof(event)); /* Note: Same offset for Reason Code in both frame subtypes */ if (len >= 24 + sizeof(mgmt->u.deauth)) reason_code = le_to_host16(mgmt->u.deauth.reason_code); if (type == EVENT_UNPROT_DISASSOC) { event.unprot_disassoc.sa = mgmt->sa; event.unprot_disassoc.da = mgmt->da; event.unprot_disassoc.reason_code = reason_code; } else { event.unprot_deauth.sa = mgmt->sa; event.unprot_deauth.da = mgmt->da; event.unprot_deauth.reason_code = reason_code; } wpa_supplicant_event(drv->ctx, type, &event); } static void mlme_event(struct wpa_driver_capwap_data *drv, enum nl80211_commands cmd, struct nlattr *frame, struct nlattr *addr, struct nlattr *timed_out, struct nlattr *freq, struct nlattr *ack, struct nlattr *cookie) { if (timed_out && addr) { mlme_timeout_event(drv, cmd, addr); return; } if (frame == NULL) { wpa_printf(MSG_DEBUG, "capwap: MLME event %d without frame " "data", cmd); return; } wpa_printf(MSG_DEBUG, "capwap: MLME event %d", cmd); wpa_hexdump(MSG_MSGDUMP, "capwap: MLME event frame", nla_data(frame), nla_len(frame)); switch (cmd) { case NL80211_CMD_AUTHENTICATE: mlme_event_auth(drv, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_ASSOCIATE: mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_DEAUTHENTICATE: mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_DISASSOCIATE: mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME: mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME_TX_STATUS: mlme_event_action_tx_status(drv, cookie, nla_data(frame), nla_len(frame), ack); break; case NL80211_CMD_UNPROT_DEAUTHENTICATE: mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_UNPROT_DISASSOCIATE: mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC, nla_data(frame), nla_len(frame)); break; default: break; } } static void mlme_event_michael_mic_failure(struct wpa_driver_capwap_data *drv, struct nlattr *tb[]) { union wpa_event_data data; wpa_printf(MSG_DEBUG, "capwap: MLME event Michael MIC failure"); os_memset(&data, 0, sizeof(data)); if (tb[NL80211_ATTR_MAC]) { wpa_hexdump(MSG_DEBUG, "capwap: Source MAC address", nla_data(tb[NL80211_ATTR_MAC]), nla_len(tb[NL80211_ATTR_MAC])); data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); } if (tb[NL80211_ATTR_KEY_SEQ]) { wpa_hexdump(MSG_DEBUG, "capwap: TSC", nla_data(tb[NL80211_ATTR_KEY_SEQ]), nla_len(tb[NL80211_ATTR_KEY_SEQ])); } if (tb[NL80211_ATTR_KEY_TYPE]) { enum nl80211_key_type key_type = nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); wpa_printf(MSG_DEBUG, "capwap: Key Type %d", key_type); if (key_type == NL80211_KEYTYPE_PAIRWISE) data.michael_mic_failure.unicast = 1; } else data.michael_mic_failure.unicast = 1; if (tb[NL80211_ATTR_KEY_IDX]) { u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); wpa_printf(MSG_DEBUG, "capwap: Key Id %d", key_id); } wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); } static void mlme_event_join_ibss(struct wpa_driver_capwap_data *drv, struct nlattr *tb[]) { if (tb[NL80211_ATTR_MAC] == NULL) { wpa_printf(MSG_DEBUG, "capwap: No address in IBSS joined " "event"); return; } os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); drv->associated = 1; wpa_printf(MSG_DEBUG, "capwap: IBSS " MACSTR " joined", MAC2STR(drv->bssid)); wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); } static void mlme_event_remain_on_channel(struct wpa_driver_capwap_data *drv, int cancel_event, struct nlattr *tb[]) { unsigned int freq, chan_type, duration; union wpa_event_data data; u64 cookie; if (tb[NL80211_ATTR_WIPHY_FREQ]) freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); else freq = 0; if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); else chan_type = 0; if (tb[NL80211_ATTR_DURATION]) duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); else duration = 0; if (tb[NL80211_ATTR_COOKIE]) cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); else cookie = 0; wpa_printf(MSG_DEBUG, "capwap: Remain-on-channel event (cancel=%d " "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", cancel_event, freq, chan_type, duration, (long long unsigned int) cookie, cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); if (cookie != drv->remain_on_chan_cookie) return; /* not for us */ if (cancel_event) drv->pending_remain_on_chan = 0; os_memset(&data, 0, sizeof(data)); data.remain_on_channel.freq = freq; data.remain_on_channel.duration = duration; wpa_supplicant_event(drv->ctx, cancel_event ? EVENT_CANCEL_REMAIN_ON_CHANNEL : EVENT_REMAIN_ON_CHANNEL, &data); } static void send_scan_event(struct wpa_driver_capwap_data *drv, int aborted, struct nlattr *tb[]) { union wpa_event_data event; struct nlattr *nl; int rem; struct scan_info *info; #define MAX_REPORT_FREQS 50 int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; os_memset(&event, 0, sizeof(event)); info = &event.scan_info; info->aborted = aborted; if (tb[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { struct wpa_driver_scan_ssid *s = &info->ssids[info->num_ssids]; s->ssid = nla_data(nl); s->ssid_len = nla_len(nl); info->num_ssids++; if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) break; } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) { freqs[num_freqs] = nla_get_u32(nl); num_freqs++; if (num_freqs == MAX_REPORT_FREQS - 1) break; } info->freqs = freqs; info->num_freqs = num_freqs; } wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); } static int get_link_signal(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, }; struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; struct wpa_signal_info *sig_change = arg; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_STA_INFO] || nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, tb[NL80211_ATTR_STA_INFO], policy)) return NL_SKIP; if (!sinfo[NL80211_STA_INFO_SIGNAL]) return NL_SKIP; sig_change->current_signal = (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) { sig_change->current_txrate = 0; } else { if (rinfo[NL80211_RATE_INFO_BITRATE]) { sig_change->current_txrate = nla_get_u16(rinfo[ NL80211_RATE_INFO_BITRATE]) * 100; } } } return NL_SKIP; } static int capwap_get_link_signal(struct wpa_driver_capwap_data *drv, struct wpa_signal_info *sig) { struct nl_msg *msg; sig->current_signal = -9999; sig->current_txrate = 0; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); return send_and_recv_msgs(drv, msg, get_link_signal, sig); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int get_link_noise(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, }; struct wpa_signal_info *sig_change = arg; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_SURVEY_INFO]) { wpa_printf(MSG_DEBUG, "capwap: survey data missing!"); return NL_SKIP; } if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, tb[NL80211_ATTR_SURVEY_INFO], survey_policy)) { wpa_printf(MSG_DEBUG, "capwap: failed to parse nested " "attributes!"); return NL_SKIP; } if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) return NL_SKIP; if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != sig_change->frequency) return NL_SKIP; if (!sinfo[NL80211_SURVEY_INFO_NOISE]) return NL_SKIP; sig_change->current_noise = (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); return NL_SKIP; } static int capwap_get_link_noise(struct wpa_driver_capwap_data *drv, struct wpa_signal_info *sig_change) { struct nl_msg *msg; sig_change->current_noise = 9999; sig_change->frequency = drv->assoc_freq; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, get_link_noise, sig_change); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, }; struct wpa_scan_results *scan_results = arg; struct wpa_scan_res *scan_res; size_t i; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_SURVEY_INFO]) { wpa_printf(MSG_DEBUG, "capwap: Survey data missing"); return NL_SKIP; } if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, tb[NL80211_ATTR_SURVEY_INFO], survey_policy)) { wpa_printf(MSG_DEBUG, "capwap: Failed to parse nested " "attributes"); return NL_SKIP; } if (!sinfo[NL80211_SURVEY_INFO_NOISE]) return NL_SKIP; if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) return NL_SKIP; for (i = 0; i < scan_results->num; ++i) { scan_res = scan_results->res[i]; if (!scan_res) continue; if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != scan_res->freq) continue; if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID)) continue; scan_res->noise = (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); scan_res->flags &= ~WPA_SCAN_NOISE_INVALID; } return NL_SKIP; } static int capwap_get_noise_for_scan_results( struct wpa_driver_capwap_data *drv, struct wpa_scan_results *scan_res) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, scan_res); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static void capwap_cqm_event(struct wpa_driver_capwap_data *drv, struct nlattr *tb[]) { static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, }; struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; enum nl80211_cqm_rssi_threshold_event event; union wpa_event_data ed; struct wpa_signal_info sig; int res; if (tb[NL80211_ATTR_CQM] == NULL || nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], cqm_policy)) { wpa_printf(MSG_DEBUG, "capwap: Ignore invalid CQM event"); return; } os_memset(&ed, 0, sizeof(ed)); if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { if (!tb[NL80211_ATTR_MAC]) return; os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); return; } if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) return; event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { wpa_printf(MSG_DEBUG, "capwap: Connection quality monitor " "event: RSSI high"); ed.signal_change.above_threshold = 1; } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { wpa_printf(MSG_DEBUG, "capwap: Connection quality monitor " "event: RSSI low"); ed.signal_change.above_threshold = 0; } else return; res = capwap_get_link_signal(drv, &sig); if (res == 0) { ed.signal_change.current_signal = sig.current_signal; ed.signal_change.current_txrate = sig.current_txrate; wpa_printf(MSG_DEBUG, "capwap: Signal: %d dBm txrate: %d", sig.current_signal, sig.current_txrate); } res = capwap_get_link_noise(drv, &sig); if (res == 0) { ed.signal_change.current_noise = sig.current_noise; wpa_printf(MSG_DEBUG, "capwap: Noise: %d dBm", sig.current_noise); } wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); } static void capwap_new_station_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { u8 *addr; union wpa_event_data data; if (tb[NL80211_ATTR_MAC] == NULL) return; addr = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "capwap: New station " MACSTR, MAC2STR(addr)); if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) { u8 *ies = NULL; size_t ies_len = 0; if (tb[NL80211_ATTR_IE]) { ies = nla_data(tb[NL80211_ATTR_IE]); ies_len = nla_len(tb[NL80211_ATTR_IE]); } wpa_hexdump(MSG_DEBUG, "capwap: Assoc Req IEs", ies, ies_len); drv_event_assoc(drv->ctx, addr, ies, ies_len, 0); return; } if (drv->nlmode != NL80211_IFTYPE_ADHOC) return; os_memset(&data, 0, sizeof(data)); os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); } static void capwap_del_station_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { u8 *addr; union wpa_event_data data; if (tb[NL80211_ATTR_MAC] == NULL) return; addr = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "capwap: Delete station " MACSTR, MAC2STR(addr)); if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) { drv_event_disassoc(drv->ctx, addr); return; } if (drv->nlmode != NL80211_IFTYPE_ADHOC) return; os_memset(&data, 0, sizeof(data)); os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); } static void capwap_rekey_offload_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { [NL80211_REKEY_DATA_KEK] = { .minlen = NL80211_KEK_LEN, .maxlen = NL80211_KEK_LEN, }, [NL80211_REKEY_DATA_KCK] = { .minlen = NL80211_KCK_LEN, .maxlen = NL80211_KCK_LEN, }, [NL80211_REKEY_DATA_REPLAY_CTR] = { .minlen = NL80211_REPLAY_CTR_LEN, .maxlen = NL80211_REPLAY_CTR_LEN, }, }; union wpa_event_data data; if (!tb[NL80211_ATTR_MAC]) return; if (!tb[NL80211_ATTR_REKEY_DATA]) return; if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) return; if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) return; os_memset(&data, 0, sizeof(data)); data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "capwap: Rekey offload event for BSSID " MACSTR, MAC2STR(data.driver_gtk_rekey.bssid)); data.driver_gtk_rekey.replay_ctr = nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); wpa_hexdump(MSG_DEBUG, "capwap: Rekey offload - Replay Counter", data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); } static void capwap_pmksa_candidate_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, [NL80211_PMKSA_CANDIDATE_BSSID] = { .minlen = ETH_ALEN, .maxlen = ETH_ALEN, }, [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, }; union wpa_event_data data; if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) return; if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) return; if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || !cand[NL80211_PMKSA_CANDIDATE_BSSID]) return; os_memset(&data, 0, sizeof(data)); os_memcpy(data.pmkid_candidate.bssid, nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); data.pmkid_candidate.index = nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); data.pmkid_candidate.preauth = cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); } static int process_event(struct nl_msg *msg, void *arg) { struct wpa_driver_capwap_data *drv = arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_IFINDEX]) { int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { wpa_printf(MSG_DEBUG, "capwap: Ignored event (cmd=%d)" " for foreign interface (ifindex %d)", gnlh->cmd, ifindex); return NL_SKIP; } } if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { wpa_driver_capwap_set_mode(&drv->first_bss, drv->ap_scan_as_station); drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } switch (gnlh->cmd) { case NL80211_CMD_TRIGGER_SCAN: wpa_printf(MSG_DEBUG, "capwap: Scan trigger"); break; case NL80211_CMD_START_SCHED_SCAN: wpa_printf(MSG_DEBUG, "capwap: Sched scan started"); break; case NL80211_CMD_SCHED_SCAN_STOPPED: wpa_printf(MSG_DEBUG, "capwap: Sched scan stopped"); wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); break; case NL80211_CMD_NEW_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "capwap: New scan results available"); drv->scan_complete_events = 1; eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); send_scan_event(drv, 0, tb); break; case NL80211_CMD_SCHED_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "capwap: New sched scan results available"); send_scan_event(drv, 0, tb); break; case NL80211_CMD_SCAN_ABORTED: wpa_printf(MSG_DEBUG, "capwap: Scan aborted"); /* * Need to indicate that scan results are available in order * not to make wpa_supplicant stop its scanning. */ eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); send_scan_event(drv, 1, tb); break; case NL80211_CMD_AUTHENTICATE: case NL80211_CMD_ASSOCIATE: case NL80211_CMD_DEAUTHENTICATE: case NL80211_CMD_DISASSOCIATE: case NL80211_CMD_FRAME: case NL80211_CMD_FRAME_TX_STATUS: case NL80211_CMD_UNPROT_DEAUTHENTICATE: case NL80211_CMD_UNPROT_DISASSOCIATE: mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; case NL80211_CMD_CONNECT: case NL80211_CMD_ROAM: mlme_event_connect(drv, gnlh->cmd, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_RESP_IE]); break; case NL80211_CMD_DISCONNECT: mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], tb[NL80211_ATTR_MAC]); break; case NL80211_CMD_MICHAEL_MIC_FAILURE: mlme_event_michael_mic_failure(drv, tb); break; case NL80211_CMD_JOIN_IBSS: mlme_event_join_ibss(drv, tb); break; case NL80211_CMD_REMAIN_ON_CHANNEL: mlme_event_remain_on_channel(drv, 0, tb); break; case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: mlme_event_remain_on_channel(drv, 1, tb); break; case NL80211_CMD_NOTIFY_CQM: capwap_cqm_event(drv, tb); break; case NL80211_CMD_REG_CHANGE: wpa_printf(MSG_DEBUG, "capwap: Regulatory domain change"); wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, NULL); break; case NL80211_CMD_REG_BEACON_HINT: wpa_printf(MSG_DEBUG, "capwap: Regulatory beacon hint"); wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, NULL); break; case NL80211_CMD_NEW_STATION: capwap_new_station_event(drv, tb); break; case NL80211_CMD_DEL_STATION: capwap_del_station_event(drv, tb); break; case NL80211_CMD_SET_REKEY_OFFLOAD: capwap_rekey_offload_event(drv, tb); break; case NL80211_CMD_PMKSA_CANDIDATE: capwap_pmksa_candidate_event(drv, tb); break; default: wpa_printf(MSG_DEBUG, "capwap: Ignored unknown event " "(cmd=%d)", gnlh->cmd); break; } return NL_SKIP; } static void wpa_driver_capwap_event_receive(int sock, void *eloop_ctx, void *handle) { struct nl_cb *cb; struct wpa_driver_capwap_data *drv = eloop_ctx; wpa_printf(MSG_DEBUG, "capwap: Event message available"); cb = nl_cb_clone(drv->global->nl_cb); if (!cb) return; nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv); nl_recvmsgs(handle, cb); nl_cb_put(cb); } /** * wpa_driver_capwap_set_country - ask capwap to set the regulatory domain * @priv: driver_capwap private data * @alpha2_arg: country to which to switch to * Returns: 0 on success, -1 on failure * * This asks capwap to set the regulatory domain for given * country ISO / IEC alpha2. */ static int wpa_driver_capwap_set_country(void *priv, const char *alpha2_arg) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; char alpha2[3]; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; alpha2[0] = alpha2_arg[0]; alpha2[1] = alpha2_arg[1]; alpha2[2] = '\0'; capwap_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG); NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2); if (send_and_recv_msgs(drv, msg, NULL, NULL)) return -EINVAL; return 0; nla_put_failure: nlmsg_free(msg); return -EINVAL; } struct wiphy_info_data { struct wpa_driver_capa *capa; unsigned int error:1; }; static int wiphy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct wiphy_info_data *info = arg; int p2p_go_supported = 0, p2p_client_supported = 0; int p2p_concurrent = 0; int auth_supported = 0, connect_supported = 0; struct wpa_driver_capa *capa = info->capa; static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = { [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, }, iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) capa->max_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) capa->max_sched_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); if (tb[NL80211_ATTR_MAX_MATCH_SETS]) capa->max_match_sets = nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { struct nlattr *nl_mode; int i; nla_for_each_nested(nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { switch (nla_type(nl_mode)) { case NL80211_IFTYPE_AP: capa->flags |= WPA_DRIVER_FLAGS_AP; break; case NL80211_IFTYPE_P2P_GO: p2p_go_supported = 1; break; case NL80211_IFTYPE_P2P_CLIENT: p2p_client_supported = 1; break; } } } if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) { struct nlattr *nl_combi; int rem_combi; nla_for_each_nested(nl_combi, tb[NL80211_ATTR_INTERFACE_COMBINATIONS], rem_combi) { struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; struct nlattr *nl_limit, *nl_mode; int err, rem_limit, rem_mode; int combination_has_p2p = 0, combination_has_mgd = 0; err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, nl_combi, iface_combination_policy); if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || !tb_comb[NL80211_IFACE_COMB_MAXNUM] || !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) goto broken_combination; nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS], rem_limit) { err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT, nl_limit, iface_limit_policy); if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES]) goto broken_combination; nla_for_each_nested( nl_mode, tb_limit[NL80211_IFACE_LIMIT_TYPES], rem_mode) { int ift = nla_type(nl_mode); if (ift == NL80211_IFTYPE_P2P_GO || ift == NL80211_IFTYPE_P2P_CLIENT) combination_has_p2p = 1; if (ift == NL80211_IFTYPE_STATION) combination_has_mgd = 1; } if (combination_has_p2p && combination_has_mgd) break; } if (combination_has_p2p && combination_has_mgd) { p2p_concurrent = 1; break; } broken_combination: ; } } if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { struct nlattr *nl_cmd; int i; nla_for_each_nested(nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { switch (nla_get_u32(nl_cmd)) { case NL80211_CMD_AUTHENTICATE: auth_supported = 1; break; case NL80211_CMD_CONNECT: connect_supported = 1; break; case NL80211_CMD_START_SCHED_SCAN: /* * Disabled for 1.x for now as it is * broken there due to the way it ends * up getting used. capa->sched_scan_supported = 1; */ break; } } } if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { wpa_printf(MSG_DEBUG, "capwap: Using driver-based " "off-channel TX"); capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; } if (tb[NL80211_ATTR_ROAM_SUPPORT]) { wpa_printf(MSG_DEBUG, "capwap: Using driver-based roaming"); capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; } /* default to 5000 since early versions of mac80211 don't set it */ capa->max_remain_on_chan = 5000; if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]) capa->max_remain_on_chan = nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); if (auth_supported) capa->flags |= WPA_DRIVER_FLAGS_SME; else if (!connect_supported) { wpa_printf(MSG_INFO, "capwap: Driver does not support " "authentication/association or connect commands"); info->error = 1; } if (p2p_go_supported && p2p_client_supported) capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; if (p2p_concurrent) { wpa_printf(MSG_DEBUG, "capwap: Use separate P2P group " "interface (driver advertised support)"); capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } if (tb[NL80211_ATTR_TDLS_SUPPORT]) { wpa_printf(MSG_DEBUG, "capwap: TDLS supported"); capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) { wpa_printf(MSG_DEBUG, "capwap: TDLS external setup"); capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; } } return NL_SKIP; } static int wpa_driver_capwap_get_info(struct wpa_driver_capwap_data *drv, struct wiphy_info_data *info) { return 0; } static int wpa_driver_capwap_capa(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG," 4.wpa_driver_capwap_capa"); struct wiphy_info_data info; if (wpa_driver_capwap_get_info(drv, &info)) return -1; drv->has_capability = 1; /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; return 0; } #ifdef ANDROID static int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name) { /* * Android ICS has very minimal genl_ctrl_resolve() implementation, so * need to work around that. */ struct nl_cache *cache = NULL; struct genl_family *capwap = NULL; int id = -1; if (genl_ctrl_alloc_cache(handle, &cache) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate generic " "netlink cache"); goto fail; } capwap = genl_ctrl_search_by_name(cache, name); if (capwap == NULL) goto fail; id = genl_family_get_id(capwap); fail: if (capwap) genl_family_put(capwap); if (cache) nl_cache_free(cache); return id; } #define genl_ctrl_resolve android_genl_ctrl_resolve #endif /* ANDROID */ static int wpa_driver_capwap_init_nl_global(struct capwap_global *global) { wpa_printf(MSG_DEBUG," 2.wpa_driver_capwap_init_nl_global"); global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); if (global->nl_cb == NULL) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate netlink " "callbacks"); return -1; } if (nl_create_handles(&global->nl, global->nl_cb, "nl")) return -1; global->capwap = genl_ctrl_search_by_name(global->nl.cache, "nl80211"); if (global->capwap == NULL) { wpa_printf(MSG_ERROR, "capwap: 'capwap' generic netlink not " "found"); } return 0; } static int wpa_driver_capwap_init_nl(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_init_nl"); return 0; } static void wpa_driver_capwap_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "capwap: RFKILL blocked"); /* * This may be for any interface; use ifdown event to disable * interface. */ } static void wpa_driver_capwap_rfkill_unblocked(void *ctx) { struct wpa_driver_capwap_data *drv = ctx; wpa_printf(MSG_DEBUG, "capwap: RFKILL unblocked"); if (linux_set_iface_flags(drv->global->ioctl_sock, drv->first_bss.ifname, 1)) { wpa_printf(MSG_DEBUG, "capwap: Could not set interface UP " "after rfkill unblock"); return; } /* rtnetlink ifup handler will report interface as enabled */ } static void capwap_get_phy_name(struct wpa_driver_capwap_data *drv) { drv->phyname[0] = '\0'; return; } #ifdef CONFIG_AP static void capwap_l2_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { wpa_printf(MSG_DEBUG, "capwap: l2_packet read %u", (unsigned int) len); } #endif /* CONFIG_AP */ /** * wpa_driver_capwap_init - Initialize capwap driver interface * @ctx: context to be used when calling wpa_supplicant functions, * e.g., wpa_supplicant_event() * @ifname: interface name, e.g., wlan0 * @global_priv: private driver global data from global_init() * Returns: Pointer to private data, %NULL on failure */ static void * wpa_driver_capwap_init(void *ctx, const char *ifname, void *global_priv) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_init"); struct wpa_driver_capwap_data *drv; struct rfkill_config *rcfg; struct i802_bss *bss; if (global_priv == NULL) return NULL; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) return NULL; drv->global = global_priv; drv->ctx = ctx; bss = &drv->first_bss; bss->drv = drv; os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); drv->monitor_ifidx = -1; drv->monitor_sock = -1; drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; if (wpa_driver_capwap_init_nl(drv)) { os_free(drv); return NULL; } capwap_get_phy_name(drv); rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL) goto failed; rcfg->ctx = drv; os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); rcfg->blocked_cb = wpa_driver_capwap_rfkill_blocked; rcfg->unblocked_cb = wpa_driver_capwap_rfkill_unblocked; drv->rfkill = rfkill_init(rcfg); if (drv->rfkill == NULL) { wpa_printf(MSG_DEBUG, "capwap: RFKILL status not available"); os_free(rcfg); } if (wpa_driver_capwap_finish_drv_init(drv)) goto failed; #ifdef CONFIG_AP drv->l2 = l2_packet_init(ifname, NULL, ETH_P_EAPOL, capwap_l2_read, drv, 0); #endif /* CONFIG_AP */ if (drv->global) { dl_list_add(&drv->global->interfaces, &drv->list); drv->in_interface_list = 1; } return bss; failed: wpa_driver_capwap_deinit(bss); return NULL; } static int capwap_register_frame(struct wpa_driver_capwap_data *drv, struct nl_handle *nl_handle, u16 type, const u8 *match, size_t match_len) { struct nl_msg *msg; int ret = -1; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); ret = send_and_recv(drv, nl_handle, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Register frame command " "failed (type=%u): ret=%d (%s)", type, ret, strerror(-ret)); wpa_hexdump(MSG_DEBUG, "capwap: Register frame match", match, match_len); goto nla_put_failure; } ret = 0; nla_put_failure: nlmsg_free(msg); return ret; } static int capwap_register_action_frame(struct wpa_driver_capwap_data *drv, const u8 *match, size_t match_len) { u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); return capwap_register_frame(drv, drv->nl_event.handle, type, match, match_len); } static int capwap_register_action_frames(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG," 6.capwap_register_action_frames"); return 0; } static void wpa_driver_capwap_send_rfkill(void *eloop_ctx, void *timeout_ctx) { wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); } static int wpa_driver_capwap_finish_drv_init(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG," 3.wpa_driver_capwap_finish_drv_init"); struct i802_bss *bss = &drv->first_bss; int send_rfkill_event = 0; drv->ifindex = if_nametoindex(bss->ifname); drv->first_bss.ifindex = drv->ifindex; #ifndef HOSTAPD /* * Make sure the interface starts up in station mode unless this is a * dynamically added interface (e.g., P2P) that was already configured * with proper iftype. */ if (drv->ifindex != drv->global->if_add_ifindex && wpa_driver_capwap_set_mode(bss, NL80211_IFTYPE_STATION) < 0) { wpa_printf(MSG_ERROR, "capwap: Could not configure driver to " "use managed mode"); return -1; } if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { if (rfkill_is_blocked(drv->rfkill)) { wpa_printf(MSG_DEBUG, "capwap: Could not yet enable " "interface '%s' due to rfkill", bss->ifname); drv->if_disabled = 1; send_rfkill_event = 1; } else { wpa_printf(MSG_ERROR, "capwap: Could not set " "interface '%s' UP", bss->ifname); return -1; } } netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT); #endif /* HOSTAPD */ if (wpa_driver_capwap_capa(drv)) return -1; if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, drv->addr)) return -1; if (capwap_register_action_frames(drv) < 0) { wpa_printf(MSG_DEBUG, "capwap: Failed to register Action " "frame processing - ignore for now"); /* * Older kernel versions did not support this, so ignore the * error for now. Some functionality may not be available * because of this. */ } if (send_rfkill_event) { eloop_register_timeout(0, 0, wpa_driver_capwap_send_rfkill, drv, drv->ctx); } return 0; } static int wpa_driver_capwap_del_beacon(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } /** * wpa_driver_capwap_deinit - Deinitialize capwap driver interface * @priv: Pointer to private capwap data from wpa_driver_capwap_init() * * Shut down driver interface and processing of driver events. Free * private data buffer if one was allocated in wpa_driver_capwap_init(). */ static void wpa_driver_capwap_deinit(void *priv) { wpa_printf(MSG_DEBUG,"wpa_driver_capwap_deinit\n"); /* struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; fake_mgmt_null_rates(drv->ctx); */ } /** * wpa_driver_capwap_scan_timeout - Scan timeout to report scan completion * @eloop_ctx: Driver private data * @timeout_ctx: ctx argument given to wpa_driver_capwap_init() * * This function can be used as registered timeout when starting a scan to * generate a scan completed event if the driver does not report this. */ static void wpa_driver_capwap_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_capwap_data *drv = eloop_ctx; if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { wpa_driver_capwap_set_mode(&drv->first_bss, drv->ap_scan_as_station); drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } /** * wpa_driver_capwap_scan - Request the driver to initiate scan * @priv: Pointer to private driver data from wpa_driver_capwap_init() * @params: Scan parameters * Returns: 0 on success, -1 on failure */ static int wpa_driver_capwap_scan(void *priv, struct wpa_driver_scan_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = 0, timeout; struct nl_msg *msg, *ssids, *freqs, *rates; size_t i; msg = nlmsg_alloc(); ssids = nlmsg_alloc(); freqs = nlmsg_alloc(); rates = nlmsg_alloc(); if (!msg || !ssids || !freqs || !rates) { nlmsg_free(msg); nlmsg_free(ssids); nlmsg_free(freqs); nlmsg_free(rates); return -1; } os_free(drv->filter_ssids); drv->filter_ssids = params->filter_ssids; params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; capwap_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); for (i = 0; i < params->num_ssids; i++) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Scan SSID", params->ssids[i].ssid, params->ssids[i].ssid_len); NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, params->ssids[i].ssid); } if (params->num_ssids) nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); if (params->extra_ies) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Scan extra IEs", params->extra_ies, params->extra_ies_len); NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies); } if (params->freqs) { for (i = 0; params->freqs[i]; i++) { wpa_printf(MSG_MSGDUMP, "capwap: Scan frequency %u " "MHz", params->freqs[i]); NLA_PUT_U32(freqs, i + 1, params->freqs[i]); } nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } if (params->p2p_probe) { /* * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates * by masking out everything else apart from the OFDM rates 6, * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz * rates are left enabled. */ NLA_PUT(rates, NL80211_BAND_2GHZ, 8, "\x0c\x12\x18\x24\x30\x48\x60\x6c"); nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates); NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); #ifdef HOSTAPD if (is_ap_interface(drv->nlmode)) { /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ if (wpa_driver_capwap_set_mode( bss, NL80211_IFTYPE_STATION)) goto nla_put_failure; if (wpa_driver_capwap_scan(drv, params)) { wpa_driver_capwap_set_mode(bss, drv->nlmode); goto nla_put_failure; } /* Restore AP mode when processing scan results */ drv->ap_scan_as_station = drv->nlmode; ret = 0; } else goto nla_put_failure; #else /* HOSTAPD */ goto nla_put_failure; #endif /* HOSTAPD */ } /* Not all drivers generate "scan completed" wireless event, so try to * read results after a timeout. */ timeout = 10; if (drv->scan_complete_events) { /* * The driver seems to deliver events to notify when scan is * complete, so use longer timeout to avoid race conditions * with scanning and following association request. */ timeout = 30; } wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " "seconds", ret, timeout); eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_capwap_scan_timeout, drv, drv->ctx); nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); nlmsg_free(freqs); nlmsg_free(rates); return ret; } /** * wpa_driver_capwap_sched_scan - Initiate a scheduled scan * @priv: Pointer to private driver data from wpa_driver_capwap_init() * @params: Scan parameters * @interval: Interval between scan cycles in milliseconds * Returns: 0 on success, -1 on failure or if not supported */ static int wpa_driver_capwap_sched_scan(void *priv, struct wpa_driver_scan_params *params, u32 interval) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = 0; struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets; size_t i; msg = nlmsg_alloc(); ssids = nlmsg_alloc(); freqs = nlmsg_alloc(); if (!msg || !ssids || !freqs) { nlmsg_free(msg); nlmsg_free(ssids); nlmsg_free(freqs); return -1; } os_free(drv->filter_ssids); drv->filter_ssids = params->filter_ssids; params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; capwap_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval); if (drv->num_filter_ssids) { match_sets = nlmsg_alloc(); for (i = 0; i < drv->num_filter_ssids; i++) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan filter SSID", drv->filter_ssids[i].ssid, drv->filter_ssids[i].ssid_len); match_set_ssid = nlmsg_alloc(); nla_put(match_set_ssid, NL80211_ATTR_SCHED_SCAN_MATCH_SSID, drv->filter_ssids[i].ssid_len, drv->filter_ssids[i].ssid); nla_put_nested(match_sets, i + 1, match_set_ssid); nlmsg_free(match_set_ssid); } nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, match_sets); nlmsg_free(match_sets); } for (i = 0; i < params->num_ssids; i++) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan SSID", params->ssids[i].ssid, params->ssids[i].ssid_len); NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, params->ssids[i].ssid); } if (params->num_ssids) nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); if (params->extra_ies) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan extra IEs", params->extra_ies, params->extra_ies_len); NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies); } if (params->freqs) { for (i = 0; params->freqs[i]; i++) { wpa_printf(MSG_MSGDUMP, "capwap: Scan frequency %u " "MHz", params->freqs[i]); NLA_PUT_U32(freqs, i + 1, params->freqs[i]); } nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); /* TODO: if we get an error here, we should fall back to normal scan */ msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Sched scan start failed: " "ret=%d (%s)", ret, strerror(-ret)); goto nla_put_failure; } wpa_printf(MSG_DEBUG, "capwap: Sched scan requested (ret=%d) - " "scan interval %d msec", ret, interval); nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); nlmsg_free(freqs); return ret; } /** * wpa_driver_capwap_stop_sched_scan - Stop a scheduled scan * @priv: Pointer to private driver data from wpa_driver_capwap_init() * Returns: 0 on success, -1 on failure or if not supported */ static int wpa_driver_capwap_stop_sched_scan(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = 0; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Sched scan stop failed: " "ret=%d (%s)", ret, strerror(-ret)); goto nla_put_failure; } wpa_printf(MSG_DEBUG, "capwap: Sched scan stop sent (ret=%d)", ret); nla_put_failure: nlmsg_free(msg); return ret; } static const u8 * capwap_get_ie(const u8 *ies, size_t ies_len, u8 ie) { const u8 *end, *pos; if (ies == NULL) return NULL; pos = ies; end = ies + ies_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == ie) return pos; pos += 2 + pos[1]; } return NULL; } static int capwap_scan_filtered(struct wpa_driver_capwap_data *drv, const u8 *ie, size_t ie_len) { const u8 *ssid; size_t i; if (drv->filter_ssids == NULL) return 0; ssid = capwap_get_ie(ie, ie_len, WLAN_EID_SSID); if (ssid == NULL) return 1; for (i = 0; i < drv->num_filter_ssids; i++) { if (ssid[1] == drv->filter_ssids[i].ssid_len && os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == 0) return 0; } return 1; } static int bss_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *bss[NL80211_BSS_MAX + 1]; static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, [NL80211_BSS_TSF] = { .type = NLA_U64 }, [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, }; struct capwap_bss_info_arg *_arg = arg; struct wpa_scan_results *res = _arg->res; struct wpa_scan_res **tmp; struct wpa_scan_res *r; const u8 *ie, *beacon_ie; size_t ie_len, beacon_ie_len; u8 *pos; size_t i; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_BSS]) return NL_SKIP; if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) return NL_SKIP; if (bss[NL80211_BSS_STATUS]) { enum nl80211_bss_status status; status = nla_get_u32(bss[NL80211_BSS_STATUS]); if (status == NL80211_BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_FREQUENCY]) { _arg->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); wpa_printf(MSG_DEBUG, "capwap: Associated on %u MHz", _arg->assoc_freq); } if (status == NL80211_BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_BSSID]) { os_memcpy(_arg->assoc_bssid, nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); wpa_printf(MSG_DEBUG, "capwap: Associated with " MACSTR, MAC2STR(_arg->assoc_bssid)); } } if (!res) return NL_SKIP; if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); } else { ie = NULL; ie_len = 0; } if (bss[NL80211_BSS_BEACON_IES]) { beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); } else { beacon_ie = NULL; beacon_ie_len = 0; } if (capwap_scan_filtered(_arg->drv, ie ? ie : beacon_ie, ie ? ie_len : beacon_ie_len)) return NL_SKIP; r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); if (r == NULL) return NL_SKIP; if (bss[NL80211_BSS_BSSID]) os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); if (bss[NL80211_BSS_FREQUENCY]) r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); if (bss[NL80211_BSS_BEACON_INTERVAL]) r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); if (bss[NL80211_BSS_CAPABILITY]) r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); r->flags |= WPA_SCAN_NOISE_INVALID; if (bss[NL80211_BSS_SIGNAL_MBM]) { r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); r->level /= 100; /* mBm to dBm */ r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); r->flags |= WPA_SCAN_QUAL_INVALID; } else r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; if (bss[NL80211_BSS_TSF]) r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); if (bss[NL80211_BSS_SEEN_MS_AGO]) r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); r->ie_len = ie_len; pos = (u8 *) (r + 1); if (ie) { os_memcpy(pos, ie, ie_len); pos += ie_len; } r->beacon_ie_len = beacon_ie_len; if (beacon_ie) os_memcpy(pos, beacon_ie, beacon_ie_len); if (bss[NL80211_BSS_STATUS]) { enum nl80211_bss_status status; status = nla_get_u32(bss[NL80211_BSS_STATUS]); switch (status) { case NL80211_BSS_STATUS_AUTHENTICATED: r->flags |= WPA_SCAN_AUTHENTICATED; break; case NL80211_BSS_STATUS_ASSOCIATED: r->flags |= WPA_SCAN_ASSOCIATED; break; default: break; } } /* * cfg80211 maintains separate BSS table entries for APs if the same * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does * not use frequency as a separate key in the BSS table, so filter out * duplicated entries. Prefer associated BSS entry in such a case in * order to get the correct frequency into the BSS table. */ for (i = 0; i < res->num; i++) { const u8 *s1, *s2; if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0) continue; s1 = capwap_get_ie((u8 *) (res->res[i] + 1), res->res[i]->ie_len, WLAN_EID_SSID); s2 = capwap_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID); if (s1 == NULL || s2 == NULL || s1[1] != s2[1] || os_memcmp(s1, s2, 2 + s1[1]) != 0) continue; /* Same BSSID,SSID was already included in scan results */ wpa_printf(MSG_DEBUG, "capwap: Remove duplicated scan result " "for " MACSTR, MAC2STR(r->bssid)); if ((r->flags & WPA_SCAN_ASSOCIATED) && !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) { os_free(res->res[i]); res->res[i] = r; } else os_free(r); return NL_SKIP; } tmp = os_realloc(res->res, (res->num + 1) * sizeof(struct wpa_scan_res *)); if (tmp == NULL) { os_free(r); return NL_SKIP; } tmp[res->num++] = r; res->res = tmp; return NL_SKIP; } static void clear_state_mismatch(struct wpa_driver_capwap_data *drv, const u8 *addr) { if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { wpa_printf(MSG_DEBUG, "capwap: Clear possible state " "mismatch (" MACSTR ")", MAC2STR(addr)); wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, WLAN_REASON_PREV_AUTH_NOT_VALID, 1); } } static void wpa_driver_capwap_check_bss_status( struct wpa_driver_capwap_data *drv, struct wpa_scan_results *res) { size_t i; for (i = 0; i < res->num; i++) { struct wpa_scan_res *r = res->res[i]; if (r->flags & WPA_SCAN_AUTHENTICATED) { wpa_printf(MSG_DEBUG, "capwap: Scan results " "indicates BSS status with " MACSTR " as authenticated", MAC2STR(r->bssid)); if (is_sta_interface(drv->nlmode) && os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "capwap: Unknown BSSID" " in local state (auth=" MACSTR " assoc=" MACSTR ")", MAC2STR(drv->auth_bssid), MAC2STR(drv->bssid)); clear_state_mismatch(drv, r->bssid); } } if (r->flags & WPA_SCAN_ASSOCIATED) { wpa_printf(MSG_DEBUG, "capwap: Scan results " "indicate BSS status with " MACSTR " as associated", MAC2STR(r->bssid)); if (is_sta_interface(drv->nlmode) && !drv->associated) { wpa_printf(MSG_DEBUG, "capwap: Local state " "(not associated) does not match " "with BSS state"); clear_state_mismatch(drv, r->bssid); } else if (is_sta_interface(drv->nlmode) && os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "capwap: Local state " "(associated with " MACSTR ") does " "not match with BSS state", MAC2STR(drv->bssid)); clear_state_mismatch(drv, r->bssid); clear_state_mismatch(drv, drv->bssid); } } } } static struct wpa_scan_results * capwap_get_scan_results(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; struct wpa_scan_results *res; int ret; struct capwap_bss_info_arg arg; res = os_zalloc(sizeof(*res)); if (res == NULL) return NULL; msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; arg.res = res; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "capwap: Received scan results (%lu " "BSSes)", (unsigned long) res->num); capwap_get_noise_for_scan_results(drv, res); return res; } wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); wpa_scan_results_free(res); return NULL; } /** * wpa_driver_capwap_get_scan_results - Fetch the latest scan results * @priv: Pointer to private wext data from wpa_driver_capwap_init() * Returns: Scan results on success, -1 on failure */ static struct wpa_scan_results * wpa_driver_capwap_get_scan_results(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct wpa_scan_results *res; res = capwap_get_scan_results(drv); if (res) wpa_driver_capwap_check_bss_status(drv, res); return res; } static void capwap_dump_scan(struct wpa_driver_capwap_data *drv) { struct wpa_scan_results *res; size_t i; res = capwap_get_scan_results(drv); if (res == NULL) { wpa_printf(MSG_DEBUG, "capwap: Failed to get scan results"); return; } wpa_printf(MSG_DEBUG, "capwap: Scan result dump"); for (i = 0; i < res->num; i++) { struct wpa_scan_res *r = res->res[i]; wpa_printf(MSG_DEBUG, "capwap: %d/%d " MACSTR "%s%s", (int) i, (int) res->num, MAC2STR(r->bssid), r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "", r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); } wpa_scan_results_free(res); } static int wpa_driver_capwap_set_key(const char *ifname, void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ifindex = if_nametoindex(ifname); struct nl_msg *msg; int ret; wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d " "set_tx=%d seq_len=%lu key_len=%lu", __func__, ifindex, alg, addr, key_idx, set_tx, (unsigned long) seq_len, (unsigned long) key_len); #ifdef CONFIG_TDLS if (key_idx == -1) key_idx = 0; #endif /* CONFIG_TDLS */ msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (alg == WPA_ALG_NONE) { capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY); } else { capwap_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); switch (alg) { case WPA_ALG_WEP: if (key_len == 5) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP104); break; case WPA_ALG_TKIP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); break; case WPA_ALG_CCMP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); break; case WPA_ALG_IGTK: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_AES_CMAC); break; default: wpa_printf(MSG_ERROR, "%s: Unsupported encryption " "algorithm %d", __func__, alg); nlmsg_free(msg); return -1; } } if (seq && seq_len) NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq); if (addr && !is_broadcast_ether_addr(addr)) { wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); if (alg != WPA_ALG_WEP && key_idx && !set_tx) { wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK"); NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, NL80211_KEYTYPE_GROUP); } } else if (addr && is_broadcast_ether_addr(addr)) { struct nl_msg *types; int err; wpa_printf(MSG_DEBUG, " broadcast key"); types = nlmsg_alloc(); if (!types) goto nla_put_failure; NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, types); nlmsg_free(types); if (err) goto nla_put_failure; } NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) ret = 0; if (ret) wpa_printf(MSG_DEBUG, "capwap: set_key failed; err=%d %s)", ret, strerror(-ret)); /* * If we failed or don't need to set the default TX key (below), * we're done here. */ if (ret || !set_tx || alg == WPA_ALG_NONE) return ret; if (is_ap_interface(drv->nlmode) && addr && !is_broadcast_ether_addr(addr)) return ret; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_KEY); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (alg == WPA_ALG_IGTK) NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); else NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); if (addr && is_broadcast_ether_addr(addr)) { struct nl_msg *types; int err; types = nlmsg_alloc(); if (!types) goto nla_put_failure; NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, types); nlmsg_free(types); if (err) goto nla_put_failure; } else if (addr) { struct nl_msg *types; int err; types = nlmsg_alloc(); if (!types) goto nla_put_failure; NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST); err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, types); nlmsg_free(types); if (err) goto nla_put_failure; } ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret == -ENOENT) ret = 0; if (ret) wpa_printf(MSG_DEBUG, "capwap: set_key default failed; " "err=%d %s)", ret, strerror(-ret)); return ret; nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, int key_idx, int defkey, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); if (!key_attr) return -1; if (defkey && alg == WPA_ALG_IGTK) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT); else if (defkey) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); switch (alg) { case WPA_ALG_WEP: if (key_len == 5) NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP104); break; case WPA_ALG_TKIP: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); break; case WPA_ALG_CCMP: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); break; case WPA_ALG_IGTK: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_AES_CMAC); break; default: wpa_printf(MSG_ERROR, "%s: Unsupported encryption " "algorithm %d", __func__, alg); return -1; } if (seq && seq_len) NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); NLA_PUT(msg, NL80211_KEY_DATA, key_len, key); nla_nest_end(msg, key_attr); return 0; nla_put_failure: return -1; } static int capwap_set_conn_keys(struct wpa_driver_associate_params *params, struct nl_msg *msg) { int i, privacy = 0; struct nlattr *nl_keys, *nl_key; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; privacy = 1; break; } if (params->wps == WPS_MODE_PRIVACY) privacy = 1; if (params->pairwise_suite && params->pairwise_suite != WPA_CIPHER_NONE) privacy = 1; if (!privacy) return 0; NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS); if (!nl_keys) goto nla_put_failure; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; nl_key = nla_nest_start(msg, i); if (!nl_key) goto nla_put_failure; NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i], params->wep_key[i]); if (params->wep_key_len[i] == 5) NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP104); NLA_PUT_U8(msg, NL80211_KEY_IDX, i); if (i == params->wep_tx_keyidx) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); nla_nest_end(msg, nl_key); } nla_nest_end(msg, nl_keys); return 0; nla_put_failure: return -ENOBUFS; } static int wpa_driver_capwap_mlme(struct wpa_driver_capwap_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change) { int ret = -1; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); if (local_state_change) NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); goto nla_put_failure; } ret = 0; nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_disconnect(struct wpa_driver_capwap_data *drv, const u8 *addr, int reason_code) { wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", __func__, MAC2STR(addr), reason_code); drv->associated = 0; return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DISCONNECT, reason_code, 0); } static int wpa_driver_capwap_deauthenticate(void *priv, const u8 *addr, int reason_code) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) return wpa_driver_capwap_disconnect(drv, addr, reason_code); wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", __func__, MAC2STR(addr), reason_code); drv->associated = 0; if (drv->nlmode == NL80211_IFTYPE_ADHOC) return capwap_leave_ibss(drv); return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, reason_code, 0); } static int wpa_driver_capwap_disassociate(void *priv, const u8 *addr, int reason_code) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) return wpa_driver_capwap_disconnect(drv, addr, reason_code); wpa_printf(MSG_DEBUG, "%s", __func__); drv->associated = 0; return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DISASSOCIATE, reason_code, 0); } static int wpa_driver_capwap_authenticate( void *priv, struct wpa_driver_auth_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1, i; struct nl_msg *msg; enum nl80211_auth_type type; enum nl80211_iftype nlmode; int count = 0; drv->associated = 0; os_memset(drv->auth_bssid, 0, ETH_ALEN); /* FIX: IBSS mode */ nlmode = params->p2p ? NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; if (drv->nlmode != nlmode && wpa_driver_capwap_set_mode(priv, nlmode) < 0) return -1; retry: msg = nlmsg_alloc(); if (!msg) return -1; wpa_printf(MSG_DEBUG, "capwap: Authenticate (ifindex=%d)", drv->ifindex); capwap_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE); for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; wpa_driver_capwap_set_key(bss->ifname, priv, WPA_ALG_WEP, NULL, i, i == params->wep_tx_keyidx, NULL, 0, params->wep_key[i], params->wep_key_len[i]); if (params->wep_tx_keyidx != i) continue; if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, params->wep_key[i], params->wep_key_len[i])) { nlmsg_free(msg); return -1; } } NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); } if (params->ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", params->ssid, params->ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid); } wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len); if (params->ie) NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie); if (params->auth_alg & WPA_AUTH_ALG_OPEN) type = NL80211_AUTHTYPE_OPEN_SYSTEM; else if (params->auth_alg & WPA_AUTH_ALG_SHARED) type = NL80211_AUTHTYPE_SHARED_KEY; else if (params->auth_alg & WPA_AUTH_ALG_LEAP) type = NL80211_AUTHTYPE_NETWORK_EAP; else if (params->auth_alg & WPA_AUTH_ALG_FT) type = NL80211_AUTHTYPE_FT; else goto nla_put_failure; wpa_printf(MSG_DEBUG, " * Auth Type %d", type); NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); if (params->local_state_change) { wpa_printf(MSG_DEBUG, " * Local state change only"); NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); count++; if (ret == -EALREADY && count == 1 && params->bssid && !params->local_state_change) { /* * mac80211 does not currently accept new * authentication if we are already authenticated. As a * workaround, force deauthentication and try again. */ wpa_printf(MSG_DEBUG, "capwap: Retry authentication " "after forced deauthentication"); wpa_driver_capwap_deauthenticate( bss, params->bssid, WLAN_REASON_PREV_AUTH_NOT_VALID); nlmsg_free(msg); goto retry; } goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Authentication request send " "successfully"); nla_put_failure: nlmsg_free(msg); return ret; } struct phy_info_arg { u16 *num_modes; struct hostapd_hw_modes *modes; }; static int phy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct phy_info_arg *phy_info = arg; struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, }; struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, }; struct nlattr *nl_band; struct nlattr *nl_freq; struct nlattr *nl_rate; int rem_band, rem_freq, rem_rate; struct hostapd_hw_modes *mode; int idx, mode_is_set; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) return NL_SKIP; nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); if (!mode) return NL_SKIP; phy_info->modes = mode; mode_is_set = 0; mode = &phy_info->modes[*(phy_info->num_modes)]; memset(mode, 0, sizeof(*mode)); mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN; *(phy_info->num_modes) += 1; nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { mode->ht_capab = nla_get_u16( tb_band[NL80211_BAND_ATTR_HT_CAPA]); } if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { mode->a_mpdu_params |= nla_get_u8( tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) & 0x03; } if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { mode->a_mpdu_params |= nla_get_u8( tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) << 2; } if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) { u8 *mcs; mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); os_memcpy(mode->mcs_set, mcs, 16); } nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; mode->num_channels++; } mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data)); if (!mode->channels) return NL_SKIP; idx = 0; nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); mode->channels[idx].flag = 0; if (!mode_is_set) { /* crude heuristic */ if (mode->channels[idx].freq < 4000) mode->mode = HOSTAPD_MODE_IEEE80211B; else mode->mode = HOSTAPD_MODE_IEEE80211A; mode_is_set = 1; } /* crude heuristic */ if (mode->channels[idx].freq < 4000) if (mode->channels[idx].freq == 2484) mode->channels[idx].chan = 14; else mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; else mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) mode->channels[idx].flag |= HOSTAPD_CHAN_DISABLED; if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) mode->channels[idx].flag |= HOSTAPD_CHAN_PASSIVE_SCAN; if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) mode->channels[idx].flag |= HOSTAPD_CHAN_NO_IBSS; if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) mode->channels[idx].flag |= HOSTAPD_CHAN_RADAR; if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) mode->channels[idx].max_tx_power = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100; idx++; } nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; mode->num_rates++; } mode->rates = os_zalloc(mode->num_rates * sizeof(int)); if (!mode->rates) return NL_SKIP; idx = 0; nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); /* crude heuristic */ if (mode->mode == HOSTAPD_MODE_IEEE80211B && mode->rates[idx] > 200) mode->mode = HOSTAPD_MODE_IEEE80211G; idx++; } } return NL_SKIP; } static struct hostapd_hw_modes * wpa_driver_capwap_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes) { u16 m; struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; int i, mode11g_idx = -1; int j; /* If only 802.11g mode is included, use it to construct matching * 802.11b mode data. */ for (m = 0; m < *num_modes; m++) { wpa_printf(MSG_DEBUG,"*** 2.2 %d\n",m); if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) return modes; /* 802.11b already included */ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) mode11g_idx = m; } if (mode11g_idx < 0) return modes; /* 2.4 GHz band not supported at all */ nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes)); if (nmodes == NULL) return modes; /* Could not add 802.11b mode */ mode = &nmodes[*num_modes]; os_memset(mode, 0, sizeof(*mode)); (*num_modes)++; modes = nmodes; mode->mode = HOSTAPD_MODE_IEEE80211B; mode11g = &modes[mode11g_idx]; mode->num_channels = mode11g->num_channels; mode->channels = os_malloc(mode11g->num_channels * sizeof(struct hostapd_channel_data)); if (mode->channels == NULL) { (*num_modes)--; return modes; /* Could not add 802.11b mode */ } os_memcpy(mode->channels, mode11g->channels, mode11g->num_channels * sizeof(struct hostapd_channel_data)); mode->num_rates = 0; mode->rates = os_malloc(4 * sizeof(int)); if (mode->rates == NULL) { os_free(mode->channels); (*num_modes)--; return modes; /* Could not add 802.11b mode */ } for (i = 0; i < mode11g->num_rates; i++) { if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && mode11g->rates[i] != 55 && mode11g->rates[i] != 110) continue; mode->rates[mode->num_rates] = mode11g->rates[i]; mode->num_rates++; if (mode->num_rates == 4) break; } if (mode->num_rates == 0) { os_free(mode->channels); os_free(mode->rates); (*num_modes)--; return modes; /* No 802.11b rates */ } wpa_printf(MSG_DEBUG, "capwap: Added 802.11b mode based on 802.11g information"); wpa_printf(MSG_DEBUG,"*** Num_channels:%d Num_rates:%d capab:%d flags:%d MODE:%d mpdu:%02X",modes->num_channels,modes->num_rates,modes->ht_capab,modes->flags,modes->mode,modes->a_mpdu_params); for(j=0;j < 16;j++){ wpa_printf(MSG_DEBUG,"%02X ",modes->mcs_set[j]); } for(j=0;j < modes->num_channels;j++){ wpa_printf(MSG_DEBUG,"*** %d freq:%d flag:%d chan:%d freq:%d maxPower:%02X ",j,modes->channels[j].freq,modes->channels[j].flag,modes->channels[j].chan,modes->channels[j].freq,modes->channels[j].max_tx_power); } for(j=0;j < modes->num_rates;j++){ wpa_printf(MSG_DEBUG,"*** %d rate:%d ",j,modes->rates[j]); } return modes; } static void capwap_set_ht40_mode(struct hostapd_hw_modes *mode, int start, int end) { int c; for (c = 0; c < mode->num_channels; c++) { struct hostapd_channel_data *chan = &mode->channels[c]; if (chan->freq - 10 >= start && chan->freq + 10 <= end) chan->flag |= HOSTAPD_CHAN_HT40; } } static void capwap_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, int end) { int c; for (c = 0; c < mode->num_channels; c++) { struct hostapd_channel_data *chan = &mode->channels[c]; if (!(chan->flag & HOSTAPD_CHAN_HT40)) continue; if (chan->freq - 30 >= start && chan->freq - 10 <= end) chan->flag |= HOSTAPD_CHAN_HT40MINUS; if (chan->freq + 10 >= start && chan->freq + 30 <= end) chan->flag |= HOSTAPD_CHAN_HT40PLUS; } } static void capwap_reg_rule_ht40(struct nlattr *tb[], struct phy_info_arg *results) { u32 start, end, max_bw; u16 m; if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) return; start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; wpa_printf(MSG_DEBUG, "capwap: %u-%u @ %u MHz", start, end, max_bw); if (max_bw < 40) return; for (m = 0; m < *results->num_modes; m++) { if (!(results->modes[m].ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) continue; capwap_set_ht40_mode(&results->modes[m], start, end); } } static void capwap_reg_rule_sec(struct nlattr *tb[], struct phy_info_arg *results) { u32 start, end, max_bw; u16 m; if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) return; start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; if (max_bw < 20) return; for (m = 0; m < *results->num_modes; m++) { if (!(results->modes[m].ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) continue; capwap_set_ht40_mode_sec(&results->modes[m], start, end); } } static int capwap_get_reg(struct nl_msg *msg, void *arg) { struct phy_info_arg *results = arg; struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *nl_rule; struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1]; int rem_rule; static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, }; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb_msg[NL80211_ATTR_REG_ALPHA2] || !tb_msg[NL80211_ATTR_REG_RULES]) { wpa_printf(MSG_DEBUG, "capwap: No regulatory information " "available"); return NL_SKIP; } wpa_printf(MSG_DEBUG, "capwap: Regulatory information - country=%s", (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2])); nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) { nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_rule), nla_len(nl_rule), reg_policy); capwap_reg_rule_ht40(tb_rule, results); } nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) { nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_rule), nla_len(nl_rule), reg_policy); capwap_reg_rule_sec(tb_rule, results); } return NL_SKIP; } static int capwap_set_ht40_flags(struct wpa_driver_capwap_data *drv, struct phy_info_arg *results) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_REG); return send_and_recv_msgs(drv, msg, capwap_get_reg, results); } static struct hostapd_hw_modes * AC_wpa_driver_capwap_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) { int rate_arrays[8]; int num_rates; /* int num_modes1; */ int i; num_rates = capability_get_rates(rate_arrays); /* capwap FIXME: needed? num_modes1 = capability_get_num_modes(); */ struct hostapd_hw_modes *mode; int clen, rlen; const short chan2freq[14] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; mode = os_zalloc(sizeof(struct hostapd_hw_modes)); if (mode == NULL) return NULL; *num_modes = 1; *flags = 0; if(capability_is_B()){ mode->mode = HOSTAPD_MODE_IEEE80211B; }else{ wpa_printf(MSG_ERROR, "ERROR AC_wpa_driver_capwap_get_hw_feature_data\n"); exit(1); } mode->num_channels = capability_get_num_channels(); mode->num_rates = num_rates ; clen = mode->num_channels * sizeof(struct hostapd_channel_data); rlen = mode->num_rates * sizeof(int); mode->channels = os_zalloc(clen); mode->rates = os_zalloc(rlen); if (mode->channels == NULL || mode->rates == NULL) { os_free(mode->channels); os_free(mode->rates); os_free(mode); return NULL; } for (i = 0; i < mode->num_channels; i++) { mode->channels[i].chan = i + 1; mode->channels[i].freq = chan2freq[i]; /* TODO: Get allowed channel list from the driver */ if (i >= 11) mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; } for( i=0; inum_rates ; i++){ if( rate_arrays[i] < 0 ) mode->rates[i] = -1 * rate_arrays[i]; else mode->rates[i] = rate_arrays[i]; } return mode; } static struct hostapd_hw_modes * wpa_driver_capwap_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_get_hw_feature_data "); return AC_wpa_driver_capwap_get_hw_feature_data(priv,num_modes,flags); } static int wpa_driver_capwap_send_frame(struct wpa_driver_capwap_data *drv, const void *data, size_t len, int encrypt) { wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_send_frame "); unsigned char buf[3000]; __u8 rtap_hdr[] = { 0x00, 0x00, /* radiotap version */ 0x0e, 0x00, /* radiotap length */ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ 0x00, /* padding */ 0x00, 0x00, /* RX and TX flags to indicate that */ 0x00, 0x00, /* this is the injected frame directly */ }; struct iovec iov[2] = { { .iov_base = &rtap_hdr, .iov_len = sizeof(rtap_hdr), }, { .iov_base = (void *) data, .iov_len = len, } }; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, .msg_iov = iov, .msg_iovlen = 2, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0, }; int res; if (encrypt) rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; memcpy(buf,(u8 *)(data),len); //AC_handle_send_data_to_WTP(buf, len, generic_ac_info.own_mac_addr); //Switch_Mac_Address_AC_to_WTP(buf, generic_ac_info.own_mac_addr); ipc_send_80211_to_wtp(generic_ac_info.fd_ipc, buf, len); return 0; res = sendmsg(drv->monitor_sock, &msg, 0); if (res < 0) { wpa_printf(MSG_INFO, "capwap: sendmsg: %s", strerror(errno)); return -1; } return 0; } static int wpa_driver_capwap_send_mlme(void *priv, const u8 *data, size_t data_len) { //wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_send_mlme "); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct ieee80211_mgmt *mgmt; int encrypt = 1; u16 fc; mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); if (is_sta_interface(drv->nlmode) && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { /* * The use of last_mgmt_freq is a bit of a hack, * but it works due to the single-threaded nature * of wpa_supplicant. */ return capwap_send_frame_cmd(drv, drv->last_mgmt_freq, 0, data, data_len, NULL, 1); } if (drv->no_monitor_iface_capab && is_ap_interface(drv->nlmode)) { return capwap_send_frame_cmd(drv, drv->ap_oper_freq, 0, data, data_len, &drv->send_action_cookie, 0); } if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { /* * Only one of the authentication frame types is encrypted. * In order for static WEP encryption to work properly (i.e., * to not encrypt the frame), we need to tell mac80211 about * the frames that must not be encrypted. */ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) encrypt = 0; } return wpa_driver_capwap_send_frame(drv, data, data_len, encrypt); } static int capwap_set_ap_isolate(struct i802_bss *bss, int enabled) { struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, enabled); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: return -ENOBUFS; } static int capwap_set_bss(struct i802_bss *bss, int cts, int preamble, int slot, int ht_opmode) { struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); if (cts >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); if (preamble >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); if (slot >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); if (ht_opmode >= 0) NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int wpa_driver_capwap_set_ap(void *priv, struct wpa_driver_ap_params *params) { wpa_printf(MSG_DEBUG, "> wpa_driver_capwap_set_ap \n"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; u8 cmd = NL80211_CMD_NEW_BEACON; int ret; int beacon_set; int ifindex = if_nametoindex(bss->ifname); int num_suites; u32 suites[10]; u32 ver; beacon_set = bss->beacon_set; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; wpa_printf(MSG_DEBUG, "capwap: Set beacon (beacon_set=%d)", beacon_set); if (beacon_set) cmd = NL80211_CMD_SET_BEACON; capwap_cmd(drv, msg, 0, cmd); NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head); NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int); NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period); NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid); switch (params->hide_ssid) { case NO_SSID_HIDING: NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, NL80211_HIDDEN_SSID_NOT_IN_USE); break; case HIDDEN_SSID_ZERO_LEN: NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, NL80211_HIDDEN_SSID_ZERO_LEN); break; case HIDDEN_SSID_ZERO_CONTENTS: NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, NL80211_HIDDEN_SSID_ZERO_CONTENTS); break; } if (params->privacy) NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { /* Leave out the attribute */ } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_SHARED_KEY); else NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_OPEN_SYSTEM); ver = 0; if (params->wpa_version & WPA_PROTO_WPA) ver |= NL80211_WPA_VERSION_1; if (params->wpa_version & WPA_PROTO_RSN) ver |= NL80211_WPA_VERSION_2; if (ver) NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); num_suites = 0; if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X) suites[num_suites++] = WLAN_AKM_SUITE_8021X; if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK) suites[num_suites++] = WLAN_AKM_SUITE_PSK; if (num_suites) { NLA_PUT(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), suites); } num_suites = 0; if (params->pairwise_ciphers & WPA_CIPHER_CCMP) suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; if (params->pairwise_ciphers & WPA_CIPHER_TKIP) suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; if (params->pairwise_ciphers & WPA_CIPHER_WEP104) suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; if (params->pairwise_ciphers & WPA_CIPHER_WEP40) suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; if (num_suites) { NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, num_suites * sizeof(u32), suites); } switch (params->group_cipher) { case WPA_CIPHER_CCMP: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_CCMP); break; case WPA_CIPHER_TKIP: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_TKIP); break; case WPA_CIPHER_WEP104: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_WEP104); break; case WPA_CIPHER_WEP40: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_WEP40); break; } if (params->beacon_ies) { NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies), wpabuf_head(params->beacon_ies)); } if (params->proberesp_ies) { NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP, wpabuf_len(params->proberesp_ies), wpabuf_head(params->proberesp_ies)); } if (params->assocresp_ies) { NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP, wpabuf_len(params->assocresp_ies), wpabuf_head(params->assocresp_ies)); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "capwap: Beacon set failed: %d (%s)", ret, strerror(-ret)); } else { bss->beacon_set = 1; ret = capwap_set_ap_isolate(bss, params->isolate); if (!params->isolate && ret) { wpa_printf(MSG_DEBUG, "capwap: Ignore AP isolation " "configuration error since isolation is " "not used"); ret = 0; } capwap_set_bss(bss, params->cts_protect, params->preamble, params->short_slot_time, params->ht_opmode); } wpa_printf(MSG_DEBUG, "=== (P) privacy: %d\n",params->privacy); wpa_printf(MSG_DEBUG, "=== (T) short_slot_time: %d\n",params->short_slot_time); wpa_printf(MSG_DEBUG, "=== (S) preamble: %d\n",params->preamble); prep_beacon(generic_ac_info.fd_ipc,drv->ctx,params); //ipc_send_ADD_WLAN(generic_ac_info.fd_ipc, params->ssid, params->ssid_len); return ret; nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int wpa_driver_capwap_set_freq(struct wpa_driver_capwap_data *drv, int freq, int ht_enabled, int sec_channel_offset) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_set_freq"); return 0; } static u32 sta_flags_capwap(int flags) { u32 f = 0; if (flags & WPA_STA_AUTHORIZED) f |= BIT(NL80211_STA_FLAG_AUTHORIZED); if (flags & WPA_STA_WMM) f |= BIT(NL80211_STA_FLAG_WME); if (flags & WPA_STA_SHORT_PREAMBLE) f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); if (flags & WPA_STA_MFP) f |= BIT(NL80211_STA_FLAG_MFP); if (flags & WPA_STA_TDLS_PEER) f |= BIT(NL80211_STA_FLAG_TDLS_PEER); return f; } static int wpa_driver_capwap_sta_add(void *priv, struct hostapd_sta_add_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct nl80211_sta_flag_update upd; int ret = -ENOBUFS; if ((params->flags & WPA_STA_TDLS_PEER) && !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION : NL80211_CMD_NEW_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, params->supp_rates); if (!params->set) { NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, params->listen_interval); } if (params->ht_capabilities) { NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sizeof(*params->ht_capabilities), params->ht_capabilities); } os_memset(&upd, 0, sizeof(upd)); upd.mask = sta_flags_capwap(params->flags); upd.set = upd.mask; NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) wpa_printf(MSG_DEBUG, "capwap: NL80211_CMD_%s_STATION " "result: %d (%s)", params->set ? "SET" : "NEW", ret, strerror(-ret)); if (ret == -EEXIST) ret = 0; nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_sta_remove(void *priv, const u8 *addr) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret == -ENOENT) return 0; return ret; nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static void capwap_remove_iface(struct wpa_driver_capwap_data *drv, int ifidx) { struct nl_msg *msg; wpa_printf(MSG_DEBUG, "capwap: Remove interface ifindex=%d", ifidx); /* stop listening for EAPOL on this interface */ del_ifidx(drv, ifidx); msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return; msg = NULL; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); } static const char * nl80211_iftype_str(enum nl80211_iftype mode) { switch (mode) { case NL80211_IFTYPE_ADHOC: return "ADHOC"; case NL80211_IFTYPE_STATION: return "STATION"; case NL80211_IFTYPE_AP: return "AP"; case NL80211_IFTYPE_MONITOR: return "MONITOR"; case NL80211_IFTYPE_P2P_CLIENT: return "P2P_CLIENT"; case NL80211_IFTYPE_P2P_GO: return "P2P_GO"; default: return "unknown"; } } static int capwap_create_iface_once(struct wpa_driver_capwap_data *drv, const char *ifname, enum nl80211_iftype iftype, const u8 *addr, int wds) { wpa_printf(MSG_DEBUG, "# capwap_create_iface_once\n"); struct nl_msg *msg, *flags = NULL; int ifidx; int ret = -ENOBUFS; wpa_printf(MSG_DEBUG, "capwap: Create interface iftype %d (%s)", iftype, nl80211_iftype_str(iftype)); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); if (iftype == NL80211_IFTYPE_MONITOR) { int err; flags = nlmsg_alloc(); if (!flags) goto nla_put_failure; NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); nlmsg_free(flags); if (err) goto nla_put_failure; } else if (wds) { NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", ifname, ret, strerror(-ret)); return ret; } ifidx = if_nametoindex(ifname); wpa_printf(MSG_DEBUG, "capwap: New interface %s created: ifindex=%d", ifname, ifidx); /* start listening for EAPOL on this interface */ wpa_printf(MSG_DEBUG, "start listening for EAPOL on this interface\n"); add_ifidx(drv, ifidx); if (addr && iftype != NL80211_IFTYPE_MONITOR && linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) { capwap_remove_iface(drv, ifidx); return -1; } wpa_printf(MSG_DEBUG, "#9 %d\n",ifidx); return ifidx; } static int capwap_create_iface(struct wpa_driver_capwap_data *drv, const char *ifname, enum nl80211_iftype iftype, const u8 *addr, int wds) { int ret; ret = capwap_create_iface_once(drv, ifname, iftype, addr, wds); /* if error occurred and interface exists already */ if (ret == -ENFILE && if_nametoindex(ifname)) { wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); /* Try to remove the interface that was already there. */ capwap_remove_iface(drv, if_nametoindex(ifname)); /* Try to create the interface again */ ret = capwap_create_iface_once(drv, ifname, iftype, addr, wds); } if (ret >= 0 && is_p2p_interface(iftype)) capwap_disable_11b_rates(drv, ret, 1); return ret; } static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) { struct ieee80211_hdr *hdr; u16 fc; union wpa_event_data event; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.tx_status.type = WLAN_FC_GET_TYPE(fc); event.tx_status.stype = WLAN_FC_GET_STYPE(fc); event.tx_status.dst = hdr->addr1; event.tx_status.data = buf; event.tx_status.data_len = len; event.tx_status.ack = ok; wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); } static void from_unknown_sta(struct wpa_driver_capwap_data *drv, u8 *buf, size_t len) { struct ieee80211_hdr *hdr = (void *)buf; u16 fc; union wpa_event_data event; if (len < sizeof(*hdr)) return; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); event.rx_from_unknown.addr = hdr->addr2; event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) == (WLAN_FC_FROMDS | WLAN_FC_TODS); wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); } static void handle_frame(struct wpa_driver_capwap_data *drv, u8 *buf, size_t len, int datarate, int ssi_signal) { struct ieee80211_hdr *hdr; u16 fc; union wpa_event_data event; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); switch (WLAN_FC_GET_TYPE(fc)) { case WLAN_FC_TYPE_MGMT: os_memset(&event, 0, sizeof(event)); event.rx_mgmt.frame = buf; event.rx_mgmt.frame_len = len; event.rx_mgmt.datarate = datarate; event.rx_mgmt.ssi_signal = ssi_signal; wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); break; case WLAN_FC_TYPE_CTRL: /* can only get here with PS-Poll frames */ wpa_printf(MSG_DEBUG, "CTRL"); from_unknown_sta(drv, buf, len); break; case WLAN_FC_TYPE_DATA: from_unknown_sta(drv, buf, len); break; } } static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx){ struct wpa_driver_capwap_data *drv = eloop_ctx; int len; unsigned char buf[3000]; struct ieee80211_radiotap_iterator iter; int ret; int datarate = 0, ssi_signal = 0; int injected = 0, failed = 0, rxflags = 0; len = recv(sock, buf, sizeof(buf), 0); if (len < 0) { perror("recv"); return; } if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { wpa_printf(MSG_DEBUG, "received invalid radiotap frame\n"); return; } while (1) { ret = ieee80211_radiotap_iterator_next(&iter); if (ret == -ENOENT) break; if (ret) { wpa_printf(MSG_DEBUG, "received invalid radiotap frame (%d)\n", ret); return; } switch (iter.this_arg_index) { case IEEE80211_RADIOTAP_FLAGS: if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) len -= 4; break; case IEEE80211_RADIOTAP_RX_FLAGS: rxflags = 1; break; case IEEE80211_RADIOTAP_TX_FLAGS: injected = 1; failed = le_to_host16((*(uint16_t *) iter.this_arg)) & IEEE80211_RADIOTAP_F_TX_FAIL; break; case IEEE80211_RADIOTAP_DATA_RETRIES: break; case IEEE80211_RADIOTAP_CHANNEL: /* TODO: convert from freq/flags to channel number */ break; case IEEE80211_RADIOTAP_RATE: datarate = *iter.this_arg * 5; break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: ssi_signal = *iter.this_arg; break; } } if (rxflags && injected) return; if (!injected) handle_frame(drv, buf + iter.max_length, len - iter.max_length, datarate, ssi_signal); else handle_tx_callback(drv->ctx, buf + iter.max_length, len - iter.max_length, !failed); } /* * we post-process the filter code later and rewrite * this to the offset to the last instruction */ #define PASS 0xFF #define FAIL 0xFE static struct sock_filter msock_filter_insns[] = { /* * do a little-endian load of the radiotap length field */ /* load lower byte into A */ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), /* put it into X (== index register) */ BPF_STMT(BPF_MISC| BPF_TAX, 0), /* load upper byte into A */ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), /* left-shift it by 8 */ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), /* or with X */ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), /* put result into X */ BPF_STMT(BPF_MISC| BPF_TAX, 0), /* * Allow management frames through, this also gives us those * management frames that we sent ourselves with status */ /* load the lower byte of the IEEE 802.11 frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* mask off frame type and version */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), /* accept frame if it's both 0, fall through otherwise */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), /* * TODO: add a bit to radiotap RX flags that indicates * that the sending station is not associated, then * add a filter here that filters on our DA and that flag * to allow us to deauth frames to that bad station. * * For now allow all To DS data frames through. */ /* load the IEEE 802.11 frame control field */ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0), /* mask off frame type, version and DS status */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03), /* accept frame if version 0, type 2 and To DS, fall through otherwise */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0), #if 0 /* * drop non-data frames */ /* load the lower byte of the frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* mask off QoS bit */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), /* drop non-data frames */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), #endif /* load the upper byte of the frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), /* mask off toDS/fromDS */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), /* accept WDS frames */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), /* * add header length to index */ /* load the lower byte of the frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* mask off QoS bit */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), /* right shift it by 6 to give 0 or 2 */ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), /* add data frame header length */ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), /* add index, was start of 802.11 header */ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), /* move to index, now start of LL header */ BPF_STMT(BPF_MISC | BPF_TAX, 0), /* * Accept empty data frames, we use those for * polling activity. */ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), /* * Accept EAPOL frames */ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), /* keep these last two statements or change the code below */ /* return 0 == "DROP" */ BPF_STMT(BPF_RET | BPF_K, 0), /* return ~0 == "keep all" */ BPF_STMT(BPF_RET | BPF_K, ~0), }; static struct sock_fprog msock_filter = { .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]), .filter = msock_filter_insns, }; static int add_monitor_filter(int s) { int idx; /* rewrite all PASS/FAIL jump offsets */ for (idx = 0; idx < msock_filter.len; idx++) { struct sock_filter *insn = &msock_filter_insns[idx]; if (BPF_CLASS(insn->code) == BPF_JMP) { if (insn->code == (BPF_JMP|BPF_JA)) { if (insn->k == PASS) insn->k = msock_filter.len - idx - 2; else if (insn->k == FAIL) insn->k = msock_filter.len - idx - 3; } if (insn->jt == PASS) insn->jt = msock_filter.len - idx - 2; else if (insn->jt == FAIL) insn->jt = msock_filter.len - idx - 3; if (insn->jf == PASS) insn->jf = msock_filter.len - idx - 2; else if (insn->jf == FAIL) insn->jf = msock_filter.len - idx - 3; } } if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &msock_filter, sizeof(msock_filter))) { perror("SO_ATTACH_FILTER"); return -1; } return 0; } static void capwap_remove_monitor_interface( struct wpa_driver_capwap_data *drv) { return ; } static int capwap_create_monitor_interface(struct wpa_driver_capwap_data *drv){ wpa_printf(MSG_DEBUG, "# 8.5 capwap_create_monitor_interface\n"); //if(!real)return 0; char buf[IFNAMSIZ]; struct sockaddr_ll ll; int optval; socklen_t optlen; if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) { /* * P2P interface name is of the format p2p-%s-%d. For monitor * interface name corresponding to P2P GO, replace "p2p-" with * "mon-" to retain the same interface name length and to * indicate that it is a monitor interface. */ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4); } else { /* Non-P2P interface with AP functionality. */ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); } buf[IFNAMSIZ - 1] = '\0'; drv->monitor_ifidx = capwap_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, 0); if (drv->monitor_ifidx == -EOPNOTSUPP) { wpa_printf(MSG_DEBUG, "capwap: Driver does not support " "monitor interface type - try to run without it"); drv->no_monitor_iface_capab = 1; } if (drv->monitor_ifidx < 0) return -1; if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1)) goto error; memset(&ll, 0, sizeof(ll)); ll.sll_family = AF_PACKET; ll.sll_ifindex = drv->monitor_ifidx; drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (drv->monitor_sock < 0) { perror("socket[PF_PACKET,SOCK_RAW]"); goto error; } if (add_monitor_filter(drv->monitor_sock)) { wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " "interface; do filtering in user space"); /* This works, but will cost in performance. */ } if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { perror("monitor socket bind"); goto error; } optlen = sizeof(optval); optval = 20; if (setsockopt (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { perror("Failed to set socket priority"); goto error; } return 0; error: capwap_remove_monitor_interface(drv); return -1; } #ifdef CONFIG_AP static int capwap_send_eapol_data(struct i802_bss *bss, const u8 *addr, const u8 *data, size_t data_len, const u8 *own_addr) { wpa_printf(MSG_DEBUG, "-------------capwap_send_eapol_data\n"); if (bss->drv->l2 == NULL) { wpa_printf(MSG_DEBUG, "capwap: No l2_packet to send EAPOL"); return -1; } if (l2_packet_send(bss->drv->l2, addr, ETH_P_EAPOL, data, data_len) < 0) return -1; return 0; } #endif /* CONFIG_AP */ static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; static int wpa_driver_capwap_hapd_send_eapol( void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, const u8 *own_addr, u32 flags) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct ieee80211_hdr *hdr; size_t len; u8 *pos; int res; int qos = flags & WPA_STA_WMM; wpa_printf(MSG_DEBUG, "-------------- wpa_driver_capwap_hapd_send_eapol %d \n",bss->ifindex); #ifdef CONFIG_AP if (drv->no_monitor_iface_capab) return capwap_send_eapol_data(bss, addr, data, data_len, own_addr); #endif /* CONFIG_AP */ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + data_len; hdr = os_zalloc(len); if (hdr == NULL) { wpa_printf(MSG_ERROR,"malloc() failed for i802_send_data(len=%lu)\n", (unsigned long) len); return -1; } hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); if (encrypt) hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); if (qos) { hdr->frame_control |= host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); } memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); pos = (u8 *) (hdr + 1); if (qos) { /* add an empty QoS header if needed */ pos[0] = 0; pos[1] = 0; pos += 2; } memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); pos += sizeof(rfc1042_header); WPA_PUT_BE16(pos, ETH_P_PAE); pos += 2; memcpy(pos, data, data_len); wpa_printf(MSG_DEBUG, "EAPOL Data Frame 1 (%zd)\n",len); res = wpa_driver_capwap_send_frame(drv, (u8 *) hdr, len, encrypt); if (res < 0) { wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " "failed: %d (%s)", (unsigned long) len, errno, strerror(errno)); } os_free(hdr); return res; } static int wpa_driver_capwap_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, int flags_and) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg, *flags = NULL; struct nl80211_sta_flag_update upd; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; flags = nlmsg_alloc(); if (!flags) { nlmsg_free(msg); return -ENOMEM; } capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); /* * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This * can be removed eventually. */ if (total_flags & WPA_STA_AUTHORIZED) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); if (total_flags & WPA_STA_WMM) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); if (total_flags & WPA_STA_SHORT_PREAMBLE) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); if (total_flags & WPA_STA_MFP) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); if (total_flags & WPA_STA_TDLS_PEER) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER); if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) goto nla_put_failure; os_memset(&upd, 0, sizeof(upd)); upd.mask = sta_flags_capwap(flags_or | ~flags_and); upd.set = sta_flags_capwap(flags_or); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); nlmsg_free(flags); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); nlmsg_free(flags); return -ENOBUFS; } static int wpa_driver_capwap_ap(struct wpa_driver_capwap_data *drv, struct wpa_driver_associate_params *params) { enum nl80211_iftype nlmode; if (params->p2p) { wpa_printf(MSG_DEBUG, "capwap: Setup AP operations for P2P " "group (GO)"); nlmode = NL80211_IFTYPE_P2P_GO; } else nlmode = NL80211_IFTYPE_AP; if (wpa_driver_capwap_set_mode(&drv->first_bss, nlmode) || wpa_driver_capwap_set_freq(drv, params->freq, 0, 0)) { capwap_remove_monitor_interface(drv); return -1; } if (drv->no_monitor_iface_capab) { if (wpa_driver_capwap_probe_req_report(&drv->first_bss, 1) < 0) { wpa_printf(MSG_DEBUG, "capwap: Failed to enable " "Probe Request frame reporting in AP mode"); /* Try to survive without this */ } } drv->ap_oper_freq = params->freq; return 0; } static int capwap_leave_ibss(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; int ret = -1; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Leave IBSS failed: ret=%d " "(%s)", ret, strerror(-ret)); goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Leave IBSS request sent successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_ibss(struct wpa_driver_capwap_data *drv, struct wpa_driver_associate_params *params) { struct nl_msg *msg; int ret = -1; int count = 0; wpa_printf(MSG_DEBUG, "capwap: Join IBSS (ifindex=%d)", drv->ifindex); if (wpa_driver_capwap_set_mode(&drv->first_bss, NL80211_IFTYPE_ADHOC)) { wpa_printf(MSG_INFO, "capwap: Failed to set interface into " "IBSS mode"); return -1; } retry: msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid)) goto nla_put_failure; wpa_hexdump_ascii(MSG_DEBUG, " * SSID", params->ssid, params->ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid); os_memcpy(drv->ssid, params->ssid, params->ssid_len); drv->ssid_len = params->ssid_len; wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); ret = capwap_set_conn_keys(params, msg); if (ret) goto nla_put_failure; if (params->wpa_ie) { wpa_hexdump(MSG_DEBUG, " * Extra IEs for Beacon/Probe Response frames", params->wpa_ie, params->wpa_ie_len); NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Join IBSS failed: ret=%d (%s)", ret, strerror(-ret)); count++; if (ret == -EALREADY && count == 1) { wpa_printf(MSG_DEBUG, "capwap: Retry IBSS join after " "forced leave"); capwap_leave_ibss(drv); nlmsg_free(msg); goto retry; } goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Join IBSS request sent successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static unsigned int capwap_get_assoc_bssid(struct wpa_driver_capwap_data *drv, u8 *bssid) { struct nl_msg *msg; int ret; struct capwap_bss_info_arg arg; os_memset(&arg, 0, sizeof(arg)); msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { if (is_zero_ether_addr(arg.assoc_bssid)) return -ENOTCONN; os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN); return 0; } wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return drv->assoc_freq; } static int capwap_disconnect(struct wpa_driver_capwap_data *drv, const u8 *bssid) { u8 addr[ETH_ALEN]; if (bssid == NULL) { int res = capwap_get_assoc_bssid(drv, addr); if (res) return res; bssid = addr; } return wpa_driver_capwap_disconnect(drv, bssid, WLAN_REASON_PREV_AUTH_NOT_VALID); } static int wpa_driver_capwap_connect( struct wpa_driver_capwap_data *drv, struct wpa_driver_associate_params *params) { struct nl_msg *msg; enum nl80211_auth_type type; int ret = 0; int algs; msg = nlmsg_alloc(); if (!msg) return -1; wpa_printf(MSG_DEBUG, "capwap: Connect (ifindex=%d)", drv->ifindex); capwap_cmd(drv, msg, 0, NL80211_CMD_CONNECT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); } if (params->ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", params->ssid, params->ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid); if (params->ssid_len > sizeof(drv->ssid)) goto nla_put_failure; os_memcpy(drv->ssid, params->ssid, params->ssid_len); drv->ssid_len = params->ssid_len; } wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); if (params->wpa_ie) NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); algs = 0; if (params->auth_alg & WPA_AUTH_ALG_OPEN) algs++; if (params->auth_alg & WPA_AUTH_ALG_SHARED) algs++; if (params->auth_alg & WPA_AUTH_ALG_LEAP) algs++; if (algs > 1) { wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " "selection"); goto skip_auth_type; } if (params->auth_alg & WPA_AUTH_ALG_OPEN) type = NL80211_AUTHTYPE_OPEN_SYSTEM; else if (params->auth_alg & WPA_AUTH_ALG_SHARED) type = NL80211_AUTHTYPE_SHARED_KEY; else if (params->auth_alg & WPA_AUTH_ALG_LEAP) type = NL80211_AUTHTYPE_NETWORK_EAP; else if (params->auth_alg & WPA_AUTH_ALG_FT) type = NL80211_AUTHTYPE_FT; else goto nla_put_failure; wpa_printf(MSG_DEBUG, " * Auth Type %d", type); NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); skip_auth_type: if (params->wpa_proto) { enum nl80211_wpa_versions ver = 0; if (params->wpa_proto & WPA_PROTO_WPA) ver |= NL80211_WPA_VERSION_1; if (params->wpa_proto & WPA_PROTO_RSN) ver |= NL80211_WPA_VERSION_2; wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver); NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); } if (params->pairwise_suite != CIPHER_NONE) { int cipher; switch (params->pairwise_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); } if (params->group_suite != CIPHER_NONE) { int cipher; switch (params->group_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); } if (params->key_mgmt_suite == KEY_MGMT_802_1X || params->key_mgmt_suite == KEY_MGMT_PSK) { int mgmt = WLAN_AKM_SUITE_PSK; switch (params->key_mgmt_suite) { case KEY_MGMT_802_1X: mgmt = WLAN_AKM_SUITE_8021X; break; case KEY_MGMT_PSK: default: mgmt = WLAN_AKM_SUITE_PSK; break; } NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); } ret = capwap_set_conn_keys(params, msg); if (ret) goto nla_put_failure; ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME connect failed: ret=%d " "(%s)", ret, strerror(-ret)); /* * cfg80211 does not currently accept new connection if we are * already connected. As a workaround, force disconnection and * try again once the driver indicates it completed * disconnection. */ if (ret == -EALREADY) capwap_disconnect(drv, params->bssid); goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Connect request send successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_associate( void *priv, struct wpa_driver_associate_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1; struct nl_msg *msg; if (params->mode == IEEE80211_MODE_AP) return wpa_driver_capwap_ap(drv, params); if (params->mode == IEEE80211_MODE_IBSS) return wpa_driver_capwap_ibss(drv, params); if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { enum nl80211_iftype nlmode = params->p2p ? NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; if (wpa_driver_capwap_set_mode(priv, nlmode) < 0) return -1; return wpa_driver_capwap_connect(drv, params); } drv->associated = 0; msg = nlmsg_alloc(); if (!msg) return -1; wpa_printf(MSG_DEBUG, "capwap: Associate (ifindex=%d)", drv->ifindex); capwap_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); drv->assoc_freq = params->freq; } else drv->assoc_freq = 0; if (params->ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", params->ssid, params->ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid); if (params->ssid_len > sizeof(drv->ssid)) goto nla_put_failure; os_memcpy(drv->ssid, params->ssid, params->ssid_len); drv->ssid_len = params->ssid_len; } wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); if (params->wpa_ie) NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); if (params->pairwise_suite != CIPHER_NONE) { int cipher; switch (params->pairwise_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); } if (params->group_suite != CIPHER_NONE) { int cipher; switch (params->group_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); } #ifdef CONFIG_IEEE80211W if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); #endif /* CONFIG_IEEE80211W */ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); if (params->prev_bssid) { wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, MAC2STR(params->prev_bssid)); NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, params->prev_bssid); } if (params->p2p) wpa_printf(MSG_DEBUG, " * P2P group"); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); capwap_dump_scan(drv); goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Association request send " "successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static int capwap_set_mode(struct wpa_driver_capwap_data *drv, int ifindex, enum nl80211_iftype mode) { wpa_printf(MSG_DEBUG, "# 1.wpa_driver_capwap_set_mode\n"); struct nl_msg *msg; int ret = -ENOBUFS; wpa_printf(MSG_DEBUG, "capwap: Set mode ifindex %d iftype %d (%s)", ifindex, mode, nl80211_iftype_str(mode)); msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (!ret) return 0; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_DEBUG, "capwap: Failed to set interface %d to mode %d:" " %d (%s)", ifindex, mode, ret, strerror(-ret)); return ret; } static int wpa_driver_capwap_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode) { wpa_printf(MSG_DEBUG, " 6.wpa_driver_capwap_set_mode\n"); //if(!real)return 0; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1; int i; int was_ap = is_ap_interface(drv->nlmode); if (capwap_set_mode(drv, drv->ifindex, nlmode) == 0) { drv->nlmode = nlmode; ret = 0; goto done; } if (nlmode == drv->nlmode) { wpa_printf(MSG_DEBUG, "capwap: Interface already in " "requested mode - ignore error"); ret = 0; goto done; /* Already in the requested mode */ } /* mac80211 doesn't allow mode changes while the device is up, so * take the device down, try to set the mode again, and bring the * device back up. */ wpa_printf(MSG_DEBUG, "capwap: Try mode change after setting " "interface down"); for (i = 0; i < 10; i++) { int res; res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); if (res == -EACCES || res == -ENODEV) break; if (res == 0) { /* Try to set the mode again while the interface is * down */ ret = capwap_set_mode(drv, drv->ifindex, nlmode); if (ret == -EACCES) break; res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); if (res && !ret) ret = -1; else if (ret != -EBUSY) break; } else wpa_printf(MSG_DEBUG, "capwap: Failed to set " "interface down"); os_sleep(0, 100000); } if (!ret) { wpa_printf(MSG_DEBUG, "capwap: Mode change succeeded while " "interface is down"); drv->nlmode = nlmode; drv->ignore_if_down_event = 1; } done: if (!ret && is_ap_interface(nlmode)) { /* Setup additional AP mode functionality if needed */ if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 && capwap_create_monitor_interface(drv) && !drv->no_monitor_iface_capab) return -1; } else if (!ret && !is_ap_interface(nlmode)) { /* Remove additional AP mode functionality */ if (was_ap && drv->no_monitor_iface_capab) wpa_driver_capwap_probe_req_report(bss, 0); capwap_remove_monitor_interface(drv); bss->beacon_set = 0; } if (!ret && is_p2p_interface(drv->nlmode)) { capwap_disable_11b_rates(drv, drv->ifindex, 1); drv->disabled_11b_rates = 1; } else if (!ret && drv->disabled_11b_rates) { capwap_disable_11b_rates(drv, drv->ifindex, 0); drv->disabled_11b_rates = 0; } if (ret) wpa_printf(MSG_DEBUG, "capwap: Interface mode change to %d " "from %d failed", nlmode, drv->nlmode); return ret; } static int wpa_driver_capwap_get_capa(void *priv, struct wpa_driver_capa *capa) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_get_capa"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!drv->has_capability) return -1; os_memcpy(capa, &drv->capa, sizeof(*capa)); return 0; } static int wpa_driver_capwap_set_operstate(void *priv, int state) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); } static int wpa_driver_capwap_set_supp_port(void *priv, int authorized) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct nl80211_sta_flag_update upd; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); os_memset(&upd, 0, sizeof(upd)); upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); if (authorized) upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } /* Set kernel driver on given frequency (MHz) */ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) { wpa_printf(MSG_DEBUG," 1.i802_set_freq"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; return wpa_driver_capwap_set_freq(drv, freq->freq, freq->ht_enabled, freq->sec_channel_offset); } #if defined(HOSTAPD) || defined(CONFIG_AP) static inline int min_int(int a, int b) { if (a < b) return a; return b; } static int get_key_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); /* * TODO: validate the key index and mac address! * Otherwise, there's a race condition as soon as * the kernel starts sending key notifications. */ if (tb[NL80211_ATTR_KEY_SEQ]) memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); return NL_SKIP; } static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, int idx, u8 *seq) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_KEY); if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); memset(seq, 0, 6); return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } int round1=0; static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, int mode) { wpa_printf(MSG_DEBUG,"> i802_set_rate_sets"); if(round1)return 0; else round1=1; struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; u8 rates[NL80211_MAX_SUPP_RATES]; u8 rates_len = 0; int i; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) rates[rates_len++] = basic_rates[i] / 5; NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: return -ENOBUFS; } static int i802_set_rts(void *priv, int rts) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret = -ENOBUFS; u32 val; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (rts >= 2347) val = (u32) -1; else val = rts; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (!ret) return 0; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_DEBUG, "capwap: Failed to set RTS threshold %d: " "%d (%s)", rts, ret, strerror(-ret)); return ret; } static int i802_set_frag(void *priv, int frag) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret = -ENOBUFS; u32 val; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (frag >= 2346) val = (u32) -1; else val = frag; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (!ret) return 0; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_DEBUG, "capwap: Failed to set fragmentation threshold " "%d: %d (%s)", frag, ret, strerror(-ret)); return ret; } static int i802_flush(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); /* * XXX: FIX! this needs to flush all VLANs too */ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int get_sta_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct hostap_sta_driver_data *data = arg; struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); /* * TODO: validate the interface and mac address! * Otherwise, there's a race condition as soon as * the kernel starts sending station notifications. */ if (!tb[NL80211_ATTR_STA_INFO]) { wpa_printf(MSG_DEBUG, "sta stats missing!"); return NL_SKIP; } if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, tb[NL80211_ATTR_STA_INFO], stats_policy)) { wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); return NL_SKIP; } if (stats[NL80211_STA_INFO_INACTIVE_TIME]) data->inactive_msec = nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); if (stats[NL80211_STA_INFO_RX_BYTES]) data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); if (stats[NL80211_STA_INFO_TX_BYTES]) data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); if (stats[NL80211_STA_INFO_RX_PACKETS]) data->rx_packets = nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); if (stats[NL80211_STA_INFO_TX_PACKETS]) data->tx_packets = nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); return NL_SKIP; } static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, const u8 *addr) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; os_memset(data, 0, sizeof(*data)); msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, get_sta_handler, data); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int i802_set_tx_queue_params(void *priv, int queue, int aifs, int cw_min, int cw_max, int burst_time) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct nlattr *txq, *params; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); if (!txq) goto nla_put_failure; /* We are only sending parameters for a single TXQ at a time */ params = nla_nest_start(msg, 1); if (!params) goto nla_put_failure; switch (queue) { case 0: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO); break; case 1: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI); break; case 2: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE); break; case 3: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK); break; } /* Burst time is configured in units of 0.1 msec and TXOP parameter in * 32 usec, so need to convert the value here. */ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); nla_nest_end(msg, params); nla_nest_end(msg, txq); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; msg = NULL; nla_put_failure: nlmsg_free(msg); return -1; } static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname, int vlan_id) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret = -ENOBUFS; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname)); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret < 0) { wpa_printf(MSG_ERROR, "capwap: NL80211_ATTR_STA_VLAN (addr=" MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", MAC2STR(addr), ifname, vlan_id, ret, strerror(-ret)); } nla_put_failure: nlmsg_free(msg); return ret; } static int i802_get_inact_sec(void *priv, const u8 *addr) { struct hostap_sta_driver_data data; int ret; data.inactive_msec = (unsigned long) -1; ret = i802_read_sta_data(priv, &data, addr); if (ret || data.inactive_msec == (unsigned long) -1) return -1; return data.inactive_msec / 1000; } static int i802_sta_clear_stats(void *priv, const u8 *addr) { #if 0 /* TODO */ #endif return 0; } static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason) { wpa_printf(MSG_DEBUG," 1.i802_sta_deauth"); struct i802_bss *bss = priv; struct ieee80211_mgmt mgmt; memset(&mgmt, 0, sizeof(mgmt)); mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); memcpy(mgmt.da, addr, ETH_ALEN); memcpy(mgmt.sa, own_addr, ETH_ALEN); memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); int r = wpa_driver_capwap_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.deauth)); return r; } static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, int reason) { struct i802_bss *bss = priv; struct ieee80211_mgmt mgmt; memset(&mgmt, 0, sizeof(mgmt)); mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DISASSOC); memcpy(mgmt.da, addr, ETH_ALEN); memcpy(mgmt.sa, own_addr, ETH_ALEN); memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return wpa_driver_capwap_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.disassoc)); } #endif /* HOSTAPD || CONFIG_AP */ #ifdef HOSTAPD static void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { wpa_printf(MSG_DEBUG," 3.add_ifidx"); int i; int *old; wpa_printf(MSG_DEBUG, "capwap: Add own interface ifindex %d", ifidx); for (i = 0; i < drv->num_if_indices; i++) { if (drv->if_indices[i] == 0) { drv->if_indices[i] = ifidx; return; } } if (drv->if_indices != drv->default_if_indices) old = drv->if_indices; else old = NULL; drv->if_indices = os_realloc(old, sizeof(int) * (drv->num_if_indices + 1)); if (!drv->if_indices) { if (!old) drv->if_indices = drv->default_if_indices; else drv->if_indices = old; wpa_printf(MSG_ERROR, "Failed to reallocate memory for " "interfaces"); wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); return; } else if (!old) os_memcpy(drv->if_indices, drv->default_if_indices, sizeof(drv->default_if_indices)); drv->if_indices[drv->num_if_indices] = ifidx; drv->num_if_indices++; } static void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { int i; for (i = 0; i < drv->num_if_indices; i++) { if (drv->if_indices[i] == ifidx) { drv->if_indices[i] = 0; break; } } } static int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { int i; for (i = 0; i < drv->num_if_indices; i++) if (drv->if_indices[i] == ifidx) return 1; return 0; } static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, const char *bridge_ifname) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; char name[IFNAMSIZ + 1]; os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); wpa_printf(MSG_DEBUG, "capwap: Set WDS STA addr=" MACSTR " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); if (val) { if (!if_nametoindex(name)) { if (capwap_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN, NULL, 1) < 0) return -1; if (bridge_ifname && linux_br_add_if(drv->global->ioctl_sock, bridge_ifname, name) < 0) return -1; } linux_set_iface_flags(drv->global->ioctl_sock, name, 1); return i802_set_sta_vlan(priv, addr, name, 0); } else { i802_set_sta_vlan(priv, addr, bss->ifname, 0); return wpa_driver_capwap_if_remove(priv, WPA_IF_AP_VLAN, name); } } void AC_handle_eapol(struct wpa_driver_capwap_data *drv, u8 *buf, int len){ u8 sa[6]; int hlen = GetEapol_Frame(sa, buf, len); //stampa_mac("AC eapol: " ,sa); drv_event_eapol_rx(drv->ctx, sa, buf + hlen, len - hlen); } static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) { wpa_printf(MSG_DEBUG, "handle_eapol %d\n",sock); struct wpa_driver_capwap_data *drv = eloop_ctx; struct sockaddr_ll lladdr; unsigned char buf[3000]; int len; socklen_t fromlen = sizeof(lladdr); len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&lladdr, &fromlen); return; if (len < 0) { wpa_printf(MSG_ERROR, "recv"); return; } wpa_printf(MSG_DEBUG, "LOCALE"); //stampa_frame(buf,len); wpa_printf(MSG_DEBUG, "%d,%d", len,have_ifidx(drv, lladdr.sll_ifindex)); //stampa_mac(" EAPOL MAC: ",lladdr.sll_addr); drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len); } static int i802_check_bridge(struct wpa_driver_capwap_data *drv, struct i802_bss *bss, const char *brname, const char *ifname) { wpa_printf(MSG_DEBUG," 7.i802_check_bridge"); int ifindex; char in_br[IFNAMSIZ]; os_strlcpy(bss->brname, brname, IFNAMSIZ); ifindex = if_nametoindex(brname); if (ifindex == 0) { /* * Bridge was configured, but the bridge device does * not exist. Try to add it now. */ if (linux_br_add(drv->global->ioctl_sock, brname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to add the " "bridge interface %s: %s", brname, strerror(errno)); return -1; } bss->added_bridge = 1; add_ifidx(drv, if_nametoindex(brname)); } if (linux_br_get(in_br, ifname) == 0) { if (os_strcmp(in_br, brname) == 0) return 0; /* already in the bridge */ wpa_printf(MSG_DEBUG, "capwap: Removing interface %s from " "bridge %s", ifname, in_br); if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to " "remove interface %s from bridge " "%s: %s", ifname, brname, strerror(errno)); return -1; } } wpa_printf(MSG_DEBUG, "capwap: Adding interface %s into bridge %s", ifname, brname); if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to add interface %s " "into bridge %s: %s", ifname, brname, strerror(errno)); return -1; } bss->added_if_into_bridge = 1; return 0; } static void *i802_init(struct hostapd_data *hapd, struct wpa_init_params *params) { wpa_printf(MSG_DEBUG, " 1.i802_init"); struct wpa_driver_capwap_data *drv; struct i802_bss *bss; size_t i; char brname[IFNAMSIZ]; int ifindex, br_ifindex; int br_added = 0; bss = wpa_driver_capwap_init(hapd, params->ifname, params->global_priv); if (bss == NULL) return NULL; drv = bss->drv; drv->nlmode = NL80211_IFTYPE_AP; drv->eapol_sock = -1; brname[0] = 0; if (linux_br_get(brname, params->ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Interface %s is in bridge %s", params->ifname, brname); br_ifindex = if_nametoindex(brname); } else { brname[0] = '\0'; br_ifindex = 0; } drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); drv->if_indices = drv->default_if_indices; for (i = 0; i < params->num_bridge; i++) { if (params->bridge[i]) { ifindex = if_nametoindex(params->bridge[i]); if (ifindex) add_ifidx(drv, ifindex); if (ifindex == br_ifindex) br_added = 1; } } if (!br_added && br_ifindex && (params->num_bridge == 0 || !params->bridge[0])) add_ifidx(drv, br_ifindex); /* start listening for EAPOL on the default AP interface */ add_ifidx(drv, drv->ifindex); if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0)) goto failed; if (params->bssid) { if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->bssid)) goto failed; } //if (eloop_register_read_sock(sockfd, AC_handle_recv_data_from_WTP,drv, NULL)) { // wpa_printf(MSG_ERROR,"Could not register UDP server socket"); // goto failed; //} if (wpa_driver_capwap_set_mode(bss, drv->nlmode)) { wpa_printf(MSG_ERROR, "capwap: Failed to set interface %s " "into AP mode", bss->ifname); goto failed; } if (params->num_bridge && params->bridge[0] && i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) goto failed; if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) goto failed; drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); if (drv->eapol_sock < 0) { perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); goto failed; } if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->own_addr)) goto failed; generic_ac_info.pseudo_interface = params->ifname; generic_ac_info.fd_ipc = start_ipc(drv->ctx, AC_inject_frame_in_hostapd); capability_get_mac(generic_ac_info.own_mac_addr); memcpy(drv->addr,generic_ac_info.own_mac_addr, ETH_ALEN); memcpy(params->own_addr,generic_ac_info.own_mac_addr, ETH_ALEN); if(generic_ac_info.fd_ipc<=0){ wpa_printf(MSG_ERROR, "Error: start_ipc"); return NULL; } return bss; failed: wpa_driver_capwap_deinit(bss); return NULL; } static void i802_deinit(void *priv) { ipc_send_DEL_WLAN(generic_ac_info.fd_ipc); end_ipc(generic_ac_info.fd_ipc); wpa_driver_capwap_deinit(priv); } #endif /* HOSTAPD */ static enum nl80211_iftype wpa_driver_capwap_if_type( enum wpa_driver_if_type type) { switch (type) { case WPA_IF_STATION: return NL80211_IFTYPE_STATION; case WPA_IF_P2P_CLIENT: case WPA_IF_P2P_GROUP: return NL80211_IFTYPE_P2P_CLIENT; case WPA_IF_AP_VLAN: return NL80211_IFTYPE_AP_VLAN; case WPA_IF_AP_BSS: return NL80211_IFTYPE_AP; case WPA_IF_P2P_GO: return NL80211_IFTYPE_P2P_GO; } return -1; } #ifdef CONFIG_P2P static int capwap_addr_in_use(struct capwap_global *global, const u8 *addr) { struct wpa_driver_capwap_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_capwap_data, list) { if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0) return 1; } return 0; } static int capwap_p2p_interface_addr(struct wpa_driver_capwap_data *drv, u8 *new_addr) { unsigned int idx; if (!drv->global) return -1; os_memcpy(new_addr, drv->addr, ETH_ALEN); for (idx = 0; idx < 64; idx++) { new_addr[0] = drv->addr[0] | 0x02; new_addr[0] ^= idx << 2; if (!capwap_addr_in_use(drv->global, new_addr)) break; } if (idx == 64) return -1; wpa_printf(MSG_DEBUG, "capwap: Assigned new P2P Interface Address " MACSTR, MAC2STR(new_addr)); return 0; } #endif /* CONFIG_P2P */ static int wpa_driver_capwap_if_add(void *priv, enum wpa_driver_if_type type, const char *ifname, const u8 *addr, void *bss_ctx, void **drv_priv, char *force_ifname, u8 *if_addr, const char *bridge) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ifidx; #ifdef HOSTAPD struct i802_bss *new_bss = NULL; if (type == WPA_IF_AP_BSS) { new_bss = os_zalloc(sizeof(*new_bss)); if (new_bss == NULL) return -1; } #endif /* HOSTAPD */ if (addr) os_memcpy(if_addr, addr, ETH_ALEN); ifidx = capwap_create_iface(drv, ifname, wpa_driver_capwap_if_type(type), addr, 0); if (ifidx < 0) { #ifdef HOSTAPD os_free(new_bss); #endif /* HOSTAPD */ return -1; } if (!addr && linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, if_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } #ifdef CONFIG_P2P if (!addr && (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || type == WPA_IF_P2P_GO)) { /* Enforce unique P2P Interface Address */ u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN]; if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, own_addr) < 0 || linux_get_ifhwaddr(drv->global->ioctl_sock, ifname, new_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "capwap: Allocate new address " "for P2P group interface"); if (capwap_p2p_interface_addr(drv, new_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, new_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } } os_memcpy(if_addr, new_addr, ETH_ALEN); } #endif /* CONFIG_P2P */ #ifdef HOSTAPD if (bridge && i802_check_bridge(drv, new_bss, bridge, ifname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to add the new " "interface %s to a bridge %s", ifname, bridge); capwap_remove_iface(drv, ifidx); os_free(new_bss); return -1; } if (type == WPA_IF_AP_BSS) { if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1)) { capwap_remove_iface(drv, ifidx); os_free(new_bss); return -1; } os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); new_bss->ifindex = ifidx; new_bss->drv = drv; new_bss->next = drv->first_bss.next; drv->first_bss.next = new_bss; if (drv_priv) *drv_priv = new_bss; } #endif /* HOSTAPD */ if (drv->global) drv->global->if_add_ifindex = ifidx; return 0; } static int wpa_driver_capwap_if_remove(void *priv, enum wpa_driver_if_type type, const char *ifname) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ifindex = if_nametoindex(ifname); wpa_printf(MSG_DEBUG, "capwap: %s(type=%d ifname=%s) ifindex=%d", __func__, type, ifname, ifindex); if (ifindex <= 0) return -1; #ifdef HOSTAPD if (bss->added_if_into_bridge) { if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, bss->ifname) < 0) wpa_printf(MSG_INFO, "capwap: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "capwap: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); } #endif /* HOSTAPD */ capwap_remove_iface(drv, ifindex); #ifdef HOSTAPD if (type != WPA_IF_AP_BSS) return 0; if (bss != &drv->first_bss) { struct i802_bss *tbss; for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { if (tbss->next == bss) { tbss->next = bss->next; os_free(bss); bss = NULL; break; } } if (bss) wpa_printf(MSG_INFO, "capwap: %s - could not find " "BSS %p in the list", __func__, bss); } #endif /* HOSTAPD */ return 0; } static int cookie_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); u64 *cookie = arg; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_COOKIE]) *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); return NL_SKIP; } static int capwap_send_frame_cmd(struct wpa_driver_capwap_data *drv, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, u64 *cookie_out, int no_cck) { struct nl_msg *msg; u64 cookie; int ret = -1; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_FRAME); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); if (wait) NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); if (no_cck) NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf); cookie = 0; ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Frame command failed: ret=%d " "(%s) (freq=%u wait=%u)", ret, strerror(-ret), freq, wait); goto nla_put_failure; } wpa_printf(MSG_DEBUG, "capwap: Frame TX command accepted; " "cookie 0x%llx", (long long unsigned int) cookie); if (cookie_out) *cookie_out = cookie; nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_send_action(void *priv, unsigned int freq, unsigned int wait_time, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, int no_cck) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1; u8 *buf; struct ieee80211_hdr *hdr; wpa_printf(MSG_DEBUG, "capwap: Send Action frame (ifindex=%d, " "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck); buf = os_zalloc(24 + data_len); if (buf == NULL) return ret; os_memcpy(buf + 24, data, data_len); hdr = (struct ieee80211_hdr *) buf; hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(hdr->addr1, dst, ETH_ALEN); os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); if (is_ap_interface(drv->nlmode)) ret = wpa_driver_capwap_send_mlme(priv, buf, 24 + data_len); else ret = capwap_send_frame_cmd(drv, freq, wait_time, buf, 24 + data_len, &drv->send_action_cookie, no_cck); os_free(buf); return ret; } static void wpa_driver_capwap_send_action_cancel_wait(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; msg = nlmsg_alloc(); if (!msg) return; capwap_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) wpa_printf(MSG_DEBUG, "capwap: wait cancel failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); } static int wpa_driver_capwap_remain_on_channel(void *priv, unsigned int freq, unsigned int duration) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; u64 cookie; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); cookie = 0; ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "capwap: Remain-on-channel cookie " "0x%llx for freq=%u MHz duration=%u", (long long unsigned int) cookie, freq, duration); drv->remain_on_chan_cookie = cookie; drv->pending_remain_on_chan = 1; return 0; } wpa_printf(MSG_DEBUG, "capwap: Failed to request remain-on-channel " "(freq=%d duration=%u): %d (%s)", freq, duration, ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_cancel_remain_on_channel(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; if (!drv->pending_remain_on_chan) { wpa_printf(MSG_DEBUG, "capwap: No pending remain-on-channel " "to cancel"); return -1; } wpa_printf(MSG_DEBUG, "capwap: Cancel remain-on-channel with cookie " "0x%llx", (long long unsigned int) drv->remain_on_chan_cookie); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "capwap: Failed to cancel remain-on-channel: " "%d (%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_probe_req_report(void *priv, int report) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!report) { if (drv->nl_preq.handle && drv->no_monitor_iface_capab && is_ap_interface(drv->nlmode)) { /* * Do not disable Probe Request reporting that was * enabled in capwap_setup_ap(). */ wpa_printf(MSG_DEBUG, "capwap: Skip disabling of " "Probe Request reporting nl_preq=%p while " "in AP mode", drv->nl_preq.handle); } else if (drv->nl_preq.handle) { wpa_printf(MSG_DEBUG, "capwap: Disable Probe Request " "reporting nl_preq=%p", drv->nl_preq.handle); eloop_unregister_read_sock( nl_socket_get_fd(drv->nl_preq.handle)); nl_destroy_handles(&drv->nl_preq); } return 0; } if (drv->nl_preq.handle) { wpa_printf(MSG_DEBUG, "capwap: Probe Request reporting " "already on!"); return 0; } if (nl_create_handles(&drv->nl_preq, drv->global->nl_cb, "preq")) return -1; if (capwap_register_frame(drv, drv->nl_preq.handle, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_PROBE_REQ << 4), NULL, 0) < 0) goto out_err; eloop_register_read_sock(nl_socket_get_fd(drv->nl_preq.handle), wpa_driver_capwap_event_receive, drv, drv->nl_preq.handle); return 0; out_err: nl_destroy_handles(&drv->nl_preq); return -1; } static int capwap_disable_11b_rates(struct wpa_driver_capwap_data *drv, int ifindex, int disabled) { struct nl_msg *msg; struct nlattr *bands, *band; int ret; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); if (!bands) goto nla_put_failure; /* * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS * rates. All 5 GHz rates are left enabled. */ band = nla_nest_start(msg, NL80211_BAND_2GHZ); if (!band) goto nla_put_failure; if (disabled) { NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, "\x0c\x12\x18\x24\x30\x48\x60\x6c"); } nla_nest_end(msg, band); nla_nest_end(msg, bands); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Set TX rates failed: ret=%d " "(%s)", ret, strerror(-ret)); } return ret; nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_deinit_ap(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_capwap_del_beacon(drv); return wpa_driver_capwap_set_mode(priv, NL80211_IFTYPE_STATION); } static int wpa_driver_capwap_deinit_p2p_cli(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT) return -1; return wpa_driver_capwap_set_mode(priv, NL80211_IFTYPE_STATION); } static void wpa_driver_capwap_resume(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { wpa_printf(MSG_DEBUG, "capwap: Failed to set interface up on " "resume event"); } } static int capwap_send_ft_action(void *priv, u8 action, const u8 *target_ap, const u8 *ies, size_t ies_len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret; u8 *data, *pos; size_t data_len; u8 own_addr[ETH_ALEN]; if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, own_addr) < 0) return -1; if (action != 1) { wpa_printf(MSG_ERROR, "capwap: Unsupported send_ft_action " "action %d", action); return -1; } /* * Action frame payload: * Category[1] = 6 (Fast BSS Transition) * Action[1] = 1 (Fast BSS Transition Request) * STA Address * Target AP Address * FT IEs */ data_len = 2 + 2 * ETH_ALEN + ies_len; data = os_malloc(data_len); if (data == NULL) return -1; pos = data; *pos++ = 0x06; /* FT Action category */ *pos++ = action; os_memcpy(pos, own_addr, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, target_ap, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, ies, ies_len); ret = wpa_driver_capwap_send_action(bss, drv->assoc_freq, 0, drv->bssid, own_addr, drv->bssid, data, data_len, 0); os_free(data); return ret; } static int capwap_signal_monitor(void *priv, int threshold, int hysteresis) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg, *cqm = NULL; wpa_printf(MSG_DEBUG, "capwap: Signal monitor threshold=%d " "hysteresis=%d", threshold, hysteresis); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_CQM); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); cqm = nlmsg_alloc(); if (cqm == NULL) return -1; NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold); NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis); nla_put_nested(msg, NL80211_ATTR_CQM, cqm); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; msg = NULL; nla_put_failure: nlmsg_free(cqm); nlmsg_free(msg); return -1; } static int capwap_signal_poll(void *priv, struct wpa_signal_info *si) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int res; os_memset(si, 0, sizeof(*si)); res = capwap_get_link_signal(drv, si); if (res != 0) return res; return capwap_get_link_noise(drv, si); } static int capwap_send_frame(void *priv, const u8 *data, size_t data_len, int encrypt) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; return wpa_driver_capwap_send_frame(drv, data, data_len, encrypt); } static int capwap_set_param(void *priv, const char *param) { wpa_printf(MSG_DEBUG, "capwap: driver param='%s'", param); if (param == NULL) return 0; #ifdef CONFIG_P2P if (os_strstr(param, "use_p2p_group_interface=1")) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; wpa_printf(MSG_DEBUG, "capwap: Use separate P2P group " "interface"); drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } #endif /* CONFIG_P2P */ return 0; } static void * capwap_global_init(void) { wpa_printf(MSG_DEBUG," 1.capwap_global_init"); struct capwap_global *global; struct netlink_config *cfg; global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; global->ioctl_sock = -1; dl_list_init(&global->interfaces); global->if_add_ifindex = -1; cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL) goto err; cfg->ctx = global; cfg->newlink_cb = wpa_driver_capwap_event_rtm_newlink; cfg->dellink_cb = wpa_driver_capwap_event_rtm_dellink; global->netlink = netlink_init(cfg); if (global->netlink == NULL) { os_free(cfg); goto err; } if (wpa_driver_capwap_init_nl_global(global) < 0) goto err; global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); if (global->ioctl_sock < 0) { perror("socket(PF_INET,SOCK_DGRAM)"); goto err; } return global; err: capwap_global_deinit(global); return NULL; } static void capwap_global_deinit(void *priv) { struct capwap_global *global = priv; if (global == NULL) return; if (!dl_list_empty(&global->interfaces)) { wpa_printf(MSG_ERROR, "capwap: %u interface(s) remain at " "capwap_global_deinit", dl_list_len(&global->interfaces)); } if (global->netlink) netlink_deinit(global->netlink); if (global->capwap) genl_family_put(global->capwap); nl_destroy_handles(&global->nl); if (global->nl_cb) nl_cb_put(global->nl_cb); if (global->ioctl_sock >= 0) close(global->ioctl_sock); os_free(global); } static const char * capwap_get_radio_name(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; return drv->phyname; } static int capwap_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, const u8 *pmkid) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(bss->drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); if (pmkid) NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid); if (bssid) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); return send_and_recv_msgs(bss->drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int capwap_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) { struct i802_bss *bss = priv; wpa_printf(MSG_DEBUG, "capwap: Add PMKID for " MACSTR, MAC2STR(bssid)); return capwap_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid); } static int capwap_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) { struct i802_bss *bss = priv; wpa_printf(MSG_DEBUG, "capwap: Delete PMKID for " MACSTR, MAC2STR(bssid)); return capwap_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid); } static int capwap_flush_pmkid(void *priv) { struct i802_bss *bss = priv; wpa_printf(MSG_DEBUG, "capwap: Flush PMKIDs"); return capwap_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL); } static void capwap_set_rekey_info(void *priv, const u8 *kek, const u8 *kck, const u8 *replay_ctr) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nlattr *replay_nested; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); if (!replay_nested) goto nla_put_failure; NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek); NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck); NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN, replay_ctr); nla_nest_end(msg, replay_nested); send_and_recv_msgs(drv, msg, NULL, NULL); return; nla_put_failure: nlmsg_free(msg); } static void capwap_poll_client(void *priv, const u8 *own_addr, const u8 *addr, int qos) { struct i802_bss *bss = priv; struct { struct ieee80211_hdr hdr; u16 qos_ctl; } STRUCT_PACKED nulldata; size_t size; /* Send data frame to poll STA and check whether this frame is ACKed */ os_memset(&nulldata, 0, sizeof(nulldata)); if (qos) { nulldata.hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_QOS_NULL); size = sizeof(nulldata); } else { nulldata.hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_NULLFUNC); size = sizeof(struct ieee80211_hdr); } nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); if (wpa_driver_capwap_send_mlme(bss, (u8 *) &nulldata, size) < 0) wpa_printf(MSG_DEBUG, "capwap_send_null_frame: Failed to " "send poll frame"); } #ifdef CONFIG_TDLS static int capwap_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, size_t len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; if (!dst) return -EINVAL; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); NLA_PUT(msg, NL80211_ATTR_IE, len, buf); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int capwap_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; enum capwap_tdls_operation capwap_oper; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; switch (oper) { case TDLS_DISCOVERY_REQ: capwap_oper = NL80211_TDLS_DISCOVERY_REQ; break; case TDLS_SETUP: capwap_oper = NL80211_TDLS_SETUP; break; case TDLS_TEARDOWN: capwap_oper = NL80211_TDLS_TEARDOWN; break; case TDLS_ENABLE_LINK: capwap_oper = NL80211_TDLS_ENABLE_LINK; break; case TDLS_DISABLE_LINK: capwap_oper = NL80211_TDLS_DISABLE_LINK; break; case TDLS_ENABLE: return 0; case TDLS_DISABLE: return 0; default: return -EINVAL; } msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, capwap_oper); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } #endif /* CONFIG TDLS */ void AC_inject_frame_in_hostapd(void *priv, u8 *buf, int len){ struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int datarate = 0, ssi_signal = 0; int failed = 0; if (len < 24) { perror("recv"); return; } int type = AC_get_Type(buf ,len ); if(type == WLAN_FC_TYPE_DATA ) { if( isEAPOL_Frame(buf, len) ) { if(isCallBackFrame(buf, len, generic_ac_info.own_mac_addr)) { wpa_printf(MSG_DEBUG, "EAPOL Data Frame 4 (%d)\n",len); handle_tx_callback(drv->ctx, buf ,len , !failed); } else { wpa_printf(MSG_DEBUG, "EAPOL Data Frame 6 (%d)\n",len); AC_handle_eapol(drv,buf,len); } } else { handle_frame(drv, buf , len , datarate, ssi_signal); } } else if( type == WLAN_FC_TYPE_MGMT ){ int stype = AC_get_SubType(buf ,len ); /* Per ora scarto i pacchetti PROBE REQUEST */ if(stype == WLAN_FC_STYPE_PROBE_REQ) { return; } if(isCallBackFrame(buf,len,generic_ac_info.own_mac_addr)) { handle_tx_callback(drv->ctx, buf ,len , !failed); if( stype == WLAN_FC_STYPE_ASSOC_RESP || stype == WLAN_FC_STYPE_REASSOC_RESP ){ ipc_send_add_station(generic_ac_info.fd_ipc,buf,len); } }else{ handle_frame(drv, buf , len , datarate, ssi_signal); if( stype == WLAN_FC_STYPE_DISASSOC ){ ipc_send_del_station(generic_ac_info.fd_ipc, buf, len); } } }else{ wpa_printf(MSG_ERROR,"Error: invalid/control 802.11 Type "); } } const struct wpa_driver_ops wpa_driver_capwap_ops = { .name = "capwap", .desc = "Linux capwap/cfg80211", .get_bssid = wpa_driver_capwap_get_bssid, .get_ssid = wpa_driver_capwap_get_ssid, .set_key = wpa_driver_capwap_set_key, .scan2 = wpa_driver_capwap_scan, .sched_scan = wpa_driver_capwap_sched_scan, .stop_sched_scan = wpa_driver_capwap_stop_sched_scan, .get_scan_results2 = wpa_driver_capwap_get_scan_results, .deauthenticate = wpa_driver_capwap_deauthenticate, .disassociate = wpa_driver_capwap_disassociate, .authenticate = wpa_driver_capwap_authenticate, .associate = wpa_driver_capwap_associate, .global_init = capwap_global_init, .global_deinit = capwap_global_deinit, .init2 = wpa_driver_capwap_init, .deinit = wpa_driver_capwap_deinit, .get_capa = wpa_driver_capwap_get_capa, .set_operstate = wpa_driver_capwap_set_operstate, .set_supp_port = wpa_driver_capwap_set_supp_port, .set_country = wpa_driver_capwap_set_country, .set_ap = wpa_driver_capwap_set_ap, .if_add = wpa_driver_capwap_if_add, .if_remove = wpa_driver_capwap_if_remove, .send_mlme = wpa_driver_capwap_send_mlme, .get_hw_feature_data = wpa_driver_capwap_get_hw_feature_data, .sta_add = wpa_driver_capwap_sta_add, .sta_remove = wpa_driver_capwap_sta_remove, .hapd_send_eapol = wpa_driver_capwap_hapd_send_eapol, .sta_set_flags = wpa_driver_capwap_sta_set_flags, //.inject_frame_in_hostapd = AC_inject_frame_in_hostapd, #ifdef HOSTAPD .hapd_init = i802_init, .hapd_deinit = i802_deinit, .set_wds_sta = i802_set_wds_sta, #endif /* HOSTAPD */ #if defined(HOSTAPD) || defined(CONFIG_AP) .get_seqnum = i802_get_seqnum, .flush = i802_flush, .read_sta_data = i802_read_sta_data, .get_inact_sec = i802_get_inact_sec, .sta_clear_stats = i802_sta_clear_stats, .set_rts = i802_set_rts, .set_frag = i802_set_frag, .set_tx_queue_params = i802_set_tx_queue_params, .set_sta_vlan = i802_set_sta_vlan, .set_rate_sets = i802_set_rate_sets, .sta_deauth = i802_sta_deauth, .sta_disassoc = i802_sta_disassoc, #endif /* HOSTAPD || CONFIG_AP */ .set_freq = i802_set_freq, .send_action = wpa_driver_capwap_send_action, .send_action_cancel_wait = wpa_driver_capwap_send_action_cancel_wait, .remain_on_channel = wpa_driver_capwap_remain_on_channel, .cancel_remain_on_channel = wpa_driver_capwap_cancel_remain_on_channel, .probe_req_report = wpa_driver_capwap_probe_req_report, .deinit_ap = wpa_driver_capwap_deinit_ap, .deinit_p2p_cli = wpa_driver_capwap_deinit_p2p_cli, .resume = wpa_driver_capwap_resume, .send_ft_action = capwap_send_ft_action, .signal_monitor = capwap_signal_monitor, .signal_poll = capwap_signal_poll, .send_frame = capwap_send_frame, .set_param = capwap_set_param, .get_radio_name = capwap_get_radio_name, .add_pmkid = capwap_add_pmkid, .remove_pmkid = capwap_remove_pmkid, .flush_pmkid = capwap_flush_pmkid, .set_rekey_info = capwap_set_rekey_info, .poll_client = capwap_poll_client, #ifdef CONFIG_TDLS .send_tdls_mgmt = capwap_send_tdls_mgmt, .tdls_oper = capwap_tdls_oper, #endif /* CONFIG_TDLS */ }; ================================================ FILE: hostapd_wrapper/src/drivers/driver_capwap_wtp.c ================================================ /* * Driver interaction with Linux capwap/cfg80211 * Copyright (c) 2002-2010, Jouni Malinen * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2007, Johannes Berg * Copyright (c) 2009-2010, Atheros Communications * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nl80211_copy.h" #include "common.h" #include "eloop.h" #include "utils/list.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "l2_packet/l2_packet.h" #include "capwap/capwap_mgmt_frame_wtp.h" #include "capwap/switch_8023_80211.h" #include "capwap/ipc_capwap_wtp.h" #include "netlink.h" #include "linux_ioctl.h" #include "radiotap.h" #include "radiotap_iter.h" #include "rfkill.h" #include "driver.h" #define BUFFER_SIZE 65000 //u8 tap_buffer[BUFFER_SIZE]; struct wtp_info { /* capwap FIXME: unused char *tap_interface; char *wlan_interface; char *br_interface; */ u8 own_mac_addr[ETH_ALEN]; int fd_tap; int fd_udp; int fd_ipc; }; struct priv_params { unsigned char ssid[32]; int ssid_len; unsigned char capa_buf[21]; }; struct priv_params ac_params; void stampa_buffer(u8 *buf, int len){ int i; for(i=0; i>= 22; port_bitmap[port / 32] &= ~(1 << (port % 32)); nl_handle_destroy(handle); } static inline int __genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache) { struct nl_cache *tmp = genl_ctrl_alloc_cache(h); if (!tmp) return -ENOMEM; *cache = tmp; return 0; } #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache #endif /* CONFIG_LIBNL20 */ struct capwap_handles { struct nl_handle *handle; struct nl_cache *cache; }; static int nl_create_handles(struct capwap_handles *handles, struct nl_cb *cb, const char *dbg) { if (!handles) return -1; handles->handle = capwap_handle_alloc(cb); if (handles->handle == NULL) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate netlink " "callbacks (%s)", dbg); return -1; } if (genl_connect(handles->handle)) { wpa_printf(MSG_ERROR, "capwap: Failed to connect to generic " "netlink (%s)", dbg); goto err; } if (genl_ctrl_alloc_cache(handles->handle, &handles->cache) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate generic " "netlink cache (%s)", dbg); goto err; } return 0; err: capwap_handle_destroy(handles->handle); return -1; } static void nl_destroy_handles(struct capwap_handles *handles) { if (handles->handle == NULL) return; nl_cache_free(handles->cache); capwap_handle_destroy(handles->handle); handles->handle = NULL; } #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ #endif #ifndef IFF_DORMANT #define IFF_DORMANT 0x20000 /* driver signals dormant */ #endif #ifndef IF_OPER_DORMANT #define IF_OPER_DORMANT 5 #endif #ifndef IF_OPER_UP #define IF_OPER_UP 6 #endif struct capwap_global { struct dl_list interfaces; int if_add_ifindex; struct netlink_data *netlink; struct nl_cb *nl_cb; struct capwap_handles nl; struct genl_family *capwap; int ioctl_sock; /* socket for ioctl() use */ }; static void capwap_global_deinit(void *priv); static void wpa_driver_capwap_deinit(void *priv); struct i802_bss { struct wpa_driver_capwap_data *drv; struct i802_bss *next; int ifindex; char ifname[IFNAMSIZ + 1]; char brname[IFNAMSIZ]; unsigned int beacon_set:1; unsigned int added_if_into_bridge:1; unsigned int added_bridge:1; }; struct wpa_driver_capwap_data { struct capwap_global *global; struct dl_list list; u8 addr[ETH_ALEN]; char phyname[32]; void *ctx; int ifindex; int if_removed; int if_disabled; int ignore_if_down_event; struct rfkill_data *rfkill; struct wpa_driver_capa capa; int has_capability; int operstate; int scan_complete_events; struct capwap_handles nl_event, nl_preq; u8 auth_bssid[ETH_ALEN]; u8 bssid[ETH_ALEN]; int associated; u8 ssid[32]; size_t ssid_len; enum nl80211_iftype nlmode; enum nl80211_iftype ap_scan_as_station; unsigned int assoc_freq; int monitor_sock; int monitor_ifidx; int no_monitor_iface_capab; unsigned int disabled_11b_rates:1; unsigned int pending_remain_on_chan:1; unsigned int in_interface_list:1; u64 remain_on_chan_cookie; u64 send_action_cookie; unsigned int last_mgmt_freq; unsigned int ap_oper_freq; struct wpa_driver_scan_filter *filter_ssids; size_t num_filter_ssids; struct i802_bss first_bss; #ifdef CONFIG_AP struct l2_packet_data *l2; #endif /* CONFIG_AP */ #ifdef HOSTAPD int eapol_sock; /* socket for EAPOL frames */ int default_if_indices[16]; int *if_indices; int num_if_indices; int last_freq; int last_freq_ht; #endif /* HOSTAPD */ #define CW_LOCAL_MAC 0 #define CW_SPLIT_MAC 1 int mac_mode; }; static void wpa_driver_capwap_scan_timeout(void *eloop_ctx, void *timeout_ctx); static int wpa_driver_capwap_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode); static int wpa_driver_capwap_finish_drv_init(struct wpa_driver_capwap_data *drv); static int wpa_driver_capwap_mlme(struct wpa_driver_capwap_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change); static void capwap_remove_monitor_interface( struct wpa_driver_capwap_data *drv); static int capwap_send_frame_cmd(struct wpa_driver_capwap_data *drv, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, u64 *cookie, int no_cck); static int wpa_driver_capwap_probe_req_report(void *priv, int report); #ifdef HOSTAPD static void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); static void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); static int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx); static int wpa_driver_capwap_if_remove(void *priv, enum wpa_driver_if_type type, const char *ifname); #else /* HOSTAPD */ static inline void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { } static inline void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { } static inline int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { return 0; } #endif /* HOSTAPD */ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq); static int capwap_disable_11b_rates(struct wpa_driver_capwap_data *drv, int ifindex, int disabled); static int capwap_leave_ibss(struct wpa_driver_capwap_data *drv); static int is_ap_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_AP || nlmode == NL80211_IFTYPE_P2P_GO); } static int is_sta_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_STATION || nlmode == NL80211_IFTYPE_P2P_CLIENT); } static int is_p2p_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_P2P_CLIENT || nlmode == NL80211_IFTYPE_P2P_GO); } struct capwap_bss_info_arg { struct wpa_driver_capwap_data *drv; struct wpa_scan_results *res; unsigned int assoc_freq; u8 assoc_bssid[ETH_ALEN]; }; static int bss_info_handler(struct nl_msg *msg, void *arg); /* capwap code */ static int ack_handler(struct nl_msg *msg, void *arg) { int *err = arg; *err = 0; return NL_STOP; } static int finish_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_SKIP; } static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; return NL_SKIP; } static int no_seq_check(struct nl_msg *msg, void *arg) { return NL_OK; } static int send_and_recv(struct wpa_driver_capwap_data *drv, struct nl_handle *nl_handle, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) { struct nl_cb *cb; int err = -ENOMEM; cb = nl_cb_clone(drv->global->nl_cb); if (!cb) goto out; err = nl_send_auto_complete(nl_handle, msg); if (err < 0) goto out; err = 1; nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); if (valid_handler) nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); while (err > 0) nl_recvmsgs(nl_handle, cb); out: nl_cb_put(cb); nlmsg_free(msg); return err; } static int send_and_recv_msgs(struct wpa_driver_capwap_data *drv, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) { return send_and_recv(drv, drv->global->nl.handle, msg, valid_handler, valid_data); } struct family_data { const char *group; int id; }; static int family_handler(struct nl_msg *msg, void *arg) { struct family_data *res = arg; struct nlattr *tb[CTRL_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *mcgrp; int i; nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[CTRL_ATTR_MCAST_GROUPS]) return NL_SKIP; nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), nla_len(mcgrp), NULL); if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID] || os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]), res->group, nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0) continue; res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); break; }; return NL_SKIP; } static int nl_get_multicast_id(struct wpa_driver_capwap_data *drv, const char *family, const char *group) { struct nl_msg *msg; int ret = -1; struct family_data res = { group, -ENOENT }; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->global->nl.handle, "nlctrl"), 0, 0, CTRL_CMD_GETFAMILY, 0); NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); ret = send_and_recv_msgs(drv, msg, family_handler, &res); msg = NULL; if (ret == 0) ret = res.id; nla_put_failure: nlmsg_free(msg); return ret; } static void * capwap_cmd(struct wpa_driver_capwap_data *drv, struct nl_msg *msg, int flags, uint8_t cmd) { return genlmsg_put(msg, 0, 0, genl_family_get_id(drv->global->capwap), 0, flags, cmd, 0); } static int wpa_driver_capwap_get_bssid(void *priv, u8 *bssid) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!drv->associated) return -1; os_memcpy(bssid, drv->bssid, ETH_ALEN); return 0; } static int wpa_driver_capwap_get_ssid(void *priv, u8 *ssid) { wpa_printf(MSG_DEBUG, "wpa_driver_capwap_get_ssid"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!drv->associated) return -1; // os_memcpy(ssid, drv->ssid, drv->ssid_len); os_memcpy(ssid, ac_params.ssid, ac_params.ssid_len); return ac_params.ssid_len; } static void wpa_driver_capwap_event_link(struct wpa_driver_capwap_data *drv, char *buf, size_t len, int del) { union wpa_event_data event; os_memset(&event, 0, sizeof(event)); if (len > sizeof(event.interface_status.ifname)) len = sizeof(event.interface_status.ifname) - 1; os_memcpy(event.interface_status.ifname, buf, len); event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : EVENT_INTERFACE_ADDED; wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", del ? "DEL" : "NEW", event.interface_status.ifname, del ? "removed" : "added"); if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) { if (del) { if (drv->if_removed) { wpa_printf(MSG_DEBUG, "capwap: if_removed " "already set - ignore event"); return; } drv->if_removed = 1; } else { if (if_nametoindex(drv->first_bss.ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Interface %s " "does not exist - ignore " "RTM_NEWLINK", drv->first_bss.ifname); return; } if (!drv->if_removed) { wpa_printf(MSG_DEBUG, "capwap: if_removed " "already cleared - ignore event"); return; } drv->if_removed = 0; } } wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } static int wpa_driver_capwap_own_ifname(struct wpa_driver_capwap_data *drv, u8 *buf, size_t len) { int attrlen, rta_len; struct rtattr *attr; attrlen = len; attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname) == 0) return 1; else break; } attr = RTA_NEXT(attr, attrlen); } return 0; } static int wpa_driver_capwap_own_ifindex(struct wpa_driver_capwap_data *drv, int ifindex, u8 *buf, size_t len) { if (drv->ifindex == ifindex) return 1; if (drv->if_removed && wpa_driver_capwap_own_ifname(drv, buf, len)) { drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname); wpa_printf(MSG_DEBUG, "capwap: Update ifindex for a removed " "interface"); wpa_driver_capwap_finish_drv_init(drv); return 1; } return 0; } static struct wpa_driver_capwap_data * capwap_find_drv(struct capwap_global *global, int idx, u8 *buf, size_t len) { struct wpa_driver_capwap_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_capwap_data, list) { if (wpa_driver_capwap_own_ifindex(drv, idx, buf, len) || have_ifidx(drv, idx)) return drv; } return NULL; } static void wpa_driver_capwap_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { struct capwap_global *global = ctx; struct wpa_driver_capwap_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; char namebuf[IFNAMSIZ]; drv = capwap_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { wpa_printf(MSG_DEBUG, "capwap: Ignore event for foreign " "ifindex %d", ifi->ifi_index); return; } wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " "(%s%s%s%s)", drv->operstate, ifi->ifi_flags, (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && linux_iface_up(drv->global->ioctl_sock, drv->first_bss.ifname) > 0) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface down " "event since interface %s is up", namebuf); return; } wpa_printf(MSG_DEBUG, "capwap: Interface down"); if (drv->ignore_if_down_event) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface down " "event generated by mode change"); drv->ignore_if_down_event = 0; } else { drv->if_disabled = 1; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); } } if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && linux_iface_up(drv->global->ioctl_sock, drv->first_bss.ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " "event since interface %s is down", namebuf); } else if (if_nametoindex(drv->first_bss.ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " "event since interface %s does not exist", drv->first_bss.ifname); } else if (drv->if_removed) { wpa_printf(MSG_DEBUG, "capwap: Ignore interface up " "event since interface %s is marked " "removed", drv->first_bss.ifname); } else { wpa_printf(MSG_DEBUG, "capwap: Interface up"); drv->if_disabled = 0; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); } } /* * Some drivers send the association event before the operup event--in * this case, lifting operstate in wpa_driver_capwap_set_operstate() * fails. This will hit us when wpa_supplicant does not need to do * IEEE 802.1X authentication */ if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, IF_OPER_UP); attrlen = len; attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_capwap_event_link( drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 0); } else if (attr->rta_type == IFLA_MASTER) brid = nla_get_u32((struct nlattr *) attr); attr = RTA_NEXT(attr, attrlen); } if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been added to bridge */ if_indextoname(brid, namebuf); wpa_printf(MSG_DEBUG, "capwap: Add ifindex %u for bridge %s", brid, namebuf); add_ifidx(drv, brid); } } static void wpa_driver_capwap_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { struct capwap_global *global = ctx; struct wpa_driver_capwap_data *drv; int attrlen, rta_len; struct rtattr *attr; u32 brid = 0; drv = capwap_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { wpa_printf(MSG_DEBUG, "capwap: Ignore dellink event for " "foreign ifindex %d", ifi->ifi_index); return; } attrlen = len; attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_capwap_event_link( drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 1); } else if (attr->rta_type == IFLA_MASTER) brid = nla_get_u32((struct nlattr *) attr); attr = RTA_NEXT(attr, attrlen); } if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; if_indextoname(brid, namebuf); wpa_printf(MSG_DEBUG, "capwap: Remove ifindex %u for bridge " "%s", brid, namebuf); del_ifidx(drv, brid); } } static void mlme_event_auth(struct wpa_driver_capwap_data *drv, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24 + sizeof(mgmt->u.auth)) { wpa_printf(MSG_DEBUG, "capwap: Too short association event " "frame"); return; } os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); os_memset(&event, 0, sizeof(event)); os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); if (len > 24 + sizeof(mgmt->u.auth)) { event.auth.ies = mgmt->u.auth.variable; event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); } wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); } static unsigned int capwap_get_assoc_freq(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; int ret; struct capwap_bss_info_arg arg; os_memset(&arg, 0, sizeof(arg)); msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "capwap: Operating frequency for the " "associated BSS from scan results: %u MHz", arg.assoc_freq); return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq; } wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return drv->assoc_freq; } static void mlme_event_assoc(struct wpa_driver_capwap_data *drv, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 status; mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24 + sizeof(mgmt->u.assoc_resp)) { wpa_printf(MSG_DEBUG, "capwap: Too short association event " "frame"); return; } status = le_to_host16(mgmt->u.assoc_resp.status_code); if (status != WLAN_STATUS_SUCCESS) { os_memset(&event, 0, sizeof(event)); event.assoc_reject.bssid = mgmt->bssid; if (len > 24 + sizeof(mgmt->u.assoc_resp)) { event.assoc_reject.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; event.assoc_reject.resp_ies_len = len - 24 - sizeof(mgmt->u.assoc_resp); } event.assoc_reject.status_code = status; wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } drv->associated = 1; os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); os_memset(&event, 0, sizeof(event)); if (len > 24 + sizeof(mgmt->u.assoc_resp)) { event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; event.assoc_info.resp_ies_len = len - 24 - sizeof(mgmt->u.assoc_resp); } event.assoc_info.freq = drv->assoc_freq; wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } static void mlme_event_connect(struct wpa_driver_capwap_data *drv, enum nl80211_commands cmd, struct nlattr *status, struct nlattr *addr, struct nlattr *req_ie, struct nlattr *resp_ie) { union wpa_event_data event; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* * Avoid reporting two association events that would confuse * the core code. */ wpa_printf(MSG_DEBUG, "capwap: Ignore connect event (cmd=%d) " "when using userspace SME", cmd); return; } os_memset(&event, 0, sizeof(event)); if (cmd == NL80211_CMD_CONNECT && nla_get_u16(status) != WLAN_STATUS_SUCCESS) { if (addr) event.assoc_reject.bssid = nla_data(addr); if (resp_ie) { event.assoc_reject.resp_ies = nla_data(resp_ie); event.assoc_reject.resp_ies_len = nla_len(resp_ie); } event.assoc_reject.status_code = nla_get_u16(status); wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } drv->associated = 1; if (addr) os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); if (req_ie) { event.assoc_info.req_ies = nla_data(req_ie); event.assoc_info.req_ies_len = nla_len(req_ie); } if (resp_ie) { event.assoc_info.resp_ies = nla_data(resp_ie); event.assoc_info.resp_ies_len = nla_len(resp_ie); } event.assoc_info.freq = capwap_get_assoc_freq(drv); wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } static void mlme_event_disconnect(struct wpa_driver_capwap_data *drv, struct nlattr *reason, struct nlattr *addr) { union wpa_event_data data; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* * Avoid reporting two disassociation events that could * confuse the core code. */ wpa_printf(MSG_DEBUG, "capwap: Ignore disconnect " "event when using userspace SME"); return; } drv->associated = 0; os_memset(&data, 0, sizeof(data)); if (reason) data.disassoc_info.reason_code = nla_get_u16(reason); wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); } static void mlme_timeout_event(struct wpa_driver_capwap_data *drv, enum nl80211_commands cmd, struct nlattr *addr) { union wpa_event_data event; enum wpa_event_type ev; if (nla_len(addr) != ETH_ALEN) return; wpa_printf(MSG_DEBUG, "capwap: MLME event %d; timeout with " MACSTR, cmd, MAC2STR((u8 *) nla_data(addr))); if (cmd == NL80211_CMD_AUTHENTICATE) ev = EVENT_AUTH_TIMED_OUT; else if (cmd == NL80211_CMD_ASSOCIATE) ev = EVENT_ASSOC_TIMED_OUT; else return; os_memset(&event, 0, sizeof(event)); os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); wpa_supplicant_event(drv->ctx, ev, &event); } static void mlme_event_mgmt(struct wpa_driver_capwap_data *drv, struct nlattr *freq, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 fc, stype; mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24) { wpa_printf(MSG_DEBUG, "capwap: Too short action frame"); return; } fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); os_memset(&event, 0, sizeof(event)); if (freq) { event.rx_action.freq = nla_get_u32(freq); drv->last_mgmt_freq = event.rx_action.freq; } if (stype == WLAN_FC_STYPE_ACTION) { event.rx_action.da = mgmt->da; event.rx_action.sa = mgmt->sa; event.rx_action.bssid = mgmt->bssid; event.rx_action.category = mgmt->u.action.category; event.rx_action.data = &mgmt->u.action.category + 1; event.rx_action.len = frame + len - event.rx_action.data; wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); } else { event.rx_mgmt.frame = frame; event.rx_mgmt.frame_len = len; wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } } static void mlme_event_action_tx_status(struct wpa_driver_capwap_data *drv, struct nlattr *cookie, const u8 *frame, size_t len, struct nlattr *ack) { union wpa_event_data event; const struct ieee80211_hdr *hdr; u16 fc; u64 cookie_val; if (!cookie) return; cookie_val = nla_get_u64(cookie); wpa_printf(MSG_DEBUG, "capwap: Action TX status: cookie=0%llx%s " "(ack=%d)", (long long unsigned int) cookie_val, cookie_val == drv->send_action_cookie ? " (match)" : " (unknown)", ack != NULL); if (cookie_val != drv->send_action_cookie) return; hdr = (const struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.tx_status.type = WLAN_FC_GET_TYPE(fc); event.tx_status.stype = WLAN_FC_GET_STYPE(fc); event.tx_status.dst = hdr->addr1; event.tx_status.data = frame; event.tx_status.data_len = len; event.tx_status.ack = ack != NULL; wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); } static void mlme_event_deauth_disassoc(struct wpa_driver_capwap_data *drv, enum wpa_event_type type, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; const u8 *bssid = NULL; u16 reason_code = 0; mgmt = (const struct ieee80211_mgmt *) frame; if (len >= 24) { bssid = mgmt->bssid; if (drv->associated != 0 && os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { /* * We have presumably received this deauth as a * response to a clear_state_mismatch() outgoing * deauth. Don't let it take us offline! */ wpa_printf(MSG_DEBUG, "capwap: Deauth received " "from Unknown BSSID " MACSTR " -- ignoring", MAC2STR(bssid)); return; } } drv->associated = 0; os_memset(&event, 0, sizeof(event)); /* Note: Same offset for Reason Code in both frame subtypes */ if (len >= 24 + sizeof(mgmt->u.deauth)) reason_code = le_to_host16(mgmt->u.deauth.reason_code); if (type == EVENT_DISASSOC) { event.disassoc_info.addr = bssid; event.disassoc_info.reason_code = reason_code; if (frame + len > mgmt->u.disassoc.variable) { event.disassoc_info.ie = mgmt->u.disassoc.variable; event.disassoc_info.ie_len = frame + len - mgmt->u.disassoc.variable; } } else { event.deauth_info.addr = bssid; event.deauth_info.reason_code = reason_code; if (frame + len > mgmt->u.deauth.variable) { event.deauth_info.ie = mgmt->u.deauth.variable; event.deauth_info.ie_len = frame + len - mgmt->u.deauth.variable; } } wpa_supplicant_event(drv->ctx, type, &event); } static void mlme_event_unprot_disconnect(struct wpa_driver_capwap_data *drv, enum wpa_event_type type, const u8 *frame, size_t len) { const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 reason_code = 0; if (len < 24) return; mgmt = (const struct ieee80211_mgmt *) frame; os_memset(&event, 0, sizeof(event)); /* Note: Same offset for Reason Code in both frame subtypes */ if (len >= 24 + sizeof(mgmt->u.deauth)) reason_code = le_to_host16(mgmt->u.deauth.reason_code); if (type == EVENT_UNPROT_DISASSOC) { event.unprot_disassoc.sa = mgmt->sa; event.unprot_disassoc.da = mgmt->da; event.unprot_disassoc.reason_code = reason_code; } else { event.unprot_deauth.sa = mgmt->sa; event.unprot_deauth.da = mgmt->da; event.unprot_deauth.reason_code = reason_code; } wpa_supplicant_event(drv->ctx, type, &event); } static void mlme_event(struct wpa_driver_capwap_data *drv, enum nl80211_commands cmd, struct nlattr *frame, struct nlattr *addr, struct nlattr *timed_out, struct nlattr *freq, struct nlattr *ack, struct nlattr *cookie) { if (timed_out && addr) { mlme_timeout_event(drv, cmd, addr); return; } if (frame == NULL) { wpa_printf(MSG_DEBUG, "capwap: MLME event %d without frame " "data", cmd); return; } wpa_printf(MSG_DEBUG, "capwap: MLME event %d", cmd); wpa_hexdump(MSG_MSGDUMP, "capwap: MLME event frame", nla_data(frame), nla_len(frame)); switch (cmd) { case NL80211_CMD_AUTHENTICATE: mlme_event_auth(drv, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_ASSOCIATE: mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_DEAUTHENTICATE: mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_DISASSOCIATE: mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME: mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME_TX_STATUS: mlme_event_action_tx_status(drv, cookie, nla_data(frame), nla_len(frame), ack); break; case NL80211_CMD_UNPROT_DEAUTHENTICATE: mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_UNPROT_DISASSOCIATE: mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC, nla_data(frame), nla_len(frame)); break; default: break; } } static void mlme_event_michael_mic_failure(struct wpa_driver_capwap_data *drv, struct nlattr *tb[]) { union wpa_event_data data; wpa_printf(MSG_DEBUG, "capwap: MLME event Michael MIC failure"); os_memset(&data, 0, sizeof(data)); if (tb[NL80211_ATTR_MAC]) { wpa_hexdump(MSG_DEBUG, "capwap: Source MAC address", nla_data(tb[NL80211_ATTR_MAC]), nla_len(tb[NL80211_ATTR_MAC])); data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); } if (tb[NL80211_ATTR_KEY_SEQ]) { wpa_hexdump(MSG_DEBUG, "capwap: TSC", nla_data(tb[NL80211_ATTR_KEY_SEQ]), nla_len(tb[NL80211_ATTR_KEY_SEQ])); } if (tb[NL80211_ATTR_KEY_TYPE]) { enum nl80211_key_type key_type = nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); wpa_printf(MSG_DEBUG, "capwap: Key Type %d", key_type); if (key_type == NL80211_KEYTYPE_PAIRWISE) data.michael_mic_failure.unicast = 1; } else data.michael_mic_failure.unicast = 1; if (tb[NL80211_ATTR_KEY_IDX]) { u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); wpa_printf(MSG_DEBUG, "capwap: Key Id %d", key_id); } wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); } static void mlme_event_join_ibss(struct wpa_driver_capwap_data *drv, struct nlattr *tb[]) { if (tb[NL80211_ATTR_MAC] == NULL) { wpa_printf(MSG_DEBUG, "capwap: No address in IBSS joined " "event"); return; } os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); drv->associated = 1; wpa_printf(MSG_DEBUG, "capwap: IBSS " MACSTR " joined", MAC2STR(drv->bssid)); wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); } static void mlme_event_remain_on_channel(struct wpa_driver_capwap_data *drv, int cancel_event, struct nlattr *tb[]) { unsigned int freq, chan_type, duration; union wpa_event_data data; u64 cookie; if (tb[NL80211_ATTR_WIPHY_FREQ]) freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); else freq = 0; if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); else chan_type = 0; if (tb[NL80211_ATTR_DURATION]) duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); else duration = 0; if (tb[NL80211_ATTR_COOKIE]) cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); else cookie = 0; wpa_printf(MSG_DEBUG, "capwap: Remain-on-channel event (cancel=%d " "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", cancel_event, freq, chan_type, duration, (long long unsigned int) cookie, cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); if (cookie != drv->remain_on_chan_cookie) return; /* not for us */ if (cancel_event) drv->pending_remain_on_chan = 0; os_memset(&data, 0, sizeof(data)); data.remain_on_channel.freq = freq; data.remain_on_channel.duration = duration; wpa_supplicant_event(drv->ctx, cancel_event ? EVENT_CANCEL_REMAIN_ON_CHANNEL : EVENT_REMAIN_ON_CHANNEL, &data); } static void send_scan_event(struct wpa_driver_capwap_data *drv, int aborted, struct nlattr *tb[]) { union wpa_event_data event; struct nlattr *nl; int rem; struct scan_info *info; #define MAX_REPORT_FREQS 50 int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; os_memset(&event, 0, sizeof(event)); info = &event.scan_info; info->aborted = aborted; if (tb[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { struct wpa_driver_scan_ssid *s = &info->ssids[info->num_ssids]; s->ssid = nla_data(nl); s->ssid_len = nla_len(nl); info->num_ssids++; if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) break; } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) { freqs[num_freqs] = nla_get_u32(nl); num_freqs++; if (num_freqs == MAX_REPORT_FREQS - 1) break; } info->freqs = freqs; info->num_freqs = num_freqs; } wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); } static int get_link_signal(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, }; struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; struct wpa_signal_info *sig_change = arg; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_STA_INFO] || nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, tb[NL80211_ATTR_STA_INFO], policy)) return NL_SKIP; if (!sinfo[NL80211_STA_INFO_SIGNAL]) return NL_SKIP; sig_change->current_signal = (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) { sig_change->current_txrate = 0; } else { if (rinfo[NL80211_RATE_INFO_BITRATE]) { sig_change->current_txrate = nla_get_u16(rinfo[ NL80211_RATE_INFO_BITRATE]) * 100; } } } return NL_SKIP; } static int capwap_get_link_signal(struct wpa_driver_capwap_data *drv, struct wpa_signal_info *sig) { struct nl_msg *msg; sig->current_signal = -9999; sig->current_txrate = 0; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); return send_and_recv_msgs(drv, msg, get_link_signal, sig); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int get_link_noise(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, }; struct wpa_signal_info *sig_change = arg; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_SURVEY_INFO]) { wpa_printf(MSG_DEBUG, "capwap: survey data missing!"); return NL_SKIP; } if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, tb[NL80211_ATTR_SURVEY_INFO], survey_policy)) { wpa_printf(MSG_DEBUG, "capwap: failed to parse nested " "attributes!"); return NL_SKIP; } if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) return NL_SKIP; if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != sig_change->frequency) return NL_SKIP; if (!sinfo[NL80211_SURVEY_INFO_NOISE]) return NL_SKIP; sig_change->current_noise = (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); return NL_SKIP; } static int capwap_get_link_noise(struct wpa_driver_capwap_data *drv, struct wpa_signal_info *sig_change) { struct nl_msg *msg; sig_change->current_noise = 9999; sig_change->frequency = drv->assoc_freq; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, get_link_noise, sig_change); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, }; struct wpa_scan_results *scan_results = arg; struct wpa_scan_res *scan_res; size_t i; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_SURVEY_INFO]) { wpa_printf(MSG_DEBUG, "capwap: Survey data missing"); return NL_SKIP; } if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, tb[NL80211_ATTR_SURVEY_INFO], survey_policy)) { wpa_printf(MSG_DEBUG, "capwap: Failed to parse nested " "attributes"); return NL_SKIP; } if (!sinfo[NL80211_SURVEY_INFO_NOISE]) return NL_SKIP; if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) return NL_SKIP; for (i = 0; i < scan_results->num; ++i) { scan_res = scan_results->res[i]; if (!scan_res) continue; if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != scan_res->freq) continue; if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID)) continue; scan_res->noise = (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); scan_res->flags &= ~WPA_SCAN_NOISE_INVALID; } return NL_SKIP; } static int capwap_get_noise_for_scan_results( struct wpa_driver_capwap_data *drv, struct wpa_scan_results *scan_res) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, scan_res); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static void capwap_cqm_event(struct wpa_driver_capwap_data *drv, struct nlattr *tb[]) { static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, }; struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; enum nl80211_cqm_rssi_threshold_event event; union wpa_event_data ed; struct wpa_signal_info sig; int res; if (tb[NL80211_ATTR_CQM] == NULL || nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], cqm_policy)) { wpa_printf(MSG_DEBUG, "capwap: Ignore invalid CQM event"); return; } os_memset(&ed, 0, sizeof(ed)); if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { if (!tb[NL80211_ATTR_MAC]) return; os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); return; } if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) return; event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { wpa_printf(MSG_DEBUG, "capwap: Connection quality monitor " "event: RSSI high"); ed.signal_change.above_threshold = 1; } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { wpa_printf(MSG_DEBUG, "capwap: Connection quality monitor " "event: RSSI low"); ed.signal_change.above_threshold = 0; } else return; res = capwap_get_link_signal(drv, &sig); if (res == 0) { ed.signal_change.current_signal = sig.current_signal; ed.signal_change.current_txrate = sig.current_txrate; wpa_printf(MSG_DEBUG, "capwap: Signal: %d dBm txrate: %d", sig.current_signal, sig.current_txrate); } res = capwap_get_link_noise(drv, &sig); if (res == 0) { ed.signal_change.current_noise = sig.current_noise; wpa_printf(MSG_DEBUG, "capwap: Noise: %d dBm", sig.current_noise); } wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); } static void capwap_new_station_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { u8 *addr; union wpa_event_data data; if (tb[NL80211_ATTR_MAC] == NULL) return; addr = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "capwap: New station " MACSTR, MAC2STR(addr)); if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) { u8 *ies = NULL; size_t ies_len = 0; if (tb[NL80211_ATTR_IE]) { ies = nla_data(tb[NL80211_ATTR_IE]); ies_len = nla_len(tb[NL80211_ATTR_IE]); } wpa_hexdump(MSG_DEBUG, "capwap: Assoc Req IEs", ies, ies_len); drv_event_assoc(drv->ctx, addr, ies, ies_len, 0); return; } if (drv->nlmode != NL80211_IFTYPE_ADHOC) return; os_memset(&data, 0, sizeof(data)); os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); } static void capwap_del_station_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { u8 *addr; union wpa_event_data data; if (tb[NL80211_ATTR_MAC] == NULL) return; addr = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "capwap: Delete station " MACSTR, MAC2STR(addr)); if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) { drv_event_disassoc(drv->ctx, addr); return; } if (drv->nlmode != NL80211_IFTYPE_ADHOC) return; os_memset(&data, 0, sizeof(data)); os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); } static void capwap_rekey_offload_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { [NL80211_REKEY_DATA_KEK] = { .minlen = NL80211_KEK_LEN, .maxlen = NL80211_KEK_LEN, }, [NL80211_REKEY_DATA_KCK] = { .minlen = NL80211_KCK_LEN, .maxlen = NL80211_KCK_LEN, }, [NL80211_REKEY_DATA_REPLAY_CTR] = { .minlen = NL80211_REPLAY_CTR_LEN, .maxlen = NL80211_REPLAY_CTR_LEN, }, }; union wpa_event_data data; if (!tb[NL80211_ATTR_MAC]) return; if (!tb[NL80211_ATTR_REKEY_DATA]) return; if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) return; if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) return; os_memset(&data, 0, sizeof(data)); data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); wpa_printf(MSG_DEBUG, "capwap: Rekey offload event for BSSID " MACSTR, MAC2STR(data.driver_gtk_rekey.bssid)); data.driver_gtk_rekey.replay_ctr = nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); wpa_hexdump(MSG_DEBUG, "capwap: Rekey offload - Replay Counter", data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); } static void capwap_pmksa_candidate_event(struct wpa_driver_capwap_data *drv, struct nlattr **tb) { struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, [NL80211_PMKSA_CANDIDATE_BSSID] = { .minlen = ETH_ALEN, .maxlen = ETH_ALEN, }, [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, }; union wpa_event_data data; if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) return; if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) return; if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || !cand[NL80211_PMKSA_CANDIDATE_BSSID]) return; os_memset(&data, 0, sizeof(data)); os_memcpy(data.pmkid_candidate.bssid, nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); data.pmkid_candidate.index = nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); data.pmkid_candidate.preauth = cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); } static int process_event(struct nl_msg *msg, void *arg) { struct wpa_driver_capwap_data *drv = arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_IFINDEX]) { int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { wpa_printf(MSG_DEBUG, "capwap: Ignored event (cmd=%d)" " for foreign interface (ifindex %d)", gnlh->cmd, ifindex); return NL_SKIP; } } if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { wpa_driver_capwap_set_mode(&drv->first_bss, drv->ap_scan_as_station); drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } switch (gnlh->cmd) { case NL80211_CMD_TRIGGER_SCAN: wpa_printf(MSG_DEBUG, "capwap: Scan trigger"); break; case NL80211_CMD_START_SCHED_SCAN: wpa_printf(MSG_DEBUG, "capwap: Sched scan started"); break; case NL80211_CMD_SCHED_SCAN_STOPPED: wpa_printf(MSG_DEBUG, "capwap: Sched scan stopped"); wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); break; case NL80211_CMD_NEW_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "capwap: New scan results available"); drv->scan_complete_events = 1; eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); send_scan_event(drv, 0, tb); break; case NL80211_CMD_SCHED_SCAN_RESULTS: wpa_printf(MSG_DEBUG, "capwap: New sched scan results available"); send_scan_event(drv, 0, tb); break; case NL80211_CMD_SCAN_ABORTED: wpa_printf(MSG_DEBUG, "capwap: Scan aborted"); /* * Need to indicate that scan results are available in order * not to make wpa_supplicant stop its scanning. */ eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); send_scan_event(drv, 1, tb); break; case NL80211_CMD_AUTHENTICATE: case NL80211_CMD_ASSOCIATE: case NL80211_CMD_DEAUTHENTICATE: case NL80211_CMD_DISASSOCIATE: case NL80211_CMD_FRAME: case NL80211_CMD_FRAME_TX_STATUS: case NL80211_CMD_UNPROT_DEAUTHENTICATE: case NL80211_CMD_UNPROT_DISASSOCIATE: mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; case NL80211_CMD_CONNECT: case NL80211_CMD_ROAM: mlme_event_connect(drv, gnlh->cmd, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_RESP_IE]); break; case NL80211_CMD_DISCONNECT: mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], tb[NL80211_ATTR_MAC]); break; case NL80211_CMD_MICHAEL_MIC_FAILURE: mlme_event_michael_mic_failure(drv, tb); break; case NL80211_CMD_JOIN_IBSS: mlme_event_join_ibss(drv, tb); break; case NL80211_CMD_REMAIN_ON_CHANNEL: mlme_event_remain_on_channel(drv, 0, tb); break; case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: mlme_event_remain_on_channel(drv, 1, tb); break; case NL80211_CMD_NOTIFY_CQM: capwap_cqm_event(drv, tb); break; case NL80211_CMD_REG_CHANGE: wpa_printf(MSG_DEBUG, "capwap: Regulatory domain change"); wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, NULL); break; case NL80211_CMD_REG_BEACON_HINT: wpa_printf(MSG_DEBUG, "capwap: Regulatory beacon hint"); wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, NULL); break; case NL80211_CMD_NEW_STATION: capwap_new_station_event(drv, tb); break; case NL80211_CMD_DEL_STATION: capwap_del_station_event(drv, tb); break; case NL80211_CMD_SET_REKEY_OFFLOAD: capwap_rekey_offload_event(drv, tb); break; case NL80211_CMD_PMKSA_CANDIDATE: capwap_pmksa_candidate_event(drv, tb); break; default: wpa_printf(MSG_DEBUG, "capwap: Ignored unknown event " "(cmd=%d)", gnlh->cmd); break; } return NL_SKIP; } static void wpa_driver_capwap_event_receive(int sock, void *eloop_ctx, void *handle) { wpa_printf(MSG_DEBUG, "wpa_driver_capwap_event_receive"); struct nl_cb *cb; struct wpa_driver_capwap_data *drv = eloop_ctx; wpa_printf(MSG_DEBUG, "capwap: Event message available"); cb = nl_cb_clone(drv->global->nl_cb); if (!cb) return; nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv); nl_recvmsgs(handle, cb); nl_cb_put(cb); } /** * wpa_driver_capwap_set_country - ask capwap to set the regulatory domain * @priv: driver_capwap private data * @alpha2_arg: country to which to switch to * Returns: 0 on success, -1 on failure * * This asks capwap to set the regulatory domain for given * country ISO / IEC alpha2. */ static int wpa_driver_capwap_set_country(void *priv, const char *alpha2_arg) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; char alpha2[3]; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; alpha2[0] = alpha2_arg[0]; alpha2[1] = alpha2_arg[1]; alpha2[2] = '\0'; capwap_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG); NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2); if (send_and_recv_msgs(drv, msg, NULL, NULL)) return -EINVAL; return 0; nla_put_failure: nlmsg_free(msg); return -EINVAL; } struct wiphy_info_data { struct wpa_driver_capa *capa; unsigned int error:1; }; static int wiphy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct wiphy_info_data *info = arg; int p2p_go_supported = 0, p2p_client_supported = 0; int p2p_concurrent = 0; int auth_supported = 0, connect_supported = 0; struct wpa_driver_capa *capa = info->capa; static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = { [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, }, iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) capa->max_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) capa->max_sched_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); if (tb[NL80211_ATTR_MAX_MATCH_SETS]) capa->max_match_sets = nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { struct nlattr *nl_mode; int i; nla_for_each_nested(nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { switch (nla_type(nl_mode)) { case NL80211_IFTYPE_AP: capa->flags |= WPA_DRIVER_FLAGS_AP; break; case NL80211_IFTYPE_P2P_GO: p2p_go_supported = 1; break; case NL80211_IFTYPE_P2P_CLIENT: p2p_client_supported = 1; break; } } } if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) { struct nlattr *nl_combi; int rem_combi; nla_for_each_nested(nl_combi, tb[NL80211_ATTR_INTERFACE_COMBINATIONS], rem_combi) { struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; struct nlattr *nl_limit, *nl_mode; int err, rem_limit, rem_mode; int combination_has_p2p = 0, combination_has_mgd = 0; err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, nl_combi, iface_combination_policy); if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || !tb_comb[NL80211_IFACE_COMB_MAXNUM] || !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) goto broken_combination; nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS], rem_limit) { err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT, nl_limit, iface_limit_policy); if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES]) goto broken_combination; nla_for_each_nested( nl_mode, tb_limit[NL80211_IFACE_LIMIT_TYPES], rem_mode) { int ift = nla_type(nl_mode); if (ift == NL80211_IFTYPE_P2P_GO || ift == NL80211_IFTYPE_P2P_CLIENT) combination_has_p2p = 1; if (ift == NL80211_IFTYPE_STATION) combination_has_mgd = 1; } if (combination_has_p2p && combination_has_mgd) break; } if (combination_has_p2p && combination_has_mgd) { p2p_concurrent = 1; break; } broken_combination: ; } } if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { struct nlattr *nl_cmd; int i; nla_for_each_nested(nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { switch (nla_get_u32(nl_cmd)) { case NL80211_CMD_AUTHENTICATE: auth_supported = 1; break; case NL80211_CMD_CONNECT: connect_supported = 1; break; case NL80211_CMD_START_SCHED_SCAN: /* * Disabled for 1.x for now as it is * broken there due to the way it ends * up getting used. capa->sched_scan_supported = 1; */ break; } } } if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { wpa_printf(MSG_DEBUG, "capwap: Using driver-based " "off-channel TX"); capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; } if (tb[NL80211_ATTR_ROAM_SUPPORT]) { wpa_printf(MSG_DEBUG, "capwap: Using driver-based roaming"); capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; } /* default to 5000 since early versions of mac80211 don't set it */ capa->max_remain_on_chan = 5000; if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]) capa->max_remain_on_chan = nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); if (auth_supported) capa->flags |= WPA_DRIVER_FLAGS_SME; else if (!connect_supported) { wpa_printf(MSG_INFO, "capwap: Driver does not support " "authentication/association or connect commands"); info->error = 1; } if (p2p_go_supported && p2p_client_supported) capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; if (p2p_concurrent) { wpa_printf(MSG_DEBUG, "capwap: Use separate P2P group " "interface (driver advertised support)"); capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } if (tb[NL80211_ATTR_TDLS_SUPPORT]) { wpa_printf(MSG_DEBUG, "capwap: TDLS supported"); capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) { wpa_printf(MSG_DEBUG, "capwap: TDLS external setup"); capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; } } return NL_SKIP; } static int wpa_driver_capwap_get_info(struct wpa_driver_capwap_data *drv, struct wiphy_info_data *info) { wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_get_info"); struct nl_msg *msg; os_memset(info, 0, sizeof(*info)); info->capa = &drv->capa; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex); if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0) return 0; msg = NULL; nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_capa(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG, " 4.wpa_driver_capwap_capa"); struct wiphy_info_data info; if (wpa_driver_capwap_get_info(drv, &info)) return -1; if (info.error) return -1; drv->has_capability = 1; /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; wpa_printf(MSG_DEBUG, "1>> drv->capa.flags %d",drv->capa.flags); wpa_printf(MSG_DEBUG, "2>> drv->capa.auth %d",drv->capa.auth ); wpa_printf(MSG_DEBUG, "2>> drv->capa.enc %d",drv->capa.enc ); return 0; } #ifdef ANDROID static int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name) { /* * Android ICS has very minimal genl_ctrl_resolve() implementation, so * need to work around that. */ struct nl_cache *cache = NULL; struct genl_family *capwap = NULL; int id = -1; if (genl_ctrl_alloc_cache(handle, &cache) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate generic " "netlink cache"); goto fail; } capwap = genl_ctrl_search_by_name(cache, name); if (capwap == NULL) goto fail; id = genl_family_get_id(capwap); fail: if (capwap) genl_family_put(capwap); if (cache) nl_cache_free(cache); return id; } #define genl_ctrl_resolve android_genl_ctrl_resolve #endif /* ANDROID */ static int wpa_driver_capwap_init_nl_global(struct capwap_global *global) { wpa_printf(MSG_DEBUG, " 2.wpa_driver_capwap_init_nl_global\n"); global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); if (global->nl_cb == NULL) { wpa_printf(MSG_ERROR, "capwap: Failed to allocate netlink " "callbacks"); return -1; } if (nl_create_handles(&global->nl, global->nl_cb, "nl")) return -1; global->capwap = genl_ctrl_search_by_name(global->nl.cache, "nl80211"); if (global->capwap == NULL) { wpa_printf(MSG_ERROR, "capwap: 'capwap' generic netlink not " "found"); return -1; } return 0; } static int wpa_driver_capwap_init_nl(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_init_nl\n"); struct capwap_global *global = drv->global; int ret; /* Initialize generic netlink and capwap */ if (nl_create_handles(&drv->nl_event, global->nl_cb, "event")) goto err3; ret = nl_get_multicast_id(drv, "nl80211", "scan"); if (ret >= 0) ret = nl_socket_add_membership(drv->nl_event.handle, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "capwap: Could not add multicast " "membership for scan events: %d (%s)", ret, strerror(-ret)); goto err4; } ret = nl_get_multicast_id(drv, "nl80211", "mlme"); if (ret >= 0) ret = nl_socket_add_membership(drv->nl_event.handle, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "capwap: Could not add multicast " "membership for mlme events: %d (%s)", ret, strerror(-ret)); goto err4; } ret = nl_get_multicast_id(drv, "nl80211", "regulatory"); if (ret >= 0) ret = nl_socket_add_membership(drv->nl_event.handle, ret); if (ret < 0) { wpa_printf(MSG_DEBUG, "capwap: Could not add multicast " "membership for regulatory events: %d (%s)", ret, strerror(-ret)); /* Continue without regulatory events */ } eloop_register_read_sock(nl_socket_get_fd(drv->nl_event.handle), wpa_driver_capwap_event_receive, drv, drv->nl_event.handle); return 0; err4: nl_destroy_handles(&drv->nl_event); err3: return -1; } static void wpa_driver_capwap_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "capwap: RFKILL blocked"); /* * This may be for any interface; use ifdown event to disable * interface. */ } static void wpa_driver_capwap_rfkill_unblocked(void *ctx) { struct wpa_driver_capwap_data *drv = ctx; wpa_printf(MSG_DEBUG, "capwap: RFKILL unblocked"); if (linux_set_iface_flags(drv->global->ioctl_sock, drv->first_bss.ifname, 1)) { wpa_printf(MSG_DEBUG, "capwap: Could not set interface UP " "after rfkill unblock"); return; } /* rtnetlink ifup handler will report interface as enabled */ } static void capwap_get_phy_name(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG, " 2.capwap_get_phy_name\n"); /* Find phy (radio) to which this interface belongs */ char buf[90], *pos; int f, rv; drv->phyname[0] = '\0'; snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", drv->first_bss.ifname); f = open(buf, O_RDONLY); if (f < 0) { wpa_printf(MSG_DEBUG, "Could not open file %s: %s", buf, strerror(errno)); return; } rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); close(f); if (rv < 0) { wpa_printf(MSG_DEBUG, "Could not read file %s: %s", buf, strerror(errno)); return; } drv->phyname[rv] = '\0'; pos = os_strchr(drv->phyname, '\n'); if (pos) *pos = '\0'; wpa_printf(MSG_DEBUG, "capwap: interface %s in phy %s", drv->first_bss.ifname, drv->phyname); } #ifdef CONFIG_AP static void capwap_l2_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { wpa_printf(MSG_DEBUG, "capwap: l2_packet read %u", (unsigned int) len); } #endif /* CONFIG_AP */ /** * wpa_driver_capwap_init - Initialize capwap driver interface * @ctx: context to be used when calling wpa_supplicant functions, * e.g., wpa_supplicant_event() * @ifname: interface name, e.g., wlan0 * @global_priv: private driver global data from global_init() * Returns: Pointer to private data, %NULL on failure */ static void * wpa_driver_capwap_init(void *ctx, const char *ifname, void *global_priv) { wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_init\n"); struct wpa_driver_capwap_data *drv; struct rfkill_config *rcfg; struct i802_bss *bss; if (global_priv == NULL) return NULL; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) return NULL; drv->global = global_priv; drv->ctx = ctx; bss = &drv->first_bss; bss->drv = drv; os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); drv->monitor_ifidx = -1; drv->monitor_sock = -1; drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; if (wpa_driver_capwap_init_nl(drv)) { os_free(drv); return NULL; } capwap_get_phy_name(drv); rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL) goto failed; rcfg->ctx = drv; os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); rcfg->blocked_cb = wpa_driver_capwap_rfkill_blocked; rcfg->unblocked_cb = wpa_driver_capwap_rfkill_unblocked; drv->rfkill = rfkill_init(rcfg); if (drv->rfkill == NULL) { wpa_printf(MSG_DEBUG, "capwap: RFKILL status not available"); os_free(rcfg); } if (wpa_driver_capwap_finish_drv_init(drv)) goto failed; #ifdef CONFIG_AP drv->l2 = l2_packet_init(ifname, NULL, ETH_P_EAPOL, capwap_l2_read, drv, 0); #endif /* CONFIG_AP */ if (drv->global) { dl_list_add(&drv->global->interfaces, &drv->list); drv->in_interface_list = 1; } return bss; failed: wpa_driver_capwap_deinit(bss); return NULL; } static int capwap_register_frame(struct wpa_driver_capwap_data *drv, struct nl_handle *nl_handle, u16 type, const u8 *match, size_t match_len) { struct nl_msg *msg; int ret = -1; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); ret = send_and_recv(drv, nl_handle, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Register frame command " "failed (type=%u): ret=%d (%s)", type, ret, strerror(-ret)); wpa_hexdump(MSG_DEBUG, "capwap: Register frame match", match, match_len); goto nla_put_failure; } ret = 0; nla_put_failure: nlmsg_free(msg); return ret; } static int capwap_register_action_frame(struct wpa_driver_capwap_data *drv, const u8 *match, size_t match_len) { u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); return capwap_register_frame(drv, drv->nl_event.handle, type, match, match_len); } static int capwap_register_action_frames(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG, " 6.capwap_register_action_frames\n"); #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) /* GAS Initial Request */ if (capwap_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0) return -1; /* GAS Initial Response */ if (capwap_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0) return -1; /* GAS Comeback Request */ if (capwap_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0) return -1; /* GAS Comeback Response */ if (capwap_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0) return -1; #endif /* CONFIG_P2P || CONFIG_INTERWORKING */ #ifdef CONFIG_P2P /* P2P Public Action */ if (capwap_register_action_frame(drv, (u8 *) "\x04\x09\x50\x6f\x9a\x09", 6) < 0) return -1; /* P2P Action */ if (capwap_register_action_frame(drv, (u8 *) "\x7f\x50\x6f\x9a\x09", 5) < 0) return -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211W /* SA Query Response */ if (capwap_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0) return -1; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_TDLS if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) { /* TDLS Discovery Response */ if (capwap_register_action_frame(drv, (u8 *) "\x04\x0e", 2) < 0) return -1; } #endif /* CONFIG_TDLS */ /* FT Action frames */ if (capwap_register_action_frame(drv, (u8 *) "\x06", 1) < 0) return -1; else drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; /* WNM - BSS Transition Management Request */ if (capwap_register_action_frame(drv, (u8 *) "\x0a\x07", 2) < 0) return -1; return 0; } static void wpa_driver_capwap_send_rfkill(void *eloop_ctx, void *timeout_ctx) { wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); } static int wpa_driver_capwap_finish_drv_init(struct wpa_driver_capwap_data *drv) { wpa_printf(MSG_DEBUG, " 3.wpa_driver_capwap_finish_drv_init\n"); struct i802_bss *bss = &drv->first_bss; int send_rfkill_event = 0; drv->ifindex = if_nametoindex(bss->ifname); drv->first_bss.ifindex = drv->ifindex; #ifndef HOSTAPD /* * Make sure the interface starts up in station mode unless this is a * dynamically added interface (e.g., P2P) that was already configured * with proper iftype. */ if (drv->ifindex != drv->global->if_add_ifindex && wpa_driver_capwap_set_mode(bss, NL80211_IFTYPE_STATION) < 0) { wpa_printf(MSG_ERROR, "capwap: Could not configure driver to " "use managed mode"); return -1; } if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { if (rfkill_is_blocked(drv->rfkill)) { wpa_printf(MSG_DEBUG, "capwap: Could not yet enable " "interface '%s' due to rfkill", bss->ifname); drv->if_disabled = 1; send_rfkill_event = 1; } else { wpa_printf(MSG_ERROR, "capwap: Could not set " "interface '%s' UP", bss->ifname); return -1; } } netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT); #endif /* HOSTAPD */ if (wpa_driver_capwap_capa(drv)) return -1; if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, drv->addr)) return -1; memcpy(generic_wtp_info.own_mac_addr,drv->addr,ETH_ALEN); if (capwap_register_action_frames(drv) < 0) { wpa_printf(MSG_DEBUG, "capwap: Failed to register Action " "frame processing - ignore for now"); /* * Older kernel versions did not support this, so ignore the * error for now. Some functionality may not be available * because of this. */ } if (send_rfkill_event) { eloop_register_timeout(0, 0, wpa_driver_capwap_send_rfkill, drv, drv->ctx); } return 0; } static int wpa_driver_capwap_del_beacon(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } /** * wpa_driver_capwap_deinit - Deinitialize capwap driver interface * @priv: Pointer to private capwap data from wpa_driver_capwap_init() * * Shut down driver interface and processing of driver events. Free * private data buffer if one was allocated in wpa_driver_capwap_init(). */ static void wpa_driver_capwap_deinit(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; #ifdef CONFIG_AP if (drv->l2) l2_packet_deinit(drv->l2); #endif /* CONFIG_AP */ if (drv->nl_preq.handle) wpa_driver_capwap_probe_req_report(bss, 0); if (bss->added_if_into_bridge) { if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, bss->ifname) < 0) wpa_printf(MSG_INFO, "capwap: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "capwap: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); } capwap_remove_monitor_interface(drv); if (is_ap_interface(drv->nlmode)) wpa_driver_capwap_del_beacon(drv); #ifdef HOSTAPD if (drv->last_freq_ht) { /* Clear HT flags from the driver */ struct hostapd_freq_params freq; os_memset(&freq, 0, sizeof(freq)); freq.freq = drv->last_freq; i802_set_freq(priv, &freq); } if (drv->eapol_sock >= 0) { eloop_unregister_read_sock(drv->eapol_sock); close(drv->eapol_sock); } if (drv->if_indices != drv->default_if_indices) os_free(drv->if_indices); #endif /* HOSTAPD */ if (drv->disabled_11b_rates) capwap_disable_11b_rates(drv, drv->ifindex, 0); netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, IF_OPER_UP); rfkill_deinit(drv->rfkill); eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); wpa_driver_capwap_set_mode(bss, NL80211_IFTYPE_STATION); eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_event.handle)); nl_destroy_handles(&drv->nl_event); os_free(drv->filter_ssids); if (drv->in_interface_list) dl_list_del(&drv->list); os_free(drv); } /** * wpa_driver_capwap_scan_timeout - Scan timeout to report scan completion * @eloop_ctx: Driver private data * @timeout_ctx: ctx argument given to wpa_driver_capwap_init() * * This function can be used as registered timeout when starting a scan to * generate a scan completed event if the driver does not report this. */ static void wpa_driver_capwap_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_capwap_data *drv = eloop_ctx; if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { wpa_driver_capwap_set_mode(&drv->first_bss, drv->ap_scan_as_station); drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } /** * wpa_driver_capwap_scan - Request the driver to initiate scan * @priv: Pointer to private driver data from wpa_driver_capwap_init() * @params: Scan parameters * Returns: 0 on success, -1 on failure */ static int wpa_driver_capwap_scan(void *priv, struct wpa_driver_scan_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = 0, timeout; struct nl_msg *msg, *ssids, *freqs, *rates; size_t i; msg = nlmsg_alloc(); ssids = nlmsg_alloc(); freqs = nlmsg_alloc(); rates = nlmsg_alloc(); if (!msg || !ssids || !freqs || !rates) { nlmsg_free(msg); nlmsg_free(ssids); nlmsg_free(freqs); nlmsg_free(rates); return -1; } os_free(drv->filter_ssids); drv->filter_ssids = params->filter_ssids; params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; capwap_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Scan SSID", ac_params.ssid, ac_params.ssid_len); NLA_PUT(ssids, 1, ac_params.ssid_len, ac_params.ssid); for (i = 1; i < params->num_ssids; i++) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Scan SSID", params->ssids[i].ssid, params->ssids[i].ssid_len); NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, params->ssids[i].ssid); } if (params->num_ssids) nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); if (params->extra_ies) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Scan extra IEs", params->extra_ies, params->extra_ies_len); NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies); } if (params->freqs) { for (i = 0; params->freqs[i]; i++) { wpa_printf(MSG_MSGDUMP, "capwap: Scan frequency %u " "MHz", params->freqs[i]); NLA_PUT_U32(freqs, i + 1, params->freqs[i]); } nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } if (params->p2p_probe) { /* * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates * by masking out everything else apart from the OFDM rates 6, * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz * rates are left enabled. */ NLA_PUT(rates, NL80211_BAND_2GHZ, 8, "\x0c\x12\x18\x24\x30\x48\x60\x6c"); nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates); NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); #ifdef HOSTAPD if (is_ap_interface(drv->nlmode)) { /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ if (wpa_driver_capwap_set_mode( bss, NL80211_IFTYPE_STATION)) goto nla_put_failure; if (wpa_driver_capwap_scan(drv, params)) { wpa_driver_capwap_set_mode(bss, drv->nlmode); goto nla_put_failure; } /* Restore AP mode when processing scan results */ drv->ap_scan_as_station = drv->nlmode; ret = 0; } else goto nla_put_failure; #else /* HOSTAPD */ goto nla_put_failure; #endif /* HOSTAPD */ } /* Not all drivers generate "scan completed" wireless event, so try to * read results after a timeout. */ timeout = 10; if (drv->scan_complete_events) { /* * The driver seems to deliver events to notify when scan is * complete, so use longer timeout to avoid race conditions * with scanning and following association request. */ timeout = 30; } wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " "seconds", ret, timeout); eloop_cancel_timeout(wpa_driver_capwap_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_capwap_scan_timeout, drv, drv->ctx); nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); nlmsg_free(freqs); nlmsg_free(rates); return ret; } /** * wpa_driver_capwap_sched_scan - Initiate a scheduled scan * @priv: Pointer to private driver data from wpa_driver_capwap_init() * @params: Scan parameters * @interval: Interval between scan cycles in milliseconds * Returns: 0 on success, -1 on failure or if not supported */ static int wpa_driver_capwap_sched_scan(void *priv, struct wpa_driver_scan_params *params, u32 interval) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = 0; struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets; size_t i; msg = nlmsg_alloc(); ssids = nlmsg_alloc(); freqs = nlmsg_alloc(); if (!msg || !ssids || !freqs) { nlmsg_free(msg); nlmsg_free(ssids); nlmsg_free(freqs); return -1; } os_free(drv->filter_ssids); drv->filter_ssids = params->filter_ssids; params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; capwap_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval); if (drv->num_filter_ssids) { match_sets = nlmsg_alloc(); for (i = 0; i < drv->num_filter_ssids; i++) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan filter SSID", drv->filter_ssids[i].ssid, drv->filter_ssids[i].ssid_len); match_set_ssid = nlmsg_alloc(); nla_put(match_set_ssid, NL80211_ATTR_SCHED_SCAN_MATCH_SSID, drv->filter_ssids[i].ssid_len, drv->filter_ssids[i].ssid); nla_put_nested(match_sets, i + 1, match_set_ssid); nlmsg_free(match_set_ssid); } nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, match_sets); nlmsg_free(match_sets); } wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan SSID", ac_params.ssid, ac_params.ssid_len); NLA_PUT(ssids, 1, ac_params.ssid_len, ac_params.ssid); for (i = 1; i < params->num_ssids; i++) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan SSID", params->ssids[i].ssid, params->ssids[i].ssid_len); NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, params->ssids[i].ssid); } if (params->num_ssids) nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); if (params->extra_ies) { wpa_hexdump_ascii(MSG_MSGDUMP, "capwap: Sched scan extra IEs", params->extra_ies, params->extra_ies_len); NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies); } if (params->freqs) { for (i = 0; params->freqs[i]; i++) { wpa_printf(MSG_MSGDUMP, "capwap: Scan frequency %u " "MHz", params->freqs[i]); NLA_PUT_U32(freqs, i + 1, params->freqs[i]); } nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); /* TODO: if we get an error here, we should fall back to normal scan */ msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Sched scan start failed: " "ret=%d (%s)", ret, strerror(-ret)); goto nla_put_failure; } wpa_printf(MSG_DEBUG, "capwap: Sched scan requested (ret=%d) - " "scan interval %d msec", ret, interval); nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); nlmsg_free(freqs); return ret; } /** * wpa_driver_capwap_stop_sched_scan - Stop a scheduled scan * @priv: Pointer to private driver data from wpa_driver_capwap_init() * Returns: 0 on success, -1 on failure or if not supported */ static int wpa_driver_capwap_stop_sched_scan(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = 0; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Sched scan stop failed: " "ret=%d (%s)", ret, strerror(-ret)); goto nla_put_failure; } wpa_printf(MSG_DEBUG, "capwap: Sched scan stop sent (ret=%d)", ret); nla_put_failure: nlmsg_free(msg); return ret; } static const u8 * capwap_get_ie(const u8 *ies, size_t ies_len, u8 ie) { const u8 *end, *pos; if (ies == NULL) return NULL; pos = ies; end = ies + ies_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == ie) return pos; pos += 2 + pos[1]; } return NULL; } static int capwap_scan_filtered(struct wpa_driver_capwap_data *drv, const u8 *ie, size_t ie_len) { const u8 *ssid; size_t i; if (drv->filter_ssids == NULL) return 0; ssid = capwap_get_ie(ie, ie_len, WLAN_EID_SSID); if (ssid == NULL) return 1; for (i = 0; i < drv->num_filter_ssids; i++) { if (ssid[1] == drv->filter_ssids[i].ssid_len && os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == 0) return 0; } return 1; } static int bss_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *bss[NL80211_BSS_MAX + 1]; static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, [NL80211_BSS_TSF] = { .type = NLA_U64 }, [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, }; struct capwap_bss_info_arg *_arg = arg; struct wpa_scan_results *res = _arg->res; struct wpa_scan_res **tmp; struct wpa_scan_res *r; const u8 *ie, *beacon_ie; size_t ie_len, beacon_ie_len; u8 *pos; size_t i; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_BSS]) return NL_SKIP; if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) return NL_SKIP; if (bss[NL80211_BSS_STATUS]) { enum nl80211_bss_status status; status = nla_get_u32(bss[NL80211_BSS_STATUS]); if (status == NL80211_BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_FREQUENCY]) { _arg->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); wpa_printf(MSG_DEBUG, "capwap: Associated on %u MHz", _arg->assoc_freq); } if (status == NL80211_BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_BSSID]) { os_memcpy(_arg->assoc_bssid, nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); wpa_printf(MSG_DEBUG, "capwap: Associated with " MACSTR, MAC2STR(_arg->assoc_bssid)); } } if (!res) return NL_SKIP; if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); } else { ie = NULL; ie_len = 0; } if (bss[NL80211_BSS_BEACON_IES]) { beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); } else { beacon_ie = NULL; beacon_ie_len = 0; } if (capwap_scan_filtered(_arg->drv, ie ? ie : beacon_ie, ie ? ie_len : beacon_ie_len)) return NL_SKIP; r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); if (r == NULL) return NL_SKIP; if (bss[NL80211_BSS_BSSID]) os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); if (bss[NL80211_BSS_FREQUENCY]) r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); if (bss[NL80211_BSS_BEACON_INTERVAL]) r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); if (bss[NL80211_BSS_CAPABILITY]) r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); r->flags |= WPA_SCAN_NOISE_INVALID; if (bss[NL80211_BSS_SIGNAL_MBM]) { r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); r->level /= 100; /* mBm to dBm */ r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); r->flags |= WPA_SCAN_QUAL_INVALID; } else r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; if (bss[NL80211_BSS_TSF]) r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); if (bss[NL80211_BSS_SEEN_MS_AGO]) r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); r->ie_len = ie_len; pos = (u8 *) (r + 1); if (ie) { os_memcpy(pos, ie, ie_len); pos += ie_len; } r->beacon_ie_len = beacon_ie_len; if (beacon_ie) os_memcpy(pos, beacon_ie, beacon_ie_len); if (bss[NL80211_BSS_STATUS]) { enum nl80211_bss_status status; status = nla_get_u32(bss[NL80211_BSS_STATUS]); switch (status) { case NL80211_BSS_STATUS_AUTHENTICATED: r->flags |= WPA_SCAN_AUTHENTICATED; break; case NL80211_BSS_STATUS_ASSOCIATED: r->flags |= WPA_SCAN_ASSOCIATED; break; default: break; } } /* * cfg80211 maintains separate BSS table entries for APs if the same * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does * not use frequency as a separate key in the BSS table, so filter out * duplicated entries. Prefer associated BSS entry in such a case in * order to get the correct frequency into the BSS table. */ for (i = 0; i < res->num; i++) { const u8 *s1, *s2; if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0) continue; s1 = capwap_get_ie((u8 *) (res->res[i] + 1), res->res[i]->ie_len, WLAN_EID_SSID); s2 = capwap_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID); if (s1 == NULL || s2 == NULL || s1[1] != s2[1] || os_memcmp(s1, s2, 2 + s1[1]) != 0) continue; /* Same BSSID,SSID was already included in scan results */ wpa_printf(MSG_DEBUG, "capwap: Remove duplicated scan result " "for " MACSTR, MAC2STR(r->bssid)); if ((r->flags & WPA_SCAN_ASSOCIATED) && !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) { os_free(res->res[i]); res->res[i] = r; } else os_free(r); return NL_SKIP; } tmp = os_realloc(res->res, (res->num + 1) * sizeof(struct wpa_scan_res *)); if (tmp == NULL) { os_free(r); return NL_SKIP; } tmp[res->num++] = r; res->res = tmp; return NL_SKIP; } static void clear_state_mismatch(struct wpa_driver_capwap_data *drv, const u8 *addr) { if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { wpa_printf(MSG_DEBUG, "capwap: Clear possible state " "mismatch (" MACSTR ")", MAC2STR(addr)); wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, WLAN_REASON_PREV_AUTH_NOT_VALID, 1); } } static void wpa_driver_capwap_check_bss_status( struct wpa_driver_capwap_data *drv, struct wpa_scan_results *res) { size_t i; for (i = 0; i < res->num; i++) { struct wpa_scan_res *r = res->res[i]; if (r->flags & WPA_SCAN_AUTHENTICATED) { wpa_printf(MSG_DEBUG, "capwap: Scan results " "indicates BSS status with " MACSTR " as authenticated", MAC2STR(r->bssid)); if (is_sta_interface(drv->nlmode) && os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "capwap: Unknown BSSID" " in local state (auth=" MACSTR " assoc=" MACSTR ")", MAC2STR(drv->auth_bssid), MAC2STR(drv->bssid)); clear_state_mismatch(drv, r->bssid); } } if (r->flags & WPA_SCAN_ASSOCIATED) { wpa_printf(MSG_DEBUG, "capwap: Scan results " "indicate BSS status with " MACSTR " as associated", MAC2STR(r->bssid)); if (is_sta_interface(drv->nlmode) && !drv->associated) { wpa_printf(MSG_DEBUG, "capwap: Local state " "(not associated) does not match " "with BSS state"); clear_state_mismatch(drv, r->bssid); } else if (is_sta_interface(drv->nlmode) && os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "capwap: Local state " "(associated with " MACSTR ") does " "not match with BSS state", MAC2STR(drv->bssid)); clear_state_mismatch(drv, r->bssid); clear_state_mismatch(drv, drv->bssid); } } } } static struct wpa_scan_results * capwap_get_scan_results(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; struct wpa_scan_results *res; int ret; struct capwap_bss_info_arg arg; res = os_zalloc(sizeof(*res)); if (res == NULL) return NULL; msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; arg.res = res; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "capwap: Received scan results (%lu " "BSSes)", (unsigned long) res->num); capwap_get_noise_for_scan_results(drv, res); return res; } wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); wpa_scan_results_free(res); return NULL; } /** * wpa_driver_capwap_get_scan_results - Fetch the latest scan results * @priv: Pointer to private wext data from wpa_driver_capwap_init() * Returns: Scan results on success, -1 on failure */ static struct wpa_scan_results * wpa_driver_capwap_get_scan_results(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct wpa_scan_results *res; res = capwap_get_scan_results(drv); if (res) wpa_driver_capwap_check_bss_status(drv, res); return res; } static void capwap_dump_scan(struct wpa_driver_capwap_data *drv) { struct wpa_scan_results *res; size_t i; res = capwap_get_scan_results(drv); if (res == NULL) { wpa_printf(MSG_DEBUG, "capwap: Failed to get scan results"); return; } wpa_printf(MSG_DEBUG, "capwap: Scan result dump"); for (i = 0; i < res->num; i++) { struct wpa_scan_res *r = res->res[i]; wpa_printf(MSG_DEBUG, "capwap: %d/%d " MACSTR "%s%s", (int) i, (int) res->num, MAC2STR(r->bssid), r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "", r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); } wpa_scan_results_free(res); } static int wpa_driver_capwap_set_key(const char *ifname, void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ifindex = if_nametoindex(ifname); struct nl_msg *msg; int ret; wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d " "set_tx=%d seq_len=%lu key_len=%lu", __func__, ifindex, alg, addr, key_idx, set_tx, (unsigned long) seq_len, (unsigned long) key_len); #ifdef CONFIG_TDLS if (key_idx == -1) key_idx = 0; #endif /* CONFIG_TDLS */ msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (alg == WPA_ALG_NONE) { capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY); } else { capwap_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); switch (alg) { case WPA_ALG_WEP: if (key_len == 5) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP104); break; case WPA_ALG_TKIP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); break; case WPA_ALG_CCMP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); break; case WPA_ALG_IGTK: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, WLAN_CIPHER_SUITE_AES_CMAC); break; default: wpa_printf(MSG_ERROR, "%s: Unsupported encryption " "algorithm %d", __func__, alg); nlmsg_free(msg); return -1; } } if (seq && seq_len) NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq); if (addr && !is_broadcast_ether_addr(addr)) { wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); if (alg != WPA_ALG_WEP && key_idx && !set_tx) { wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK"); NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, NL80211_KEYTYPE_GROUP); } } else if (addr && is_broadcast_ether_addr(addr)) { struct nl_msg *types; int err; wpa_printf(MSG_DEBUG, " broadcast key"); types = nlmsg_alloc(); if (!types) goto nla_put_failure; NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, types); nlmsg_free(types); if (err) goto nla_put_failure; } NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) ret = 0; if (ret) wpa_printf(MSG_DEBUG, "capwap: set_key failed; err=%d %s)", ret, strerror(-ret)); /* * If we failed or don't need to set the default TX key (below), * we're done here. */ if (ret || !set_tx || alg == WPA_ALG_NONE) return ret; if (is_ap_interface(drv->nlmode) && addr && !is_broadcast_ether_addr(addr)) return ret; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_KEY); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (alg == WPA_ALG_IGTK) NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); else NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); if (addr && is_broadcast_ether_addr(addr)) { struct nl_msg *types; int err; types = nlmsg_alloc(); if (!types) goto nla_put_failure; NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, types); nlmsg_free(types); if (err) goto nla_put_failure; } else if (addr) { struct nl_msg *types; int err; types = nlmsg_alloc(); if (!types) goto nla_put_failure; NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST); err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, types); nlmsg_free(types); if (err) goto nla_put_failure; } ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret == -ENOENT) ret = 0; if (ret) wpa_printf(MSG_DEBUG, "capwap: set_key default failed; " "err=%d %s)", ret, strerror(-ret)); return ret; nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, int key_idx, int defkey, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); if (!key_attr) return -1; if (defkey && alg == WPA_ALG_IGTK) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT); else if (defkey) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); switch (alg) { case WPA_ALG_WEP: if (key_len == 5) NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP104); break; case WPA_ALG_TKIP: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); break; case WPA_ALG_CCMP: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); break; case WPA_ALG_IGTK: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_AES_CMAC); break; default: wpa_printf(MSG_ERROR, "%s: Unsupported encryption " "algorithm %d", __func__, alg); return -1; } if (seq && seq_len) NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); NLA_PUT(msg, NL80211_KEY_DATA, key_len, key); nla_nest_end(msg, key_attr); return 0; nla_put_failure: return -1; } static int capwap_set_conn_keys(struct wpa_driver_associate_params *params, struct nl_msg *msg) { int i, privacy = 0; struct nlattr *nl_keys, *nl_key; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; privacy = 1; break; } if (params->wps == WPS_MODE_PRIVACY) privacy = 1; if (params->pairwise_suite && params->pairwise_suite != WPA_CIPHER_NONE) privacy = 1; if (!privacy) return 0; NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS); if (!nl_keys) goto nla_put_failure; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; nl_key = nla_nest_start(msg, i); if (!nl_key) goto nla_put_failure; NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i], params->wep_key[i]); if (params->wep_key_len[i] == 5) NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_WEP104); NLA_PUT_U8(msg, NL80211_KEY_IDX, i); if (i == params->wep_tx_keyidx) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); nla_nest_end(msg, nl_key); } nla_nest_end(msg, nl_keys); return 0; nla_put_failure: return -ENOBUFS; } static int wpa_driver_capwap_mlme(struct wpa_driver_capwap_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change) { int ret = -1; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); if (local_state_change) NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); goto nla_put_failure; } ret = 0; nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_disconnect(struct wpa_driver_capwap_data *drv, const u8 *addr, int reason_code) { wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", __func__, MAC2STR(addr), reason_code); drv->associated = 0; return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DISCONNECT, reason_code, 0); } static int wpa_driver_capwap_deauthenticate(void *priv, const u8 *addr, int reason_code) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) return wpa_driver_capwap_disconnect(drv, addr, reason_code); wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", __func__, MAC2STR(addr), reason_code); drv->associated = 0; if (drv->nlmode == NL80211_IFTYPE_ADHOC) return capwap_leave_ibss(drv); return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, reason_code, 0); } static int wpa_driver_capwap_disassociate(void *priv, const u8 *addr, int reason_code) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) return wpa_driver_capwap_disconnect(drv, addr, reason_code); wpa_printf(MSG_DEBUG, "%s", __func__); drv->associated = 0; return wpa_driver_capwap_mlme(drv, addr, NL80211_CMD_DISASSOCIATE, reason_code, 0); } static int wpa_driver_capwap_authenticate( void *priv, struct wpa_driver_auth_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1, i; struct nl_msg *msg; enum nl80211_auth_type type; enum nl80211_iftype nlmode; int count = 0; drv->associated = 0; os_memset(drv->auth_bssid, 0, ETH_ALEN); /* FIX: IBSS mode */ nlmode = params->p2p ? NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; if (drv->nlmode != nlmode && wpa_driver_capwap_set_mode(priv, nlmode) < 0) return -1; retry: msg = nlmsg_alloc(); if (!msg) return -1; wpa_printf(MSG_DEBUG, "capwap: Authenticate (ifindex=%d)", drv->ifindex); capwap_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE); for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; wpa_driver_capwap_set_key(bss->ifname, priv, WPA_ALG_WEP, NULL, i, i == params->wep_tx_keyidx, NULL, 0, params->wep_key[i], params->wep_key_len[i]); if (params->wep_tx_keyidx != i) continue; if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, params->wep_key[i], params->wep_key_len[i])) { nlmsg_free(msg); return -1; } } NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); } if (ac_params.ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", ac_params.ssid, ac_params.ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, ac_params.ssid_len, ac_params.ssid); } wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len); if (params->ie) NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie); if (params->auth_alg & WPA_AUTH_ALG_OPEN) type = NL80211_AUTHTYPE_OPEN_SYSTEM; else if (params->auth_alg & WPA_AUTH_ALG_SHARED) type = NL80211_AUTHTYPE_SHARED_KEY; else if (params->auth_alg & WPA_AUTH_ALG_LEAP) type = NL80211_AUTHTYPE_NETWORK_EAP; else if (params->auth_alg & WPA_AUTH_ALG_FT) type = NL80211_AUTHTYPE_FT; else goto nla_put_failure; wpa_printf(MSG_DEBUG, " * Auth Type %d", type); NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); if (params->local_state_change) { wpa_printf(MSG_DEBUG, " * Local state change only"); NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); count++; if (ret == -EALREADY && count == 1 && params->bssid && !params->local_state_change) { /* * mac80211 does not currently accept new * authentication if we are already authenticated. As a * workaround, force deauthentication and try again. */ wpa_printf(MSG_DEBUG, "capwap: Retry authentication " "after forced deauthentication"); wpa_driver_capwap_deauthenticate( bss, params->bssid, WLAN_REASON_PREV_AUTH_NOT_VALID); nlmsg_free(msg); goto retry; } goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Authentication request send " "successfully"); nla_put_failure: nlmsg_free(msg); return ret; } struct phy_info_arg { u16 *num_modes; struct hostapd_hw_modes *modes; }; static int phy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct phy_info_arg *phy_info = arg; struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, }; struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, }; struct nlattr *nl_band; struct nlattr *nl_freq; struct nlattr *nl_rate; int rem_band, rem_freq, rem_rate; struct hostapd_hw_modes *mode; int idx, mode_is_set; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) return NL_SKIP; nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); if (!mode) return NL_SKIP; phy_info->modes = mode; mode_is_set = 0; mode = &phy_info->modes[*(phy_info->num_modes)]; memset(mode, 0, sizeof(*mode)); mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN; *(phy_info->num_modes) += 1; nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { mode->ht_capab = nla_get_u16( tb_band[NL80211_BAND_ATTR_HT_CAPA]); } if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { mode->a_mpdu_params |= nla_get_u8( tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) & 0x03; } if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { mode->a_mpdu_params |= nla_get_u8( tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) << 2; } if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) { u8 *mcs; mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); os_memcpy(mode->mcs_set, mcs, 16); } nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; mode->num_channels++; } mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data)); if (!mode->channels) return NL_SKIP; idx = 0; nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); mode->channels[idx].flag = 0; if (!mode_is_set) { /* crude heuristic */ if (mode->channels[idx].freq < 4000) mode->mode = HOSTAPD_MODE_IEEE80211B; else mode->mode = HOSTAPD_MODE_IEEE80211A; mode_is_set = 1; } /* crude heuristic */ if (mode->channels[idx].freq < 4000) if (mode->channels[idx].freq == 2484) mode->channels[idx].chan = 14; else mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; else mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) mode->channels[idx].flag |= HOSTAPD_CHAN_DISABLED; if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) mode->channels[idx].flag |= HOSTAPD_CHAN_PASSIVE_SCAN; if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) mode->channels[idx].flag |= HOSTAPD_CHAN_NO_IBSS; if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) mode->channels[idx].flag |= HOSTAPD_CHAN_RADAR; if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) mode->channels[idx].max_tx_power = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100; idx++; } nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; mode->num_rates++; } mode->rates = os_zalloc(mode->num_rates * sizeof(int)); if (!mode->rates) return NL_SKIP; idx = 0; nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); /* crude heuristic */ if (mode->mode == HOSTAPD_MODE_IEEE80211B && mode->rates[idx] > 200) mode->mode = HOSTAPD_MODE_IEEE80211G; idx++; } } return NL_SKIP; } static struct hostapd_hw_modes * wpa_driver_capwap_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes) { u16 m; struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; int i, mode11g_idx = -1; /* If only 802.11g mode is included, use it to construct matching * 802.11b mode data. */ for (m = 0; m < *num_modes; m++) { if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) return modes; /* 802.11b already included */ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) mode11g_idx = m; } if (mode11g_idx < 0) return modes; /* 2.4 GHz band not supported at all */ nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes)); if (nmodes == NULL) return modes; /* Could not add 802.11b mode */ mode = &nmodes[*num_modes]; os_memset(mode, 0, sizeof(*mode)); (*num_modes)++; modes = nmodes; mode->mode = HOSTAPD_MODE_IEEE80211B; mode11g = &modes[mode11g_idx]; mode->num_channels = mode11g->num_channels; mode->channels = os_malloc(mode11g->num_channels * sizeof(struct hostapd_channel_data)); if (mode->channels == NULL) { (*num_modes)--; return modes; /* Could not add 802.11b mode */ } os_memcpy(mode->channels, mode11g->channels, mode11g->num_channels * sizeof(struct hostapd_channel_data)); mode->num_rates = 0; mode->rates = os_malloc(4 * sizeof(int)); if (mode->rates == NULL) { os_free(mode->channels); (*num_modes)--; return modes; /* Could not add 802.11b mode */ } for (i = 0; i < mode11g->num_rates; i++) { if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && mode11g->rates[i] != 55 && mode11g->rates[i] != 110) continue; mode->rates[mode->num_rates] = mode11g->rates[i]; mode->num_rates++; if (mode->num_rates == 4) break; } if (mode->num_rates == 0) { os_free(mode->channels); os_free(mode->rates); (*num_modes)--; return modes; /* No 802.11b rates */ } wpa_printf(MSG_DEBUG, "capwap: Added 802.11b mode based on 802.11g " "information"); return modes; } static void capwap_set_ht40_mode(struct hostapd_hw_modes *mode, int start, int end) { int c; for (c = 0; c < mode->num_channels; c++) { struct hostapd_channel_data *chan = &mode->channels[c]; if (chan->freq - 10 >= start && chan->freq + 10 <= end) chan->flag |= HOSTAPD_CHAN_HT40; } } static void capwap_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, int end) { int c; for (c = 0; c < mode->num_channels; c++) { struct hostapd_channel_data *chan = &mode->channels[c]; if (!(chan->flag & HOSTAPD_CHAN_HT40)) continue; if (chan->freq - 30 >= start && chan->freq - 10 <= end) chan->flag |= HOSTAPD_CHAN_HT40MINUS; if (chan->freq + 10 >= start && chan->freq + 30 <= end) chan->flag |= HOSTAPD_CHAN_HT40PLUS; } } static void capwap_reg_rule_ht40(struct nlattr *tb[], struct phy_info_arg *results) { u32 start, end, max_bw; u16 m; if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) return; start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; wpa_printf(MSG_DEBUG, "capwap: %u-%u @ %u MHz", start, end, max_bw); if (max_bw < 40) return; for (m = 0; m < *results->num_modes; m++) { if (!(results->modes[m].ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) continue; capwap_set_ht40_mode(&results->modes[m], start, end); } } static void capwap_reg_rule_sec(struct nlattr *tb[], struct phy_info_arg *results) { u32 start, end, max_bw; u16 m; if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) return; start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; if (max_bw < 20) return; for (m = 0; m < *results->num_modes; m++) { if (!(results->modes[m].ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) continue; capwap_set_ht40_mode_sec(&results->modes[m], start, end); } } static int capwap_get_reg(struct nl_msg *msg, void *arg) { struct phy_info_arg *results = arg; struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *nl_rule; struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1]; int rem_rule; static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, }; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb_msg[NL80211_ATTR_REG_ALPHA2] || !tb_msg[NL80211_ATTR_REG_RULES]) { wpa_printf(MSG_DEBUG, "capwap: No regulatory information " "available"); return NL_SKIP; } wpa_printf(MSG_DEBUG, "capwap: Regulatory information - country=%s", (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2])); nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) { nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_rule), nla_len(nl_rule), reg_policy); capwap_reg_rule_ht40(tb_rule, results); } nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) { nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_rule), nla_len(nl_rule), reg_policy); capwap_reg_rule_sec(tb_rule, results); } return NL_SKIP; } static int capwap_set_ht40_flags(struct wpa_driver_capwap_data *drv, struct phy_info_arg *results) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_REG); return send_and_recv_msgs(drv, msg, capwap_get_reg, results); } static struct hostapd_hw_modes * wpa_driver_capwap_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_get_hw_feature_data \n"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct phy_info_arg result = { .num_modes = num_modes, .modes = NULL, }; *num_modes = 0; *flags = 0; msg = nlmsg_alloc(); if (!msg) return NULL; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) { capwap_set_ht40_flags(drv, &result); return wpa_driver_capwap_add_11b(result.modes, num_modes); } msg = NULL; nla_put_failure: nlmsg_free(msg); return NULL; } int wpa_driver_capwap_send_frame(struct wpa_driver_capwap_data *drv,const void *data, size_t len,int encrypt) { __u8 rtap_hdr[] = { 0x00, 0x00, /* radiotap version */ 0x0e, 0x00, /* radiotap length */ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ 0x00, /* padding */ 0x00, 0x00, /* RX and TX flags to indicate that */ 0x00, 0x00, /* this is the injected frame directly */ }; struct iovec iov[2] = { { .iov_base = &rtap_hdr, .iov_len = sizeof(rtap_hdr), }, { .iov_base = (void *) data, .iov_len = len, } }; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, .msg_iov = iov, .msg_iovlen = 2, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0, }; int res; if (encrypt) rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; if (drv->monitor_sock < 0) { wpa_printf(MSG_DEBUG, "capwap: No monitor socket available " "for %s", __func__); return -1; } res = sendmsg(drv->monitor_sock, &msg, 0); if (res < 0) { wpa_printf(MSG_INFO, "capwap: sendmsg: %s", strerror(errno)); return -1; } return 0; } static int wpa_driver_capwap_send_mlme(void *priv, const u8 *data, size_t data_len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct ieee80211_mgmt *mgmt; int encrypt = 1; u16 fc; mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); if (is_sta_interface(drv->nlmode) && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { /* * The use of last_mgmt_freq is a bit of a hack, * but it works due to the single-threaded nature * of wpa_supplicant. */ return capwap_send_frame_cmd(drv, drv->last_mgmt_freq, 0, data, data_len, NULL, 1); } if (drv->no_monitor_iface_capab && is_ap_interface(drv->nlmode)) { return capwap_send_frame_cmd(drv, drv->ap_oper_freq, 0, data, data_len, &drv->send_action_cookie, 0); } if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { /* * Only one of the authentication frame types is encrypted. * In order for static WEP encryption to work properly (i.e., * to not encrypt the frame), we need to tell mac80211 about * the frames that must not be encrypted. */ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) encrypt = 0; } return wpa_driver_capwap_send_frame(drv, data, data_len, encrypt); } static int capwap_set_ap_isolate(struct i802_bss *bss, int enabled) { struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, enabled); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: return -ENOBUFS; } static int capwap_set_bss(struct i802_bss *bss, int cts, int preamble, int slot, int ht_opmode) { wpa_printf(MSG_DEBUG,"> capwap_set_bss\n"); struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); if (cts >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); if (preamble >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); if (slot >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); if (ht_opmode >= 0) NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int wpa_driver_capwap_set_ap(void *priv, struct wpa_driver_ap_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; u8 cmd = NL80211_CMD_NEW_BEACON; int ret; int beacon_set; int ifindex = if_nametoindex(bss->ifname); int num_suites; u32 suites[10]; u32 ver; drv->mac_mode = params->mac_mode; beacon_set = bss->beacon_set; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; wpa_printf(MSG_DEBUG, "capwap: Set beacon (beacon_set=%d)", beacon_set); if (beacon_set) cmd = NL80211_CMD_SET_BEACON; capwap_cmd(drv, msg, 0, cmd); NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head); NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int); NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period); NLA_PUT(msg, NL80211_ATTR_SSID, ac_params.ssid_len, ac_params.ssid); switch (params->hide_ssid) { case NO_SSID_HIDING: NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, NL80211_HIDDEN_SSID_NOT_IN_USE); break; case HIDDEN_SSID_ZERO_LEN: NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, NL80211_HIDDEN_SSID_ZERO_LEN); break; case HIDDEN_SSID_ZERO_CONTENTS: NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, NL80211_HIDDEN_SSID_ZERO_CONTENTS); break; } if (params->privacy) NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { /* Leave out the attribute */ } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_SHARED_KEY); else NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_OPEN_SYSTEM); ver = 0; if (params->wpa_version & WPA_PROTO_WPA) ver |= NL80211_WPA_VERSION_1; if (params->wpa_version & WPA_PROTO_RSN) ver |= NL80211_WPA_VERSION_2; if (ver) NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); num_suites = 0; if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X) suites[num_suites++] = WLAN_AKM_SUITE_8021X; if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK) suites[num_suites++] = WLAN_AKM_SUITE_PSK; if (num_suites) { NLA_PUT(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), suites); } num_suites = 0; if (params->pairwise_ciphers & WPA_CIPHER_CCMP) suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; if (params->pairwise_ciphers & WPA_CIPHER_TKIP) suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; if (params->pairwise_ciphers & WPA_CIPHER_WEP104) suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; if (params->pairwise_ciphers & WPA_CIPHER_WEP40) suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; if (num_suites) { NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, num_suites * sizeof(u32), suites); } switch (params->group_cipher) { case WPA_CIPHER_CCMP: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_CCMP); break; case WPA_CIPHER_TKIP: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_TKIP); break; case WPA_CIPHER_WEP104: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_WEP104); break; case WPA_CIPHER_WEP40: NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLAN_CIPHER_SUITE_WEP40); break; } if (params->beacon_ies) { NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies), wpabuf_head(params->beacon_ies)); } if (params->proberesp_ies) { NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP, wpabuf_len(params->proberesp_ies), wpabuf_head(params->proberesp_ies)); } if (params->assocresp_ies) { NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP, wpabuf_len(params->assocresp_ies), wpabuf_head(params->assocresp_ies)); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "capwap: Beacon set failed: %d (%s)", ret, strerror(-ret)); } else { bss->beacon_set = 0; ret = capwap_set_ap_isolate(bss, params->isolate); if (!params->isolate && ret) { wpa_printf(MSG_DEBUG, "capwap: Ignore AP isolation " "configuration error since isolation is " "not used"); ret = 0; } capwap_set_bss(bss, params->cts_protect, params->preamble, params->short_slot_time, params->ht_opmode); } return ret; nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int wpa_driver_capwap_set_freq(struct wpa_driver_capwap_data *drv, int freq, int ht_enabled, int sec_channel_offset) { wpa_printf(MSG_DEBUG," 1.wpa_driver_capwap_set_freq\n"); struct nl_msg *msg; int ret; wpa_printf(MSG_DEBUG, "capwap: Set freq %d (ht_enabled=%d " "sec_channel_offset=%d)", freq, ht_enabled, sec_channel_offset); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); if (ht_enabled) { switch (sec_channel_offset) { case -1: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS); break; case 1: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS); break; default: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); break; } } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "capwap: Failed to set channel (freq=%d): " "%d (%s)", freq, ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return -1; } static u32 sta_flags_capwap(int flags) { u32 f = 0; if (flags & WPA_STA_AUTHORIZED) f |= BIT(NL80211_STA_FLAG_AUTHORIZED); if (flags & WPA_STA_WMM) f |= BIT(NL80211_STA_FLAG_WME); if (flags & WPA_STA_SHORT_PREAMBLE) f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); if (flags & WPA_STA_MFP) f |= BIT(NL80211_STA_FLAG_MFP); if (flags & WPA_STA_TDLS_PEER) f |= BIT(NL80211_STA_FLAG_TDLS_PEER); return f; } static int wpa_driver_capwap_sta_add(void *priv, struct hostapd_sta_add_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct nl80211_sta_flag_update upd; int ret = -ENOBUFS; if ((params->flags & WPA_STA_TDLS_PEER) && !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION : NL80211_CMD_NEW_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,params->supp_rates); if (!params->set) { NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, params->listen_interval); } if (params->ht_capabilities) { NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sizeof(*params->ht_capabilities), params->ht_capabilities); } os_memset(&upd, 0, sizeof(upd)); upd.mask = sta_flags_capwap(params->flags); upd.set = upd.mask; NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) wpa_printf(MSG_DEBUG, "capwap: NL80211_CMD_%s_STATION " "result: %d (%s)", params->set ? "SET" : "NEW", ret, strerror(-ret)); if (ret == -EEXIST) ret = 0; nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_sta_remove(void *priv, const u8 *addr) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret == -ENOENT) return 0; return ret; nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static void capwap_remove_iface(struct wpa_driver_capwap_data *drv, int ifidx) { struct nl_msg *msg; wpa_printf(MSG_DEBUG, "capwap: Remove interface ifindex=%d", ifidx); /* stop listening for EAPOL on this interface */ del_ifidx(drv, ifidx); msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return; msg = NULL; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); } static const char * nl80211_iftype_str(enum nl80211_iftype mode) { switch (mode) { case NL80211_IFTYPE_ADHOC: return "ADHOC"; case NL80211_IFTYPE_STATION: return "STATION"; case NL80211_IFTYPE_AP: return "AP"; case NL80211_IFTYPE_MONITOR: return "MONITOR"; case NL80211_IFTYPE_P2P_CLIENT: return "P2P_CLIENT"; case NL80211_IFTYPE_P2P_GO: return "P2P_GO"; default: return "unknown"; } } static int capwap_create_iface_once(struct wpa_driver_capwap_data *drv, const char *ifname, enum nl80211_iftype iftype, const u8 *addr, int wds) { struct nl_msg *msg, *flags = NULL; int ifidx; int ret = -ENOBUFS; wpa_printf(MSG_DEBUG, "capwap: Create interface iftype %d (%s)", iftype, nl80211_iftype_str(iftype)); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); if (iftype == NL80211_IFTYPE_MONITOR) { int err; flags = nlmsg_alloc(); if (!flags) goto nla_put_failure; NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); nlmsg_free(flags); if (err) goto nla_put_failure; } else if (wds) { NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", ifname, ret, strerror(-ret)); return ret; } ifidx = if_nametoindex(ifname); wpa_printf(MSG_DEBUG, "capwap: New interface %s created: ifindex=%d", ifname, ifidx); if (ifidx <= 0) return -1; /* start listening for EAPOL on this interface */ wpa_printf(MSG_DEBUG, "start listening for EAPOL on this interface\n"); add_ifidx(drv, ifidx); if (addr && iftype != NL80211_IFTYPE_MONITOR && linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) { capwap_remove_iface(drv, ifidx); return -1; } return ifidx; } static int capwap_create_iface(struct wpa_driver_capwap_data *drv, const char *ifname, enum nl80211_iftype iftype, const u8 *addr, int wds) { int ret; ret = capwap_create_iface_once(drv, ifname, iftype, addr, wds); /* if error occurred and interface exists already */ if (ret == -ENFILE && if_nametoindex(ifname)) { wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); /* Try to remove the interface that was already there. */ capwap_remove_iface(drv, if_nametoindex(ifname)); /* Try to create the interface again */ ret = capwap_create_iface_once(drv, ifname, iftype, addr, wds); } if (ret >= 0 && is_p2p_interface(iftype)) capwap_disable_11b_rates(drv, ret, 1); return ret; } static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) { struct ieee80211_hdr *hdr; u16 fc; union wpa_event_data event; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.tx_status.type = WLAN_FC_GET_TYPE(fc); event.tx_status.stype = WLAN_FC_GET_STYPE(fc); event.tx_status.dst = hdr->addr1; event.tx_status.data = buf; event.tx_status.data_len = len; event.tx_status.ack = ok; wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); } static void from_unknown_sta(struct wpa_driver_capwap_data *drv, u8 *buf, size_t len) { struct ieee80211_hdr *hdr = (void *)buf; u16 fc; union wpa_event_data event; if (len < sizeof(*hdr)) return; fc = le_to_host16(hdr->frame_control); os_memset(&event, 0, sizeof(event)); event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); event.rx_from_unknown.addr = hdr->addr2; event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) == (WLAN_FC_FROMDS | WLAN_FC_TODS); wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); } static void handle_frame(struct wpa_driver_capwap_data *drv, u8 *buf, size_t len, int datarate, int ssi_signal) { struct ieee80211_hdr *hdr; u16 fc; union wpa_event_data event; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); switch (WLAN_FC_GET_TYPE(fc)) { case WLAN_FC_TYPE_MGMT: os_memset(&event, 0, sizeof(event)); event.rx_mgmt.frame = buf; event.rx_mgmt.frame_len = len; event.rx_mgmt.datarate = datarate; event.rx_mgmt.ssi_signal = ssi_signal; wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); break; case WLAN_FC_TYPE_CTRL: /* can only get here with PS-Poll frames */ wpa_printf(MSG_DEBUG, "CTRL"); from_unknown_sta(drv, buf, len); break; case WLAN_FC_TYPE_DATA: from_unknown_sta(drv, buf, len); break; } } static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx){ struct wpa_driver_capwap_data *drv = eloop_ctx; int len; int close = 0; unsigned char buf[3000]; struct ieee80211_radiotap_iterator iter; int ret; int datarate = 0, ssi_signal = 0; int injected = 0, failed = 0, rxflags = 0; len = recv(sock, buf, sizeof(buf), 0); /* Scarto i pacchetti Beacon ricevutti */ if(buf[14]==0x80 )return;// Beacon Frame if (len < 0) { perror("recv"); return; } if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { wpa_printf(MSG_DEBUG, "received invalid radiotap frame\n"); return; } while (1) { ret = ieee80211_radiotap_iterator_next(&iter); if (ret == -ENOENT) break; if (ret) { wpa_printf(MSG_DEBUG, "received invalid radiotap frame (%d)\n", ret); return; } switch (iter.this_arg_index) { case IEEE80211_RADIOTAP_FLAGS: if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) len -= 4; break; case IEEE80211_RADIOTAP_RX_FLAGS: rxflags = 1; break; case IEEE80211_RADIOTAP_TX_FLAGS: injected = 1; failed = le_to_host16((*(uint16_t *) iter.this_arg)) & IEEE80211_RADIOTAP_F_TX_FAIL; break; case IEEE80211_RADIOTAP_DATA_RETRIES: break; case IEEE80211_RADIOTAP_CHANNEL: /* TODO: convert from freq/flags to channel number */ break; case IEEE80211_RADIOTAP_RATE: datarate = *iter.this_arg * 5; break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: ssi_signal = *iter.this_arg; break; } } if (rxflags && injected) return; struct ieee80211_hdr *hdr; u16 fc; hdr = (struct ieee80211_hdr *)(buf + iter.max_length); fc = le_to_host16(hdr->frame_control); switch (WLAN_FC_GET_TYPE(fc)) { case WLAN_FC_TYPE_DATA: wpa_printf(MSG_DEBUG, "EAPOL Data Frame 3 (%d)\n", len - iter.max_length); ipc_send_80211_to_ac(generic_wtp_info.fd_ipc, buf + iter.max_length,len - iter.max_length); return; case WLAN_FC_TYPE_MGMT: switch (WLAN_FC_GET_STYPE(fc)) { case WLAN_FC_STYPE_BEACON: /* TODO: why are beacon frames not forwarded to hostapd */ return; case WLAN_FC_STYPE_PROBE_REQ: case WLAN_FC_STYPE_PROBE_RESP: /* handled by hostapd */ break; case WLAN_FC_STYPE_ASSOC_REQ: case WLAN_FC_STYPE_REASSOC_REQ: /* always forward to AC */ ipc_send_80211_to_ac(generic_wtp_info.fd_ipc,buf + iter.max_length,len - iter.max_length); if (drv->mac_mode == CW_SPLIT_MAC) /* in Split MAC mode the AC handles the rest */ return; break; case WLAN_FC_STYPE_ASSOC_RESP: case WLAN_FC_STYPE_REASSOC_RESP: if (drv->mac_mode == CW_SPLIT_MAC) /* don't mirror responses back to the AC */ return; /* handled by hostapd in Local MAC Mode*/ break; case WLAN_FC_STYPE_AUTH: if (!injected) /* forward to AC */ ipc_send_80211_to_ac(generic_wtp_info.fd_ipc,buf + iter.max_length,len - iter.max_length); if (drv->mac_mode == CW_SPLIT_MAC) /* handled by hostapd in Local MAC Mode*/ return; break; default: // All other packet sent to AC ipc_send_80211_to_ac(generic_wtp_info.fd_ipc,buf + iter.max_length,len - iter.max_length); return; } break; default: wpa_printf(MSG_ERROR, "ERROR RECV CONTROLL TRAFIC on MONITOR INTERFACE"); return; } if (!injected) handle_frame(drv, buf + iter.max_length, len - iter.max_length, datarate, ssi_signal); else handle_tx_callback(drv->ctx, buf + iter.max_length, len - iter.max_length, !failed); if (drv->mac_mode == CW_SPLIT_MAC && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) ipc_send_80211_to_ac(generic_wtp_info.fd_ipc, buf + iter.max_length,len - iter.max_length); } /* * we post-process the filter code later and rewrite * this to the offset to the last instruction */ #define PASS 0xFF #define FAIL 0xFE static struct sock_filter msock_filter_insns[] = { /* * do a little-endian load of the radiotap length field */ /* load lower byte into A */ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), /* put it into X (== index register) */ BPF_STMT(BPF_MISC| BPF_TAX, 0), /* load upper byte into A */ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), /* left-shift it by 8 */ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), /* or with X */ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), /* put result into X */ BPF_STMT(BPF_MISC| BPF_TAX, 0), /* * Allow management frames through, this also gives us those * management frames that we sent ourselves with status */ /* load the lower byte of the IEEE 802.11 frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* mask off frame type and version */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), /* accept frame if it's both 0, fall through otherwise */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), /* * TODO: add a bit to radiotap RX flags that indicates * that the sending station is not associated, then * add a filter here that filters on our DA and that flag * to allow us to deauth frames to that bad station. * * For now allow all To DS data frames through. */ /* load the IEEE 802.11 frame control field */ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0), /* mask off frame type, version and DS status */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03), /* accept frame if version 0, type 2 and To DS, fall through otherwise */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0), #if 0 /* * drop non-data frames */ /* load the lower byte of the frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* mask off QoS bit */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), /* drop non-data frames */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), #endif /* load the upper byte of the frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), /* mask off toDS/fromDS */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), /* accept WDS frames */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), /* * add header length to index */ /* load the lower byte of the frame control field */ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* mask off QoS bit */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), /* right shift it by 6 to give 0 or 2 */ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), /* add data frame header length */ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), /* add index, was start of 802.11 header */ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), /* move to index, now start of LL header */ BPF_STMT(BPF_MISC | BPF_TAX, 0), /* * Accept empty data frames, we use those for * polling activity. */ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), /* * Accept EAPOL frames */ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), /* keep these last two statements or change the code below */ /* return 0 == "DROP" */ BPF_STMT(BPF_RET | BPF_K, 0), /* return ~0 == "keep all" */ BPF_STMT(BPF_RET | BPF_K, ~0), }; static struct sock_fprog msock_filter = { .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]), .filter = msock_filter_insns, }; static int add_monitor_filter(int s) { int idx; /* rewrite all PASS/FAIL jump offsets */ for (idx = 0; idx < msock_filter.len; idx++) { struct sock_filter *insn = &msock_filter_insns[idx]; if (BPF_CLASS(insn->code) == BPF_JMP) { if (insn->code == (BPF_JMP|BPF_JA)) { if (insn->k == PASS) insn->k = msock_filter.len - idx - 2; else if (insn->k == FAIL) insn->k = msock_filter.len - idx - 3; } if (insn->jt == PASS) insn->jt = msock_filter.len - idx - 2; else if (insn->jt == FAIL) insn->jt = msock_filter.len - idx - 3; if (insn->jf == PASS) insn->jf = msock_filter.len - idx - 2; else if (insn->jf == FAIL) insn->jf = msock_filter.len - idx - 3; } } if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &msock_filter, sizeof(msock_filter))) { perror("SO_ATTACH_FILTER"); return -1; } return 0; } static void capwap_remove_monitor_interface( struct wpa_driver_capwap_data *drv) { if (drv->monitor_ifidx >= 0) { capwap_remove_iface(drv, drv->monitor_ifidx); drv->monitor_ifidx = -1; } if (drv->monitor_sock >= 0) { eloop_unregister_read_sock(drv->monitor_sock); close(drv->monitor_sock); drv->monitor_sock = -1; } } static int capwap_create_monitor_interface(struct wpa_driver_capwap_data *drv){ wpa_printf(MSG_DEBUG, "8.5 capwap_create_monitor_interface\n"); char buf[IFNAMSIZ]; struct sockaddr_ll ll; int optval; socklen_t optlen; if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) { /* * P2P interface name is of the format p2p-%s-%d. For monitor * interface name corresponding to P2P GO, replace "p2p-" with * "mon-" to retain the same interface name length and to * indicate that it is a monitor interface. */ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4); } else { /* Non-P2P interface with AP functionality. */ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); } buf[IFNAMSIZ - 1] = '\0'; drv->monitor_ifidx = capwap_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, 0); if (drv->monitor_ifidx == -EOPNOTSUPP) { wpa_printf(MSG_DEBUG, "capwap: Driver does not support " "monitor interface type - try to run without it"); drv->no_monitor_iface_capab = 1; } if (drv->monitor_ifidx < 0) return -1; if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1)) goto error; memset(&ll, 0, sizeof(ll)); ll.sll_family = AF_PACKET; ll.sll_ifindex = drv->monitor_ifidx; drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (drv->monitor_sock < 0) { perror("socket[PF_PACKET,SOCK_RAW]"); goto error; } if (add_monitor_filter(drv->monitor_sock)) { wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " "interface; do filtering in user space"); /* This works, but will cost in performance. */ } if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { perror("monitor socket bind"); goto error; } optlen = sizeof(optval); optval = 20; if (setsockopt (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { perror("Failed to set socket priority"); goto error; } if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, drv, NULL)) { wpa_printf(MSG_DEBUG, "Could not register monitor read socket\n"); goto error; } return 0; error: capwap_remove_monitor_interface(drv); return -1; } #ifdef CONFIG_AP static int capwap_send_eapol_data(struct i802_bss *bss, const u8 *addr, const u8 *data, size_t data_len, const u8 *own_addr) { wpa_printf(MSG_DEBUG, "capwap_send_eapol_data\n"); if (bss->drv->l2 == NULL) { wpa_printf(MSG_DEBUG, "capwap: No l2_packet to send EAPOL"); return -1; } if (l2_packet_send(bss->drv->l2, addr, ETH_P_EAPOL, data, data_len) < 0) return -1; return 0; } #endif /* CONFIG_AP */ static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; static int wpa_driver_capwap_hapd_send_eapol( void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, const u8 *own_addr, u32 flags) { wpa_printf(MSG_DEBUG, "-------------- wpa_driver_capwap_hapd_send_eapol\n"); return 0; struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct ieee80211_hdr *hdr; size_t len; u8 *pos; int res; int qos = flags & WPA_STA_WMM; #ifdef CONFIG_AP if (drv->no_monitor_iface_capab) return capwap_send_eapol_data(bss, addr, data, data_len, own_addr); #endif /* CONFIG_AP */ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + data_len; hdr = os_zalloc(len); if (hdr == NULL) { wpa_printf(MSG_DEBUG, "malloc() failed for i802_send_data(len=%lu)\n", (unsigned long) len); return -1; } hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); if (encrypt) hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); if (qos) { hdr->frame_control |= host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); } memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); pos = (u8 *) (hdr + 1); if (qos) { /* add an empty QoS header if needed */ pos[0] = 0; pos[1] = 0; pos += 2; } memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); pos += sizeof(rfc1042_header); WPA_PUT_BE16(pos, ETH_P_PAE); pos += 2; memcpy(pos, data, data_len); res = wpa_driver_capwap_send_frame(drv, (u8 *) hdr, len, encrypt); if (res < 0) { wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " "failed: %d (%s)", (unsigned long) len, errno, strerror(errno)); } os_free(hdr); return res; } static int wpa_driver_capwap_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, int flags_and) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg, *flags = NULL; struct nl80211_sta_flag_update upd; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; flags = nlmsg_alloc(); if (!flags) { nlmsg_free(msg); return -ENOMEM; } capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); /* * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This * can be removed eventually. */ if (total_flags & WPA_STA_AUTHORIZED) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); if (total_flags & WPA_STA_WMM) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); if (total_flags & WPA_STA_SHORT_PREAMBLE) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); if (total_flags & WPA_STA_MFP) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); if (total_flags & WPA_STA_TDLS_PEER) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER); if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) goto nla_put_failure; os_memset(&upd, 0, sizeof(upd)); upd.mask = sta_flags_capwap(flags_or | ~flags_and); upd.set = sta_flags_capwap(flags_or); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); nlmsg_free(flags); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); nlmsg_free(flags); return -ENOBUFS; } static int wpa_driver_capwap_ap(struct wpa_driver_capwap_data *drv, struct wpa_driver_associate_params *params) { enum nl80211_iftype nlmode; if (params->p2p) { wpa_printf(MSG_DEBUG, "capwap: Setup AP operations for P2P " "group (GO)"); nlmode = NL80211_IFTYPE_P2P_GO; } else nlmode = NL80211_IFTYPE_AP; if (wpa_driver_capwap_set_mode(&drv->first_bss, nlmode) || wpa_driver_capwap_set_freq(drv, params->freq, 0, 0)) { capwap_remove_monitor_interface(drv); return -1; } if (drv->no_monitor_iface_capab) { if (wpa_driver_capwap_probe_req_report(&drv->first_bss, 1) < 0) { wpa_printf(MSG_DEBUG, "capwap: Failed to enable " "Probe Request frame reporting in AP mode"); /* Try to survive without this */ } } drv->ap_oper_freq = params->freq; return 0; } static int capwap_leave_ibss(struct wpa_driver_capwap_data *drv) { struct nl_msg *msg; int ret = -1; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Leave IBSS failed: ret=%d " "(%s)", ret, strerror(-ret)); goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Leave IBSS request sent successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_ibss(struct wpa_driver_capwap_data *drv, struct wpa_driver_associate_params *params) { struct nl_msg *msg; int ret = -1; int count = 0; wpa_printf(MSG_DEBUG, "capwap: Join IBSS (ifindex=%d)", drv->ifindex); if (wpa_driver_capwap_set_mode(&drv->first_bss, NL80211_IFTYPE_ADHOC)) { wpa_printf(MSG_INFO, "capwap: Failed to set interface into " "IBSS mode"); return -1; } retry: msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (ac_params.ssid == NULL || ac_params.ssid_len > sizeof(drv->ssid)) goto nla_put_failure; wpa_hexdump_ascii(MSG_DEBUG, " * SSID", ac_params.ssid, ac_params.ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, ac_params.ssid_len, ac_params.ssid); os_memcpy(drv->ssid, ac_params.ssid, ac_params.ssid_len); drv->ssid_len = ac_params.ssid_len; wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); ret = capwap_set_conn_keys(params, msg); if (ret) goto nla_put_failure; if (params->wpa_ie) { wpa_hexdump(MSG_DEBUG, " * Extra IEs for Beacon/Probe Response frames", params->wpa_ie, params->wpa_ie_len); NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Join IBSS failed: ret=%d (%s)", ret, strerror(-ret)); count++; if (ret == -EALREADY && count == 1) { wpa_printf(MSG_DEBUG, "capwap: Retry IBSS join after " "forced leave"); capwap_leave_ibss(drv); nlmsg_free(msg); goto retry; } goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Join IBSS request sent successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static unsigned int capwap_get_assoc_bssid(struct wpa_driver_capwap_data *drv, u8 *bssid) { struct nl_msg *msg; int ret; struct capwap_bss_info_arg arg; os_memset(&arg, 0, sizeof(arg)); msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; capwap_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { if (is_zero_ether_addr(arg.assoc_bssid)) return -ENOTCONN; os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN); return 0; } wpa_printf(MSG_DEBUG, "capwap: Scan result fetch failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return drv->assoc_freq; } static int capwap_disconnect(struct wpa_driver_capwap_data *drv, const u8 *bssid) { u8 addr[ETH_ALEN]; if (bssid == NULL) { int res = capwap_get_assoc_bssid(drv, addr); if (res) return res; bssid = addr; } return wpa_driver_capwap_disconnect(drv, bssid, WLAN_REASON_PREV_AUTH_NOT_VALID); } static int wpa_driver_capwap_connect( struct wpa_driver_capwap_data *drv, struct wpa_driver_associate_params *params) { struct nl_msg *msg; enum nl80211_auth_type type; int ret = 0; int algs; msg = nlmsg_alloc(); if (!msg) return -1; wpa_printf(MSG_DEBUG, "capwap: Connect (ifindex=%d)", drv->ifindex); capwap_cmd(drv, msg, 0, NL80211_CMD_CONNECT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); } if (ac_params.ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", ac_params.ssid, ac_params.ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, ac_params.ssid_len, ac_params.ssid); if (ac_params.ssid_len > sizeof(drv->ssid)) goto nla_put_failure; os_memcpy(drv->ssid, ac_params.ssid, ac_params.ssid_len); drv->ssid_len = ac_params.ssid_len; } wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); if (params->wpa_ie) NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); algs = 0; if (params->auth_alg & WPA_AUTH_ALG_OPEN) algs++; if (params->auth_alg & WPA_AUTH_ALG_SHARED) algs++; if (params->auth_alg & WPA_AUTH_ALG_LEAP) algs++; if (algs > 1) { wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " "selection"); goto skip_auth_type; } if (params->auth_alg & WPA_AUTH_ALG_OPEN) type = NL80211_AUTHTYPE_OPEN_SYSTEM; else if (params->auth_alg & WPA_AUTH_ALG_SHARED) type = NL80211_AUTHTYPE_SHARED_KEY; else if (params->auth_alg & WPA_AUTH_ALG_LEAP) type = NL80211_AUTHTYPE_NETWORK_EAP; else if (params->auth_alg & WPA_AUTH_ALG_FT) type = NL80211_AUTHTYPE_FT; else goto nla_put_failure; wpa_printf(MSG_DEBUG, " * Auth Type %d", type); NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); skip_auth_type: if (params->wpa_proto) { enum nl80211_wpa_versions ver = 0; if (params->wpa_proto & WPA_PROTO_WPA) ver |= NL80211_WPA_VERSION_1; if (params->wpa_proto & WPA_PROTO_RSN) ver |= NL80211_WPA_VERSION_2; wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver); NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); } if (params->pairwise_suite != CIPHER_NONE) { int cipher; switch (params->pairwise_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); } if (params->group_suite != CIPHER_NONE) { int cipher; switch (params->group_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); } if (params->key_mgmt_suite == KEY_MGMT_802_1X || params->key_mgmt_suite == KEY_MGMT_PSK) { int mgmt = WLAN_AKM_SUITE_PSK; switch (params->key_mgmt_suite) { case KEY_MGMT_802_1X: mgmt = WLAN_AKM_SUITE_8021X; break; case KEY_MGMT_PSK: default: mgmt = WLAN_AKM_SUITE_PSK; break; } NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); } ret = capwap_set_conn_keys(params, msg); if (ret) goto nla_put_failure; ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME connect failed: ret=%d " "(%s)", ret, strerror(-ret)); /* * cfg80211 does not currently accept new connection if we are * already connected. As a workaround, force disconnection and * try again once the driver indicates it completed * disconnection. */ if (ret == -EALREADY) capwap_disconnect(drv, params->bssid); goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Connect request send successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_associate( void *priv, struct wpa_driver_associate_params *params) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1; struct nl_msg *msg; if (params->mode == IEEE80211_MODE_AP) return wpa_driver_capwap_ap(drv, params); if (params->mode == IEEE80211_MODE_IBSS) return wpa_driver_capwap_ibss(drv, params); if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { enum nl80211_iftype nlmode = params->p2p ? NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; if (wpa_driver_capwap_set_mode(priv, nlmode) < 0) return -1; return wpa_driver_capwap_connect(drv, params); } drv->associated = 0; msg = nlmsg_alloc(); if (!msg) return -1; wpa_printf(MSG_DEBUG, "capwap: Associate (ifindex=%d)", drv->ifindex); capwap_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); drv->assoc_freq = params->freq; } else drv->assoc_freq = 0; if (ac_params.ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", ac_params.ssid, ac_params.ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, ac_params.ssid_len, ac_params.ssid); if (ac_params.ssid_len > sizeof(drv->ssid)) goto nla_put_failure; os_memcpy(drv->ssid, ac_params.ssid, ac_params.ssid_len); drv->ssid_len = ac_params.ssid_len; } wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); if (params->wpa_ie) NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); if (params->pairwise_suite != CIPHER_NONE) { int cipher; switch (params->pairwise_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); } if (params->group_suite != CIPHER_NONE) { int cipher; switch (params->group_suite) { case CIPHER_WEP40: cipher = WLAN_CIPHER_SUITE_WEP40; break; case CIPHER_WEP104: cipher = WLAN_CIPHER_SUITE_WEP104; break; case CIPHER_CCMP: cipher = WLAN_CIPHER_SUITE_CCMP; break; case CIPHER_TKIP: default: cipher = WLAN_CIPHER_SUITE_TKIP; break; } wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); } #ifdef CONFIG_IEEE80211W if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); #endif /* CONFIG_IEEE80211W */ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); if (params->prev_bssid) { wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, MAC2STR(params->prev_bssid)); NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, params->prev_bssid); } if (params->p2p) wpa_printf(MSG_DEBUG, " * P2P group"); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); capwap_dump_scan(drv); goto nla_put_failure; } ret = 0; wpa_printf(MSG_DEBUG, "capwap: Association request send " "successfully"); nla_put_failure: nlmsg_free(msg); return ret; } static int capwap_set_mode(struct wpa_driver_capwap_data *drv, int ifindex, enum nl80211_iftype mode) { wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_set_mode\n"); struct nl_msg *msg; int ret = -ENOBUFS; wpa_printf(MSG_DEBUG, "capwap: Set mode ifindex %d iftype %d (%s)", ifindex, mode, nl80211_iftype_str(mode)); msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (!ret) return 0; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_DEBUG, "capwap: Failed to set interface %d to mode %d:" " %d (%s)", ifindex, mode, ret, strerror(-ret)); return ret; } static int wpa_driver_capwap_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode) { wpa_printf(MSG_DEBUG, " 6.wpa_driver_capwap_set_mode\n"); struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1; int i; int was_ap = is_ap_interface(drv->nlmode); if (capwap_set_mode(drv, drv->ifindex, nlmode) == 0) { drv->nlmode = nlmode; ret = 0; goto done; } if (nlmode == drv->nlmode) { wpa_printf(MSG_DEBUG, "capwap: Interface already in " "requested mode - ignore error"); ret = 0; goto done; /* Already in the requested mode */ } /* mac80211 doesn't allow mode changes while the device is up, so * take the device down, try to set the mode again, and bring the * device back up. */ wpa_printf(MSG_DEBUG, "capwap: Try mode change after setting " "interface down"); for (i = 0; i < 10; i++) { int res; res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); if (res == -EACCES || res == -ENODEV) break; if (res == 0) { /* Try to set the mode again while the interface is * down */ ret = capwap_set_mode(drv, drv->ifindex, nlmode); if (ret == -EACCES) break; res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); if (res && !ret) ret = -1; else if (ret != -EBUSY) break; } else wpa_printf(MSG_DEBUG, "capwap: Failed to set " "interface down"); os_sleep(0, 100000); } if (!ret) { wpa_printf(MSG_DEBUG, "capwap: Mode change succeeded while " "interface is down"); drv->nlmode = nlmode; drv->ignore_if_down_event = 1; } done: if (!ret && is_ap_interface(nlmode)) { /* Setup additional AP mode functionality if needed */ if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 && capwap_create_monitor_interface(drv) && !drv->no_monitor_iface_capab) return -1; } else if (!ret && !is_ap_interface(nlmode)) { /* Remove additional AP mode functionality */ if (was_ap && drv->no_monitor_iface_capab) wpa_driver_capwap_probe_req_report(bss, 0); capwap_remove_monitor_interface(drv); bss->beacon_set = 0; } if (!ret && is_p2p_interface(drv->nlmode)) { capwap_disable_11b_rates(drv, drv->ifindex, 1); drv->disabled_11b_rates = 1; } else if (!ret && drv->disabled_11b_rates) { capwap_disable_11b_rates(drv, drv->ifindex, 0); drv->disabled_11b_rates = 0; } if (ret) wpa_printf(MSG_DEBUG, "capwap: Interface mode change to %d " "from %d failed", nlmode, drv->nlmode); return ret; } static int wpa_driver_capwap_get_capa(void *priv, struct wpa_driver_capa *capa) { wpa_printf(MSG_DEBUG, " 1.wpa_driver_capwap_get_capa\n"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!drv->has_capability) return -1; os_memcpy(capa, &drv->capa, sizeof(*capa)); return 0; } static int wpa_driver_capwap_set_operstate(void *priv, int state) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); } static int wpa_driver_capwap_set_supp_port(void *priv, int authorized) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct nl80211_sta_flag_update upd; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); os_memset(&upd, 0, sizeof(upd)); upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); if (authorized) upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } /* Set kernel driver on given frequency (MHz) */ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) { wpa_printf(MSG_DEBUG, " 1.i802_set_freq \n"); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; return wpa_driver_capwap_set_freq(drv, freq->freq, freq->ht_enabled, freq->sec_channel_offset); } #if defined(HOSTAPD) || defined(CONFIG_AP) static inline int min_int(int a, int b) { if (a < b) return a; return b; } static int get_key_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); /* * TODO: validate the key index and mac address! * Otherwise, there's a race condition as soon as * the kernel starts sending key notifications. */ if (tb[NL80211_ATTR_KEY_SEQ]) memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); return NL_SKIP; } static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, int idx, u8 *seq) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_KEY); if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); memset(seq, 0, 6); return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, int mode) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; u8 rates[NL80211_MAX_SUPP_RATES]; u8 rates_len = 0; int i; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_BSS); for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) rates[rates_len++] = basic_rates[i] / 5; NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: return -ENOBUFS; } static int i802_set_rts(void *priv, int rts) { wpa_printf(MSG_DEBUG, "> i802_set_rts %d \n",rts); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret = -ENOBUFS; u32 val; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (rts >= 2347) val = (u32) -1; else val = rts; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (!ret) return 0; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_DEBUG, "capwap: Failed to set RTS threshold %d: " "%d (%s)", rts, ret, strerror(-ret)); return ret; } static int i802_set_frag(void *priv, int frag) { wpa_printf(MSG_DEBUG, "> i802_set_frag %d\n",frag); struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret = -ENOBUFS; u32 val; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (frag >= 2346) val = (u32) -1; else val = frag; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (!ret) return 0; nla_put_failure: nlmsg_free(msg); wpa_printf(MSG_DEBUG, "capwap: Failed to set fragmentation threshold " "%d: %d (%s)", frag, ret, strerror(-ret)); return ret; } static int i802_flush(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); /* * XXX: FIX! this needs to flush all VLANs too */ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int get_sta_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct hostap_sta_driver_data *data = arg; struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); /* * TODO: validate the interface and mac address! * Otherwise, there's a race condition as soon as * the kernel starts sending station notifications. */ if (!tb[NL80211_ATTR_STA_INFO]) { wpa_printf(MSG_DEBUG, "sta stats missing!"); return NL_SKIP; } if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, tb[NL80211_ATTR_STA_INFO], stats_policy)) { wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); return NL_SKIP; } if (stats[NL80211_STA_INFO_INACTIVE_TIME]) data->inactive_msec = nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); if (stats[NL80211_STA_INFO_RX_BYTES]) data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); if (stats[NL80211_STA_INFO_TX_BYTES]) data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); if (stats[NL80211_STA_INFO_RX_PACKETS]) data->rx_packets = nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); if (stats[NL80211_STA_INFO_TX_PACKETS]) data->tx_packets = nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); return NL_SKIP; } static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, const u8 *addr) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; os_memset(data, 0, sizeof(*data)); msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_GET_STATION); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); return send_and_recv_msgs(drv, msg, get_sta_handler, data); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int i802_set_tx_queue_params(void *priv, int queue, int aifs, int cw_min, int cw_max, int burst_time) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; struct nlattr *txq, *params; flush_SET_TXQ_handle(generic_wtp_info.fd_ipc, drv->ctx); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); if (!txq) goto nla_put_failure; /* We are only sending parameters for a single TXQ at a time */ params = nla_nest_start(msg, 1); if (!params) goto nla_put_failure; switch (queue) { case 0: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO); break; case 1: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI); break; case 2: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE); break; case 3: NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK); break; } /* Burst time is configured in units of 0.1 msec and TXOP parameter in * 32 usec, so need to convert the value here. */ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); nla_nest_end(msg, params); nla_nest_end(msg, txq); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; msg = NULL; nla_put_failure: nlmsg_free(msg); return -1; } static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname, int vlan_id) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret = -ENOBUFS; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname)); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret < 0) { wpa_printf(MSG_ERROR, "capwap: NL80211_ATTR_STA_VLAN (addr=" MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", MAC2STR(addr), ifname, vlan_id, ret, strerror(-ret)); } nla_put_failure: nlmsg_free(msg); return ret; } static int i802_get_inact_sec(void *priv, const u8 *addr) { struct hostap_sta_driver_data data; int ret; data.inactive_msec = (unsigned long) -1; ret = i802_read_sta_data(priv, &data, addr); if (ret || data.inactive_msec == (unsigned long) -1) return -1; return data.inactive_msec / 1000; } static int i802_sta_clear_stats(void *priv, const u8 *addr) { #if 0 /* TODO */ #endif return 0; } static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason) { wpa_printf(MSG_DEBUG, " 1.i802_sta_deauth \n"); struct i802_bss *bss = priv; struct ieee80211_mgmt mgmt; memset(&mgmt, 0, sizeof(mgmt)); mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); memcpy(mgmt.da, addr, ETH_ALEN); memcpy(mgmt.sa, own_addr, ETH_ALEN); memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); return wpa_driver_capwap_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.deauth)); } static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, int reason) { struct i802_bss *bss = priv; struct ieee80211_mgmt mgmt; memset(&mgmt, 0, sizeof(mgmt)); mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DISASSOC); memcpy(mgmt.da, addr, ETH_ALEN); memcpy(mgmt.sa, own_addr, ETH_ALEN); memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return wpa_driver_capwap_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.disassoc)); } #endif /* HOSTAPD || CONFIG_AP */ #ifdef HOSTAPD static void add_ifidx(struct wpa_driver_capwap_data *drv, int ifidx){ wpa_printf(MSG_DEBUG," 3.add_ifidx\n"); int i; int *old; wpa_printf(MSG_DEBUG, "capwap: Add own interface ifindex %d", ifidx); for (i = 0; i < drv->num_if_indices; i++) { if (drv->if_indices[i] == 0) { drv->if_indices[i] = ifidx; return; } } if (drv->if_indices != drv->default_if_indices) old = drv->if_indices; else old = NULL; drv->if_indices = os_realloc(old, sizeof(int) * (drv->num_if_indices + 1)); if (!drv->if_indices) { if (!old) drv->if_indices = drv->default_if_indices; else drv->if_indices = old; wpa_printf(MSG_ERROR, "Failed to reallocate memory for " "interfaces"); wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); return; } else if (!old) os_memcpy(drv->if_indices, drv->default_if_indices, sizeof(drv->default_if_indices)); drv->if_indices[drv->num_if_indices] = ifidx; drv->num_if_indices++; } static void del_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { int i; for (i = 0; i < drv->num_if_indices; i++) { if (drv->if_indices[i] == ifidx) { drv->if_indices[i] = 0; break; } } } static int have_ifidx(struct wpa_driver_capwap_data *drv, int ifidx) { int i; for (i = 0; i < drv->num_if_indices; i++) if (drv->if_indices[i] == ifidx) return 1; return 0; } static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, const char *bridge_ifname) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; char name[IFNAMSIZ + 1]; os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); wpa_printf(MSG_DEBUG, "capwap: Set WDS STA addr=" MACSTR " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); if (val) { if (!if_nametoindex(name)) { if (capwap_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN, NULL, 1) < 0) return -1; if (bridge_ifname && linux_br_add_if(drv->global->ioctl_sock, bridge_ifname, name) < 0) return -1; } linux_set_iface_flags(drv->global->ioctl_sock, name, 1); return i802_set_sta_vlan(priv, addr, name, 0); } else { i802_set_sta_vlan(priv, addr, bss->ifname, 0); return wpa_driver_capwap_if_remove(priv, WPA_IF_AP_VLAN, name); } } static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) { struct wpa_driver_capwap_data *drv = eloop_ctx; struct sockaddr_ll lladdr; unsigned char buf[3000]; int len; socklen_t fromlen = sizeof(lladdr); len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&lladdr, &fromlen); if (len < 0) { perror("recv"); return; } wpa_printf(MSG_DEBUG, "%d, %d", len,have_ifidx(drv, lladdr.sll_ifindex)); int i; wpa_printf(MSG_DEBUG, " EAPOL MAC: "); for(i=0; i<6; i++ )wpa_printf(MSG_DEBUG, "%02X ",lladdr.sll_addr[i]);printf("\n"); u8 outbuf_8022[BUFFER_SIZE]; u8 outbuf_80211[BUFFER_SIZE]; int outlen_8022 = add_8022_header(buf, len, outbuf_8022); int outlen_80211 = add_80211_Data_header(generic_wtp_info.own_mac_addr, lladdr.sll_addr, generic_wtp_info.own_mac_addr, 1, 0, outbuf_8022, outlen_8022, outbuf_80211); wpa_printf(MSG_DEBUG, "EAPOL Data Frame 5 (%d)\n",outlen_80211); // flush_pcap(outlen_80211,outbuf_80211,WTP_LOG); ipc_send_80211_to_ac(generic_wtp_info.fd_ipc, outbuf_80211, outlen_80211); //WTP_handle_send_data_to_AC(outbuf_80211, outlen_80211); return; if (have_ifidx(drv, lladdr.sll_ifindex)) drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len); } static int i802_check_bridge(struct wpa_driver_capwap_data *drv, struct i802_bss *bss, const char *brname, const char *ifname) { wpa_printf(MSG_DEBUG, " 7.i802_check_bridge\n"); int ifindex; char in_br[IFNAMSIZ]; os_strlcpy(bss->brname, brname, IFNAMSIZ); ifindex = if_nametoindex(brname); if (ifindex == 0) { /* * Bridge was configured, but the bridge device does * not exist. Try to add it now. */ if (linux_br_add(drv->global->ioctl_sock, brname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to add the " "bridge interface %s: %s", brname, strerror(errno)); return -1; } bss->added_bridge = 1; add_ifidx(drv, if_nametoindex(brname)); } if (linux_br_get(in_br, ifname) == 0) { if (os_strcmp(in_br, brname) == 0) return 0; /* already in the bridge */ wpa_printf(MSG_DEBUG, "capwap: Removing interface %s from " "bridge %s", ifname, in_br); if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to " "remove interface %s from bridge " "%s: %s", ifname, brname, strerror(errno)); return -1; } } wpa_printf(MSG_DEBUG, "capwap: Adding interface %s into bridge %s", ifname, brname); if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to add interface %s " "into bridge %s: %s", ifname, brname, strerror(errno)); return -1; } bss->added_if_into_bridge = 1; return 0; } void AC_popu_capa_info(struct i802_bss *bss, unsigned char *mac_addr) { struct hostapd_hw_modes *tmp_modes; u16 num_modes1, flags1; tmp_modes = wpa_driver_capwap_get_hw_feature_data(bss, &num_modes1, &flags1); if(tmp_modes == NULL){ wpa_printf(MSG_DEBUG, "NULL mm\n"); exit(1); } int cnt_indx; for(cnt_indx=0; cnt_indx<21; cnt_indx++) ac_params.capa_buf[cnt_indx] = 0; for(cnt_indx=0; cnt_indxchannels[0].chan; ac_params.capa_buf[12] = fe->num_channels; ac_params.capa_buf[14] = fe->channels[0].max_tx_power; int kk; for(kk=0; kknum_rates && kk<8 ;kk++) { int tmp_sup_rate = (unsigned char)(fe->rates[kk] / 5); if(fe->mode == HOSTAPD_MODE_IEEE80211B) tmp_sup_rate |= 0x80; if(tmp_sup_rate > ac_params.capa_buf[kk]) ac_params.capa_buf[kk] = tmp_sup_rate; } if(fe->mode == HOSTAPD_MODE_IEEE80211B ) ac_params.capa_buf[8] |= 1; if(fe->mode == HOSTAPD_MODE_IEEE80211A ) ac_params.capa_buf[8] |= 2; if(fe->mode == HOSTAPD_MODE_IEEE80211G ) ac_params.capa_buf[8] |= 4; } memcpy(ac_params.capa_buf + 15, bss->drv->addr, 6); } static void *i802_init(struct hostapd_data *hapd, struct wpa_init_params *params) { wpa_printf(MSG_DEBUG, " 1.i802_init\n"); struct wpa_driver_capwap_data *drv; struct i802_bss *bss; size_t i; char brname[IFNAMSIZ]; int ifindex, br_ifindex; int br_added = 0; bss = wpa_driver_capwap_init(hapd, params->ifname, params->global_priv); if (bss == NULL) return NULL; drv = bss->drv; drv->nlmode = NL80211_IFTYPE_AP; drv->eapol_sock = -1; if (linux_br_get(brname, params->ifname) == 0) { wpa_printf(MSG_DEBUG, "capwap: Interface %s is in bridge %s", params->ifname, brname); br_ifindex = if_nametoindex(brname); } else { brname[0] = '\0'; br_ifindex = 0; } drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); drv->if_indices = drv->default_if_indices; for (i = 0; i < params->num_bridge; i++) { if (params->bridge[i]) { ifindex = if_nametoindex(params->bridge[i]); if (ifindex) add_ifidx(drv, ifindex); if (ifindex == br_ifindex) br_added = 1; } } if (!br_added && br_ifindex && (params->num_bridge == 0 || !params->bridge[0])) add_ifidx(drv, br_ifindex); /* start listening for EAPOL on the default AP interface */ add_ifidx(drv, drv->ifindex); if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0)) goto failed; if (params->bssid) { if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->bssid)) goto failed; } if (wpa_driver_capwap_set_mode(bss, drv->nlmode)) { wpa_printf(MSG_ERROR, "capwap: Failed to set interface %s " "into AP mode", bss->ifname); goto failed; } if (params->num_bridge && params->bridge[0] && i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) goto failed; if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) goto failed; drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); if (drv->eapol_sock < 0) { perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); goto failed; } if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) { wpa_printf(MSG_DEBUG, "Could not register read socket for eapol\n"); goto failed; } if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->own_addr)) goto failed; /* capwap FIXME: not defined wpa_printf(MSG_DEBUG, "iFace: %s TapInterface: %s \n",params->ifname,params->tap); */ /* capwap FIXME: unused generic_wtp_info.wlan_interface = params->ifname; generic_wtp_info.tap_interface = params->tap; generic_wtp_info.br_interface = params->br_name; */ AC_popu_capa_info(bss, params->own_addr); wpa_printf(MSG_DEBUG, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", ac_params.capa_buf[0], ac_params.capa_buf[1], ac_params.capa_buf[2], ac_params.capa_buf[3], ac_params.capa_buf[4], ac_params.capa_buf[5], ac_params.capa_buf[6], ac_params.capa_buf[7], ac_params.capa_buf[8], ac_params.capa_buf[9], ac_params.capa_buf[10], ac_params.capa_buf[11], ac_params.capa_buf[12], ac_params.capa_buf[13], ac_params.capa_buf[14], ac_params.capa_buf[15], ac_params.capa_buf[16], ac_params.capa_buf[17], ac_params.capa_buf[18], ac_params.capa_buf[19], ac_params.capa_buf[20]); generic_wtp_info.fd_ipc = start_ipc(drv->ctx, ac_params.ssid, &(ac_params.ssid_len), WTP_inject_frame_in_air, ac_params.capa_buf); memcpy(params->ssid, ac_params.ssid, ac_params.ssid_len); params->ssid_len = ac_params.ssid_len; if(generic_wtp_info.fd_ipc<=0) { wpa_printf(MSG_ERROR, "Error: start_ipc"); return NULL; } return bss; failed: wpa_driver_capwap_deinit(bss); return NULL; } static void i802_deinit(void *priv) { wpa_printf(MSG_DEBUG, "> i802_deinit \n"); end_ipc(generic_wtp_info.fd_ipc); wpa_driver_capwap_deinit(priv); } #endif /* HOSTAPD */ static enum nl80211_iftype wpa_driver_capwap_if_type( enum wpa_driver_if_type type) { switch (type) { case WPA_IF_STATION: return NL80211_IFTYPE_STATION; case WPA_IF_P2P_CLIENT: case WPA_IF_P2P_GROUP: return NL80211_IFTYPE_P2P_CLIENT; case WPA_IF_AP_VLAN: return NL80211_IFTYPE_AP_VLAN; case WPA_IF_AP_BSS: return NL80211_IFTYPE_AP; case WPA_IF_P2P_GO: return NL80211_IFTYPE_P2P_GO; } return -1; } #ifdef CONFIG_P2P static int capwap_addr_in_use(struct capwap_global *global, const u8 *addr) { struct wpa_driver_capwap_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_capwap_data, list) { if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0) return 1; } return 0; } static int capwap_p2p_interface_addr(struct wpa_driver_capwap_data *drv, u8 *new_addr) { unsigned int idx; if (!drv->global) return -1; os_memcpy(new_addr, drv->addr, ETH_ALEN); for (idx = 0; idx < 64; idx++) { new_addr[0] = drv->addr[0] | 0x02; new_addr[0] ^= idx << 2; if (!capwap_addr_in_use(drv->global, new_addr)) break; } if (idx == 64) return -1; wpa_printf(MSG_DEBUG, "capwap: Assigned new P2P Interface Address " MACSTR, MAC2STR(new_addr)); return 0; } #endif /* CONFIG_P2P */ static int wpa_driver_capwap_if_add(void *priv, enum wpa_driver_if_type type, const char *ifname, const u8 *addr, void *bss_ctx, void **drv_priv, char *force_ifname, u8 *if_addr, const char *bridge) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ifidx; #ifdef HOSTAPD struct i802_bss *new_bss = NULL; if (type == WPA_IF_AP_BSS) { new_bss = os_zalloc(sizeof(*new_bss)); if (new_bss == NULL) return -1; } #endif /* HOSTAPD */ if (addr) os_memcpy(if_addr, addr, ETH_ALEN); ifidx = capwap_create_iface(drv, ifname, wpa_driver_capwap_if_type(type), addr, 0); if (ifidx < 0) { #ifdef HOSTAPD os_free(new_bss); #endif /* HOSTAPD */ return -1; } if (!addr && linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, if_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } #ifdef CONFIG_P2P if (!addr && (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || type == WPA_IF_P2P_GO)) { /* Enforce unique P2P Interface Address */ u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN]; if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, own_addr) < 0 || linux_get_ifhwaddr(drv->global->ioctl_sock, ifname, new_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "capwap: Allocate new address " "for P2P group interface"); if (capwap_p2p_interface_addr(drv, new_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, new_addr) < 0) { capwap_remove_iface(drv, ifidx); return -1; } } os_memcpy(if_addr, new_addr, ETH_ALEN); } #endif /* CONFIG_P2P */ #ifdef HOSTAPD if (bridge && i802_check_bridge(drv, new_bss, bridge, ifname) < 0) { wpa_printf(MSG_ERROR, "capwap: Failed to add the new " "interface %s to a bridge %s", ifname, bridge); capwap_remove_iface(drv, ifidx); os_free(new_bss); return -1; } if (type == WPA_IF_AP_BSS) { if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1)) { capwap_remove_iface(drv, ifidx); os_free(new_bss); return -1; } os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); new_bss->ifindex = ifidx; new_bss->drv = drv; new_bss->next = drv->first_bss.next; drv->first_bss.next = new_bss; if (drv_priv) *drv_priv = new_bss; } #endif /* HOSTAPD */ if (drv->global) drv->global->if_add_ifindex = ifidx; return 0; } static int wpa_driver_capwap_if_remove(void *priv, enum wpa_driver_if_type type, const char *ifname) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ifindex = if_nametoindex(ifname); wpa_printf(MSG_DEBUG, "capwap: %s(type=%d ifname=%s) ifindex=%d", __func__, type, ifname, ifindex); if (ifindex <= 0) return -1; #ifdef HOSTAPD if (bss->added_if_into_bridge) { if (linux_br_del_if(drv->global->ioctl_sock, bss->brname, bss->ifname) < 0) wpa_printf(MSG_INFO, "capwap: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); } if (bss->added_bridge) { if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) wpa_printf(MSG_INFO, "capwap: Failed to remove " "bridge %s: %s", bss->brname, strerror(errno)); } #endif /* HOSTAPD */ capwap_remove_iface(drv, ifindex); #ifdef HOSTAPD if (type != WPA_IF_AP_BSS) return 0; if (bss != &drv->first_bss) { struct i802_bss *tbss; for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { if (tbss->next == bss) { tbss->next = bss->next; os_free(bss); bss = NULL; break; } } if (bss) wpa_printf(MSG_INFO, "capwap: %s - could not find " "BSS %p in the list", __func__, bss); } #endif /* HOSTAPD */ return 0; } static int cookie_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); u64 *cookie = arg; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_COOKIE]) *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); return NL_SKIP; } static int capwap_send_frame_cmd(struct wpa_driver_capwap_data *drv, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, u64 *cookie_out, int no_cck) { struct nl_msg *msg; u64 cookie; int ret = -1; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_FRAME); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); if (wait) NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); if (no_cck) NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE); NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf); cookie = 0; ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Frame command failed: ret=%d " "(%s) (freq=%u wait=%u)", ret, strerror(-ret), freq, wait); goto nla_put_failure; } wpa_printf(MSG_DEBUG, "capwap: Frame TX command accepted; " "cookie 0x%llx", (long long unsigned int) cookie); if (cookie_out) *cookie_out = cookie; nla_put_failure: nlmsg_free(msg); return ret; } static int wpa_driver_capwap_send_action(void *priv, unsigned int freq, unsigned int wait_time, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, int no_cck) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret = -1; u8 *buf; struct ieee80211_hdr *hdr; wpa_printf(MSG_DEBUG, "capwap: Send Action frame (ifindex=%d, " "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck); buf = os_zalloc(24 + data_len); if (buf == NULL) return ret; os_memcpy(buf + 24, data, data_len); hdr = (struct ieee80211_hdr *) buf; hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(hdr->addr1, dst, ETH_ALEN); os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); if (is_ap_interface(drv->nlmode)) ret = wpa_driver_capwap_send_mlme(priv, buf, 24 + data_len); else ret = capwap_send_frame_cmd(drv, freq, wait_time, buf, 24 + data_len, &drv->send_action_cookie, no_cck); os_free(buf); return ret; } static void wpa_driver_capwap_send_action_cancel_wait(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; msg = nlmsg_alloc(); if (!msg) return; capwap_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) wpa_printf(MSG_DEBUG, "capwap: wait cancel failed: ret=%d " "(%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); } static int wpa_driver_capwap_remain_on_channel(void *priv, unsigned int freq, unsigned int duration) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; u64 cookie; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); cookie = 0; ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "capwap: Remain-on-channel cookie " "0x%llx for freq=%u MHz duration=%u", (long long unsigned int) cookie, freq, duration); drv->remain_on_chan_cookie = cookie; drv->pending_remain_on_chan = 1; return 0; } wpa_printf(MSG_DEBUG, "capwap: Failed to request remain-on-channel " "(freq=%d duration=%u): %d (%s)", freq, duration, ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_cancel_remain_on_channel(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; int ret; if (!drv->pending_remain_on_chan) { wpa_printf(MSG_DEBUG, "capwap: No pending remain-on-channel " "to cancel"); return -1; } wpa_printf(MSG_DEBUG, "capwap: Cancel remain-on-channel with cookie " "0x%llx", (long long unsigned int) drv->remain_on_chan_cookie); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "capwap: Failed to cancel remain-on-channel: " "%d (%s)", ret, strerror(-ret)); nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_probe_req_report(void *priv, int report) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!report) { if (drv->nl_preq.handle && drv->no_monitor_iface_capab && is_ap_interface(drv->nlmode)) { /* * Do not disable Probe Request reporting that was * enabled in capwap_setup_ap(). */ wpa_printf(MSG_DEBUG, "capwap: Skip disabling of " "Probe Request reporting nl_preq=%p while " "in AP mode", drv->nl_preq.handle); } else if (drv->nl_preq.handle) { wpa_printf(MSG_DEBUG, "capwap: Disable Probe Request " "reporting nl_preq=%p", drv->nl_preq.handle); eloop_unregister_read_sock( nl_socket_get_fd(drv->nl_preq.handle)); nl_destroy_handles(&drv->nl_preq); } return 0; } if (drv->nl_preq.handle) { wpa_printf(MSG_DEBUG, "capwap: Probe Request reporting " "already on!"); return 0; } if (nl_create_handles(&drv->nl_preq, drv->global->nl_cb, "preq")) return -1; if (capwap_register_frame(drv, drv->nl_preq.handle, (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_PROBE_REQ << 4), NULL, 0) < 0) goto out_err; eloop_register_read_sock(nl_socket_get_fd(drv->nl_preq.handle), wpa_driver_capwap_event_receive, drv, drv->nl_preq.handle); return 0; out_err: nl_destroy_handles(&drv->nl_preq); return -1; } static int capwap_disable_11b_rates(struct wpa_driver_capwap_data *drv, int ifindex, int disabled) { struct nl_msg *msg; struct nlattr *bands, *band; int ret; msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); if (!bands) goto nla_put_failure; /* * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS * rates. All 5 GHz rates are left enabled. */ band = nla_nest_start(msg, NL80211_BAND_2GHZ); if (!band) goto nla_put_failure; if (disabled) { NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, "\x0c\x12\x18\x24\x30\x48\x60\x6c"); } nla_nest_end(msg, band); nla_nest_end(msg, bands); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "capwap: Set TX rates failed: ret=%d " "(%s)", ret, strerror(-ret)); } return ret; nla_put_failure: nlmsg_free(msg); return -1; } static int wpa_driver_capwap_deinit_ap(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_capwap_del_beacon(drv); return wpa_driver_capwap_set_mode(priv, NL80211_IFTYPE_STATION); } static int wpa_driver_capwap_deinit_p2p_cli(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT) return -1; return wpa_driver_capwap_set_mode(priv, NL80211_IFTYPE_STATION); } static void wpa_driver_capwap_resume(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { wpa_printf(MSG_DEBUG, "capwap: Failed to set interface up on " "resume event"); } } static int capwap_send_ft_action(void *priv, u8 action, const u8 *target_ap, const u8 *ies, size_t ies_len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int ret; u8 *data, *pos; size_t data_len; u8 own_addr[ETH_ALEN]; if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, own_addr) < 0) return -1; if (action != 1) { wpa_printf(MSG_ERROR, "capwap: Unsupported send_ft_action " "action %d", action); return -1; } /* * Action frame payload: * Category[1] = 6 (Fast BSS Transition) * Action[1] = 1 (Fast BSS Transition Request) * STA Address * Target AP Address * FT IEs */ data_len = 2 + 2 * ETH_ALEN + ies_len; data = os_malloc(data_len); if (data == NULL) return -1; pos = data; *pos++ = 0x06; /* FT Action category */ *pos++ = action; os_memcpy(pos, own_addr, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, target_ap, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, ies, ies_len); ret = wpa_driver_capwap_send_action(bss, drv->assoc_freq, 0, drv->bssid, own_addr, drv->bssid, data, data_len, 0); os_free(data); return ret; } static int capwap_signal_monitor(void *priv, int threshold, int hysteresis) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg, *cqm = NULL; wpa_printf(MSG_DEBUG, "capwap: Signal monitor threshold=%d " "hysteresis=%d", threshold, hysteresis); msg = nlmsg_alloc(); if (!msg) return -1; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_CQM); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); cqm = nlmsg_alloc(); if (cqm == NULL) return -1; NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold); NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis); nla_put_nested(msg, NL80211_ATTR_CQM, cqm); if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; msg = NULL; nla_put_failure: nlmsg_free(cqm); nlmsg_free(msg); return -1; } static int capwap_signal_poll(void *priv, struct wpa_signal_info *si) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int res; os_memset(si, 0, sizeof(*si)); res = capwap_get_link_signal(drv, si); if (res != 0) return res; return capwap_get_link_noise(drv, si); } static int capwap_send_frame(void *priv, const u8 *data, size_t data_len, int encrypt) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; return wpa_driver_capwap_send_frame(drv, data, data_len, encrypt); } static int capwap_set_param(void *priv, const char *param) { wpa_printf(MSG_DEBUG, "capwap: driver param='%s'", param); if (param == NULL) return 0; #ifdef CONFIG_P2P if (os_strstr(param, "use_p2p_group_interface=1")) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; wpa_printf(MSG_DEBUG, "capwap: Use separate P2P group " "interface"); drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } #endif /* CONFIG_P2P */ return 0; } static void * capwap_global_init(void) { wpa_printf(MSG_DEBUG," 1.capwap_global_init\n"); struct capwap_global *global; struct netlink_config *cfg; global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; global->ioctl_sock = -1; dl_list_init(&global->interfaces); global->if_add_ifindex = -1; cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL) goto err; cfg->ctx = global; cfg->newlink_cb = wpa_driver_capwap_event_rtm_newlink; cfg->dellink_cb = wpa_driver_capwap_event_rtm_dellink; global->netlink = netlink_init(cfg); if (global->netlink == NULL) { os_free(cfg); goto err; } if (wpa_driver_capwap_init_nl_global(global) < 0) goto err; global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); if (global->ioctl_sock < 0) { perror("socket(PF_INET,SOCK_DGRAM)"); goto err; } return global; err: capwap_global_deinit(global); return NULL; } static void capwap_global_deinit(void *priv) { struct capwap_global *global = priv; if (global == NULL) return; if (!dl_list_empty(&global->interfaces)) { wpa_printf(MSG_ERROR, "capwap: %u interface(s) remain at " "capwap_global_deinit", dl_list_len(&global->interfaces)); } if (global->netlink) netlink_deinit(global->netlink); if (global->capwap) genl_family_put(global->capwap); nl_destroy_handles(&global->nl); if (global->nl_cb) nl_cb_put(global->nl_cb); if (global->ioctl_sock >= 0) close(global->ioctl_sock); os_free(global); } static const char * capwap_get_radio_name(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; return drv->phyname; } static int capwap_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, const u8 *pmkid) { struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(bss->drv, msg, 0, cmd); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); if (pmkid) NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid); if (bssid) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); return send_and_recv_msgs(bss->drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int capwap_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) { struct i802_bss *bss = priv; wpa_printf(MSG_DEBUG, "capwap: Add PMKID for " MACSTR, MAC2STR(bssid)); return capwap_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid); } static int capwap_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) { struct i802_bss *bss = priv; wpa_printf(MSG_DEBUG, "capwap: Delete PMKID for " MACSTR, MAC2STR(bssid)); return capwap_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid); } static int capwap_flush_pmkid(void *priv) { struct i802_bss *bss = priv; wpa_printf(MSG_DEBUG, "capwap: Flush PMKIDs"); return capwap_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL); } static void capwap_set_rekey_info(void *priv, const u8 *kek, const u8 *kck, const u8 *replay_ctr) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nlattr *replay_nested; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return; capwap_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); if (!replay_nested) goto nla_put_failure; NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek); NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck); NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN, replay_ctr); nla_nest_end(msg, replay_nested); send_and_recv_msgs(drv, msg, NULL, NULL); return; nla_put_failure: nlmsg_free(msg); } static void capwap_poll_client(void *priv, const u8 *own_addr, const u8 *addr, int qos) { struct i802_bss *bss = priv; struct { struct ieee80211_hdr hdr; u16 qos_ctl; } STRUCT_PACKED nulldata; size_t size; /* Send data frame to poll STA and check whether this frame is ACKed */ os_memset(&nulldata, 0, sizeof(nulldata)); if (qos) { nulldata.hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_QOS_NULL); size = sizeof(nulldata); } else { nulldata.hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_NULLFUNC); size = sizeof(struct ieee80211_hdr); } nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN); os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); if (wpa_driver_capwap_send_mlme(bss, (u8 *) &nulldata, size) < 0) wpa_printf(MSG_DEBUG, "capwap_send_null_frame: Failed to " "send poll frame"); } #ifdef CONFIG_TDLS static int capwap_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, size_t len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; if (!dst) return -EINVAL; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); NLA_PUT(msg, NL80211_ATTR_IE, len, buf); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } static int capwap_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; struct nl_msg *msg; enum capwap_tdls_operation capwap_oper; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; switch (oper) { case TDLS_DISCOVERY_REQ: capwap_oper = NL80211_TDLS_DISCOVERY_REQ; break; case TDLS_SETUP: capwap_oper = NL80211_TDLS_SETUP; break; case TDLS_TEARDOWN: capwap_oper = NL80211_TDLS_TEARDOWN; break; case TDLS_ENABLE_LINK: capwap_oper = NL80211_TDLS_ENABLE_LINK; break; case TDLS_DISABLE_LINK: capwap_oper = NL80211_TDLS_DISABLE_LINK; break; case TDLS_ENABLE: return 0; case TDLS_DISABLE: return 0; default: return -EINVAL; } msg = nlmsg_alloc(); if (!msg) return -ENOMEM; capwap_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, capwap_oper); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: nlmsg_free(msg); return -ENOBUFS; } #endif /* CONFIG TDLS */ void WTP_inject_frame_in_air(void *priv, u8 *buf, int len) { struct i802_bss *bss = priv; struct wpa_driver_capwap_data *drv = bss->drv; int type = WTP_get_Type(buf ,len ); if( type == WLAN_FC_TYPE_DATA){ if( isEAPOL_Frame(buf, len) ){ wpa_printf(MSG_DEBUG, "EAPOL Data Frame 2 (%d)\n",len); wpa_driver_capwap_send_frame(drv,buf,len,0); } else wpa_printf(MSG_DEBUG, "ERROR Data Frame in hostapd WTP"); } else if( type == WLAN_FC_TYPE_MGMT ){ wpa_driver_capwap_send_frame(drv,buf,len,0); } else wpa_printf(MSG_ERROR, "ERROR: Received invalid/controlo 802.11 header type"); } const struct wpa_driver_ops wpa_driver_capwap_wtp_ops = { .name = "capwap_wtp", .desc = "Linux capwap/cfg80211", .get_bssid = wpa_driver_capwap_get_bssid, .get_ssid = wpa_driver_capwap_get_ssid, .set_key = wpa_driver_capwap_set_key, .scan2 = wpa_driver_capwap_scan, .sched_scan = wpa_driver_capwap_sched_scan, .stop_sched_scan = wpa_driver_capwap_stop_sched_scan, .get_scan_results2 = wpa_driver_capwap_get_scan_results, .deauthenticate = wpa_driver_capwap_deauthenticate, .disassociate = wpa_driver_capwap_disassociate, .authenticate = wpa_driver_capwap_authenticate, .associate = wpa_driver_capwap_associate, .global_init = capwap_global_init, .global_deinit = capwap_global_deinit, .init2 = wpa_driver_capwap_init, .deinit = wpa_driver_capwap_deinit, .get_capa = wpa_driver_capwap_get_capa, .set_operstate = wpa_driver_capwap_set_operstate, .set_supp_port = wpa_driver_capwap_set_supp_port, .set_country = wpa_driver_capwap_set_country, .set_ap = wpa_driver_capwap_set_ap, .if_add = wpa_driver_capwap_if_add, .if_remove = wpa_driver_capwap_if_remove, .send_mlme = wpa_driver_capwap_send_mlme, .get_hw_feature_data = wpa_driver_capwap_get_hw_feature_data, .sta_add = wpa_driver_capwap_sta_add, .sta_remove = wpa_driver_capwap_sta_remove, .hapd_send_eapol = wpa_driver_capwap_hapd_send_eapol, .sta_set_flags = wpa_driver_capwap_sta_set_flags, #ifdef HOSTAPD .hapd_init = i802_init, .hapd_deinit = i802_deinit, .set_wds_sta = i802_set_wds_sta, #endif /* HOSTAPD */ #if defined(HOSTAPD) || defined(CONFIG_AP) .get_seqnum = i802_get_seqnum, .flush = i802_flush, .read_sta_data = i802_read_sta_data, .get_inact_sec = i802_get_inact_sec, .sta_clear_stats = i802_sta_clear_stats, .set_rts = i802_set_rts, .set_frag = i802_set_frag, .set_tx_queue_params = i802_set_tx_queue_params, .set_sta_vlan = i802_set_sta_vlan, .set_rate_sets = i802_set_rate_sets, .sta_deauth = i802_sta_deauth, .sta_disassoc = i802_sta_disassoc, #endif /* HOSTAPD || CONFIG_AP */ .set_freq = i802_set_freq, .send_action = wpa_driver_capwap_send_action, .send_action_cancel_wait = wpa_driver_capwap_send_action_cancel_wait, .remain_on_channel = wpa_driver_capwap_remain_on_channel, .cancel_remain_on_channel = wpa_driver_capwap_cancel_remain_on_channel, .probe_req_report = wpa_driver_capwap_probe_req_report, .deinit_ap = wpa_driver_capwap_deinit_ap, .deinit_p2p_cli = wpa_driver_capwap_deinit_p2p_cli, .resume = wpa_driver_capwap_resume, .send_ft_action = capwap_send_ft_action, .signal_monitor = capwap_signal_monitor, .signal_poll = capwap_signal_poll, .send_frame = capwap_send_frame, .set_param = capwap_set_param, .get_radio_name = capwap_get_radio_name, .add_pmkid = capwap_add_pmkid, .remove_pmkid = capwap_remove_pmkid, .flush_pmkid = capwap_flush_pmkid, .set_rekey_info = capwap_set_rekey_info, .poll_client = capwap_poll_client, #ifdef CONFIG_TDLS .send_tdls_mgmt = capwap_send_tdls_mgmt, .tdls_oper = capwap_tdls_oper, #endif /* CONFIG_TDLS */ //.inject_frame_in_air = WTP_inject_frame_in_air, }; ================================================ FILE: hostapd_wrapper/src/drivers/linux_ioctl_fake.c ================================================ /* * Linux ioctl helper functions for driver wrappers * Copyright (c) 2002-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "utils/includes.h" #include #include #include #include "utils/common.h" #include "linux_ioctl_fake.h" int linux_set_iface_flags(int sock, const char *ifname, int dev_up){ return 0; } int linux_iface_up(int sock, const char *ifname){ return 0; } int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr){ int i=2; if(i==0){ // TP-LINK (Atheros) addr[0]=0xB0; addr[1]=0x48; addr[2]=0x7A; addr[3]=0x93; addr[4]=0x90; addr[5]=0xF8; }else if(i==1){// D-Link addr[0]=0x28; addr[1]=0x10; addr[2]=0x7B; addr[3]=0x44; addr[4]=0xd0; addr[5]=0xB1; }else if(i==2){// TP-LINK (Atheros) addr[0]=0xAA; addr[1]=0xBB; addr[2]=0xCC; addr[3]=0xDD; addr[4]=0xEE; addr[5]=0xFF; } return 0; } int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr){ return 0; } #ifndef SIOCBRADDBR #define SIOCBRADDBR 0x89a0 #endif #ifndef SIOCBRDELBR #define SIOCBRDELBR 0x89a1 #endif #ifndef SIOCBRADDIF #define SIOCBRADDIF 0x89a2 #endif #ifndef SIOCBRDELIF #define SIOCBRDELIF 0x89a3 #endif int linux_br_add(int sock, const char *brname){ return 0; } int linux_br_del(int sock, const char *brname){ return 0; } int linux_br_add_if(int sock, const char *brname, const char *ifname){ return 0; } int linux_br_del_if(int sock, const char *brname, const char *ifname){ return 0; } int linux_br_get(char *brname, const char *ifname){ return 0; } ================================================ FILE: hostapd_wrapper/src/drivers/linux_ioctl_fake.h ================================================ /* * Linux ioctl helper functions for driver wrappers * Copyright (c) 2002-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef LINUX_IOCTL_H #define LINUX_IOCTL_H int linux_set_iface_flags(int sock, const char *ifname, int dev_up); int linux_iface_up(int sock, const char *ifname); int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr); int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr); int linux_br_add(int sock, const char *brname); int linux_br_del(int sock, const char *brname); int linux_br_add_if(int sock, const char *brname, const char *ifname); int linux_br_del_if(int sock, const char *brname, const char *ifname); int linux_br_get(char *brname, const char *ifname); #endif /* LINUX_IOCTL_H */ ================================================ FILE: hostapd_wrapper/src/drivers/netlink_fake.c ================================================ /* * Netlink helper functions for driver wrappers * Copyright (c) 2002-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "eloop.h" #include "priv_netlink.h" #include "netlink_fake.h" struct netlink_data { struct netlink_config *cfg; int sock; }; static void netlink_receive_link(struct netlink_data *netlink, void (*cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len), struct nlmsghdr *h) { return; } static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx) { return; } struct netlink_data * netlink_init(struct netlink_config *cfg) { struct netlink_data *netlink; struct sockaddr_nl local; netlink = os_zalloc(sizeof(*netlink)); if (netlink == NULL) return NULL; netlink->cfg = cfg; netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); os_memset(&local, 0, sizeof(local)); local.nl_family = AF_NETLINK; local.nl_groups = RTMGRP_LINK; eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL); return netlink; } void netlink_deinit(struct netlink_data *netlink) { return; } int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, int linkmode, int operstate){ return 0; } ================================================ FILE: hostapd_wrapper/src/drivers/netlink_fake.h ================================================ /* * Netlink helper functions for driver wrappers * Copyright (c) 2002-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef NETLINK_H #define NETLINK_H struct netlink_data; struct ifinfomsg; struct netlink_config { void *ctx; void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len); void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len); }; struct netlink_data * netlink_init(struct netlink_config *cfg); void netlink_deinit(struct netlink_data *netlink); int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, int linkmode, int operstate); #endif /* NETLINK_H */ ================================================ FILE: ieee802_11_defs.h ================================================ /* * IEEE 802.11 Frame type definitions * Copyright (c) 2002-2009, Jouni Malinen * Copyright (c) 2007-2008 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef IEEE802_11_DEFS_H #define IEEE802_11_DEFS_H /* IEEE 802.11 defines */ #define WLAN_FC_PVER 0x0003 #define WLAN_FC_TODS 0x0100 #define WLAN_FC_FROMDS 0x0200 #define WLAN_FC_MOREFRAG 0x0400 #define WLAN_FC_RETRY 0x0800 #define WLAN_FC_PWRMGT 0x1000 #define WLAN_FC_MOREDATA 0x2000 #define WLAN_FC_ISWEP 0x4000 #define WLAN_FC_ORDER 0x8000 #define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) #define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) #define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) #define WLAN_GET_SEQ_SEQ(seq) \ (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) #define WLAN_FC_TYPE_MGMT 0 #define WLAN_FC_TYPE_CTRL 1 #define WLAN_FC_TYPE_DATA 2 /* management */ #define WLAN_FC_STYPE_ASSOC_REQ 0 #define WLAN_FC_STYPE_ASSOC_RESP 1 #define WLAN_FC_STYPE_REASSOC_REQ 2 #define WLAN_FC_STYPE_REASSOC_RESP 3 #define WLAN_FC_STYPE_PROBE_REQ 4 #define WLAN_FC_STYPE_PROBE_RESP 5 #define WLAN_FC_STYPE_BEACON 8 #define WLAN_FC_STYPE_ATIM 9 #define WLAN_FC_STYPE_DISASSOC 10 #define WLAN_FC_STYPE_AUTH 11 #define WLAN_FC_STYPE_DEAUTH 12 #define WLAN_FC_STYPE_ACTION 13 /* control */ #define WLAN_FC_STYPE_PSPOLL 10 #define WLAN_FC_STYPE_RTS 11 #define WLAN_FC_STYPE_CTS 12 #define WLAN_FC_STYPE_ACK 13 #define WLAN_FC_STYPE_CFEND 14 #define WLAN_FC_STYPE_CFENDACK 15 /* data */ #define WLAN_FC_STYPE_DATA 0 #define WLAN_FC_STYPE_DATA_CFACK 1 #define WLAN_FC_STYPE_DATA_CFPOLL 2 #define WLAN_FC_STYPE_DATA_CFACKPOLL 3 #define WLAN_FC_STYPE_NULLFUNC 4 #define WLAN_FC_STYPE_CFACK 5 #define WLAN_FC_STYPE_CFPOLL 6 #define WLAN_FC_STYPE_CFACKPOLL 7 #define WLAN_FC_STYPE_QOS_DATA 8 #define WLAN_FC_STYPE_QOS_DATA_CFACK 9 #define WLAN_FC_STYPE_QOS_DATA_CFPOLL 10 #define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL 11 #define WLAN_FC_STYPE_QOS_NULL 12 #define WLAN_FC_STYPE_QOS_CFPOLL 14 #define WLAN_FC_STYPE_QOS_CFACKPOLL 15 /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 #define WLAN_AUTH_FT 2 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 #define WLAN_CAPABILITY_ESS BIT(0) #define WLAN_CAPABILITY_IBSS BIT(1) #define WLAN_CAPABILITY_CF_POLLABLE BIT(2) #define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) #define WLAN_CAPABILITY_PRIVACY BIT(4) #define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5) #define WLAN_CAPABILITY_PBCC BIT(6) #define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) #define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) #define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) #define WLAN_CAPABILITY_DSSS_OFDM BIT(13) /* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ #define WLAN_STATUS_SUCCESS 0 #define WLAN_STATUS_UNSPECIFIED_FAILURE 1 #define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2 #define WLAN_STATUS_TDLS_WAKEUP_REJECT 3 #define WLAN_STATUS_SECURITY_DISABLED 5 #define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6 #define WLAN_STATUS_NOT_IN_SAME_BSS 7 #define WLAN_STATUS_CAPS_UNSUPPORTED 10 #define WLAN_STATUS_REASSOC_NO_ASSOC 11 #define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 #define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 #define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 #define WLAN_STATUS_CHALLENGE_FAIL 15 #define WLAN_STATUS_AUTH_TIMEOUT 16 #define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 #define WLAN_STATUS_ASSOC_DENIED_RATES 18 /* IEEE 802.11b */ #define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 #define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 #define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 /* IEEE 802.11h */ #define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 #define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 #define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 /* IEEE 802.11g */ #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 #define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26 #define WLAN_STATUS_ASSOC_DENIED_NO_HT 27 #define WLAN_STATUS_R0KH_UNREACHABLE 28 #define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29 /* IEEE 802.11w */ #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 #define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 #define WLAN_STATUS_REQUEST_DECLINED 37 #define WLAN_STATUS_INVALID_PARAMETERS 38 /* IEEE 802.11i */ #define WLAN_STATUS_INVALID_IE 40 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 #define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 #define WLAN_STATUS_AKMP_NOT_VALID 43 #define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 #define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 #define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 #define WLAN_STATUS_TS_NOT_CREATED 47 #define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 #define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 #define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 #define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 /* IEEE 802.11r */ #define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 #define WLAN_STATUS_INVALID_PMKID 53 #define WLAN_STATUS_INVALID_MDIE 54 #define WLAN_STATUS_INVALID_FTIE 55 #define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59 #define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60 #define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61 #define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62 #define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63 #define WLAN_STATUS_REQ_REFUSED_HOME 64 #define WLAN_STATUS_ADV_SRV_UNREACHABLE 65 #define WLAN_STATUS_REQ_REFUSED_SSPN 67 #define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68 #define WLAN_STATUS_INVALID_RSNIE 72 #define WLAN_STATUS_TRANSMISSION_FAILURE 79 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 #define WLAN_REASON_PREV_AUTH_NOT_VALID 2 #define WLAN_REASON_DEAUTH_LEAVING 3 #define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 #define WLAN_REASON_DISASSOC_AP_BUSY 5 #define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 #define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 #define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 /* IEEE 802.11h */ #define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 #define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 /* IEEE 802.11i */ #define WLAN_REASON_INVALID_IE 13 #define WLAN_REASON_MICHAEL_MIC_FAILURE 14 #define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 #define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 #define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 #define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 #define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 #define WLAN_REASON_AKMP_NOT_VALID 20 #define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 #define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24 #define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25 #define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26 /* IEEE 802.11e */ #define WLAN_REASON_DISASSOC_LOW_ACK 34 /* Information Element IDs */ #define WLAN_EID_SSID 0 #define WLAN_EID_SUPP_RATES 1 #define WLAN_EID_FH_PARAMS 2 #define WLAN_EID_DS_PARAMS 3 #define WLAN_EID_CF_PARAMS 4 #define WLAN_EID_TIM 5 #define WLAN_EID_IBSS_PARAMS 6 #define WLAN_EID_COUNTRY 7 #define WLAN_EID_CHALLENGE 16 /* EIDs defined by IEEE 802.11h - START */ #define WLAN_EID_PWR_CONSTRAINT 32 #define WLAN_EID_PWR_CAPABILITY 33 #define WLAN_EID_TPC_REQUEST 34 #define WLAN_EID_TPC_REPORT 35 #define WLAN_EID_SUPPORTED_CHANNELS 36 #define WLAN_EID_CHANNEL_SWITCH 37 #define WLAN_EID_MEASURE_REQUEST 38 #define WLAN_EID_MEASURE_REPORT 39 #define WLAN_EID_QUITE 40 #define WLAN_EID_IBSS_DFS 41 /* EIDs defined by IEEE 802.11h - END */ #define WLAN_EID_ERP_INFO 42 #define WLAN_EID_HT_CAP 45 #define WLAN_EID_RSN 48 #define WLAN_EID_EXT_SUPP_RATES 50 #define WLAN_EID_MOBILITY_DOMAIN 54 #define WLAN_EID_FAST_BSS_TRANSITION 55 #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_TIME_ADVERTISEMENT 69 #define WLAN_EID_20_40_BSS_COEXISTENCE 72 #define WLAN_EID_20_40_BSS_INTOLERANT 73 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 #define WLAN_EID_MMIE 76 #define WLAN_EID_TIME_ZONE 98 #define WLAN_EID_LINK_ID 101 #define WLAN_EID_INTERWORKING 107 #define WLAN_EID_ADV_PROTO 108 #define WLAN_EID_ROAMING_CONSORTIUM 111 #define WLAN_EID_EXT_CAPAB 127 #define WLAN_EID_VENDOR_SPECIFIC 221 /* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ #define WLAN_ACTION_SPECTRUM_MGMT 0 #define WLAN_ACTION_QOS 1 #define WLAN_ACTION_DLS 2 #define WLAN_ACTION_BLOCK_ACK 3 #define WLAN_ACTION_PUBLIC 4 #define WLAN_ACTION_RADIO_MEASUREMENT 5 #define WLAN_ACTION_FT 6 #define WLAN_ACTION_HT 7 #define WLAN_ACTION_SA_QUERY 8 #define WLAN_ACTION_WNM 10 #define WLAN_ACTION_UNPROTECTED_WNM 11 #define WLAN_ACTION_TDLS 12 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ #define WLAN_ACTION_VENDOR_SPECIFIC 127 /* Public action codes */ #define WLAN_PA_VENDOR_SPECIFIC 9 #define WLAN_PA_GAS_INITIAL_REQ 10 #define WLAN_PA_GAS_INITIAL_RESP 11 #define WLAN_PA_GAS_COMEBACK_REQ 12 #define WLAN_PA_GAS_COMEBACK_RESP 13 #define WLAN_TDLS_DISCOVERY_RESPONSE 14 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ #define WLAN_SA_QUERY_REQUEST 0 #define WLAN_SA_QUERY_RESPONSE 1 #define WLAN_SA_QUERY_TR_ID_LEN 2 /* TDLS action codes */ #define WLAN_TDLS_SETUP_REQUEST 0 #define WLAN_TDLS_SETUP_RESPONSE 1 #define WLAN_TDLS_SETUP_CONFIRM 2 #define WLAN_TDLS_TEARDOWN 3 #define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4 #define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5 #define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6 #define WLAN_TDLS_PEER_PSM_REQUEST 7 #define WLAN_TDLS_PEER_PSM_RESPONSE 8 #define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9 #define WLAN_TDLS_DISCOVERY_REQUEST 10 /* Timeout Interval Type */ #define WLAN_TIMEOUT_REASSOC_DEADLINE 1 #define WLAN_TIMEOUT_KEY_LIFETIME 2 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3 /* Interworking element (IEEE 802.11u) - Access Network Options */ #define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f #define INTERWORKING_ANO_INTERNET 0x10 #define INTERWORKING_ANO_ASRA 0x20 #define INTERWORKING_ANO_ESR 0x40 #define INTERWORKING_ANO_UESA 0x80 #define INTERWORKING_ANT_PRIVATE 0 #define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1 #define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2 #define INTERWORKING_ANT_FREE_PUBLIC 3 #define INTERWORKING_ANT_PERSONAL_DEVICE 4 #define INTERWORKING_ANT_EMERGENCY_SERVICES 5 #define INTERWORKING_ANT_TEST 6 #define INTERWORKING_ANT_WILDCARD 15 /* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */ enum adv_proto_id { ACCESS_NETWORK_QUERY_PROTOCOL = 0, MIH_INFO_SERVICE = 1, MIH_CMD_AND_EVENT_DISCOVERY = 2, EMERGENCY_ALERT_SYSTEM = 3, ADV_PROTO_VENDOR_SPECIFIC = 221 }; /* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */ enum anqp_info_id { ANQP_QUERY_LIST = 256, ANQP_CAPABILITY_LIST = 257, ANQP_VENUE_NAME = 258, ANQP_EMERGENCY_CALL_NUMBER = 259, ANQP_NETWORK_AUTH_TYPE = 260, ANQP_ROAMING_CONSORTIUM = 261, ANQP_IP_ADDR_TYPE_AVAILABILITY = 262, ANQP_NAI_REALM = 263, ANQP_3GPP_CELLULAR_NETWORK = 264, ANQP_AP_GEOSPATIAL_LOCATION = 265, ANQP_AP_CIVIC_LOCATION = 266, ANQP_AP_LOCATION_PUBLIC_URI = 267, ANQP_DOMAIN_NAME = 268, ANQP_EMERGENCY_ALERT_URI = 269, ANQP_EMERGENCY_NAI = 271, ANQP_VENDOR_SPECIFIC = 56797 }; /* NAI Realm list - EAP Method subfield - Authentication Parameter ID */ enum nai_realm_eap_auth_param { NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1, NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2, NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3, NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4, NAI_REALM_EAP_AUTH_CRED_TYPE = 5, NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6, NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221 }; enum nai_realm_eap_auth_inner_non_eap { NAI_REALM_INNER_NON_EAP_PAP = 1, NAI_REALM_INNER_NON_EAP_CHAP = 2, NAI_REALM_INNER_NON_EAP_MSCHAP = 3, NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4 }; enum nai_realm_eap_cred_type { NAI_REALM_CRED_TYPE_SIM = 1, NAI_REALM_CRED_TYPE_USIM = 2, NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3, NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4, NAI_REALM_CRED_TYPE_SOFTOKEN = 5, NAI_REALM_CRED_TYPE_CERTIFICATE = 6, NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7, NAI_REALM_CRED_TYPE_NONE = 8, NAI_REALM_CRED_TYPE_ANONYMOUS = 9, NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10 }; #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ struct ieee80211_hdr { le16 frame_control; le16 duration_id; u8 addr1[6]; u8 addr2[6]; u8 addr3[6]; le16 seq_ctrl; /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame */ } STRUCT_PACKED; #define IEEE80211_DA_FROMDS addr1 #define IEEE80211_BSSID_FROMDS addr2 #define IEEE80211_SA_FROMDS addr3 #define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) #define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) struct ieee80211_mgmt { le16 frame_control; le16 duration; u8 da[6]; u8 sa[6]; u8 bssid[6]; le16 seq_ctrl; union { struct { le16 auth_alg; le16 auth_transaction; le16 status_code; /* possibly followed by Challenge text */ u8 variable[0]; } STRUCT_PACKED auth; struct { le16 reason_code; u8 variable[0]; } STRUCT_PACKED deauth; struct { le16 capab_info; le16 listen_interval; /* followed by SSID and Supported rates */ u8 variable[0]; } STRUCT_PACKED assoc_req; struct { le16 capab_info; le16 status_code; le16 aid; /* followed by Supported rates */ u8 variable[0]; } STRUCT_PACKED assoc_resp, reassoc_resp; struct { le16 capab_info; le16 listen_interval; u8 current_ap[6]; /* followed by SSID and Supported rates */ u8 variable[0]; } STRUCT_PACKED reassoc_req; struct { le16 reason_code; u8 variable[0]; } STRUCT_PACKED disassoc; struct { u8 timestamp[8]; le16 beacon_int; le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params, TIM */ u8 variable[0]; } STRUCT_PACKED beacon; struct { /* only variable items: SSID, Supported rates */ u8 variable[0]; } STRUCT_PACKED probe_req; struct { u8 timestamp[8]; le16 beacon_int; le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params */ u8 variable[0]; } STRUCT_PACKED probe_resp; struct { u8 category; union { struct { u8 action_code; u8 dialog_token; u8 status_code; u8 variable[0]; } STRUCT_PACKED wmm_action; struct { u8 action_code; u8 element_id; u8 length; u8 switch_mode; u8 new_chan; u8 switch_count; } STRUCT_PACKED chan_switch; struct { u8 action; u8 sta_addr[ETH_ALEN]; u8 target_ap_addr[ETH_ALEN]; u8 variable[0]; /* FT Request */ } STRUCT_PACKED ft_action_req; struct { u8 action; u8 sta_addr[ETH_ALEN]; u8 target_ap_addr[ETH_ALEN]; le16 status_code; u8 variable[0]; /* FT Request */ } STRUCT_PACKED ft_action_resp; struct { u8 action; u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; } STRUCT_PACKED sa_query_req; struct { u8 action; /* */ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; } STRUCT_PACKED sa_query_resp; struct { u8 action; u8 variable[0]; } STRUCT_PACKED public_action; struct { u8 action; /* 9 */ u8 oui[3]; /* Vendor-specific content */ u8 variable[0]; } STRUCT_PACKED vs_public_action; struct { u8 action; /* 7 */ u8 dialog_token; u8 req_mode; le16 disassoc_timer; u8 validity_interval; /* BSS Termination Duration (optional), * Session Information URL (optional), * BSS Transition Candidate List * Entries */ u8 variable[0]; } STRUCT_PACKED bss_tm_req; } u; } STRUCT_PACKED action; } u; } STRUCT_PACKED; struct ieee80211_ht_capabilities { le16 ht_capabilities_info; u8 a_mpdu_params; u8 supported_mcs_set[16]; le16 ht_extended_capabilities; le32 tx_bf_capability_info; u8 asel_capabilities; } STRUCT_PACKED; struct ieee80211_ht_operation { u8 control_chan; u8 ht_param; le16 operation_mode; le16 stbc_param; u8 basic_set[16]; } STRUCT_PACKED; #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ #define ERP_INFO_NON_ERP_PRESENT BIT(0) #define ERP_INFO_USE_PROTECTION BIT(1) #define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) #define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) #define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) #define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) #define HT_CAP_INFO_SMPS_STATIC ((u16) 0) #define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) #define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) #define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) #define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) #define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) #define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) #define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) #define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) #define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) #define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) #define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) #define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) #define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) #define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) #define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) #define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) #define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) #define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 #define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 #define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10)) #define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11)) #define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0)) #define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1)) #define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2)) #define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3)) #define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4)) #define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5)) #define TX_BEAMFORM_CAP_CALIB_OFFSET 6 #define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8)) #define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9)) #define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10)) #define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11 #define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13 #define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15 #define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17 #define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19 #define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21 #define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23 #define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25 #define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0)) #define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1)) #define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2)) #define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3)) #define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4)) #define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) #define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) #define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) #define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) #define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) #define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) #define OP_MODE_PURE 0 #define OP_MODE_MAY_BE_LEGACY_STAS 1 #define OP_MODE_20MHZ_HT_STA_ASSOCED 2 #define OP_MODE_MIXED 3 #define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ ((le16) (0x0001 | 0x0002)) #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 #define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) #define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) #define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) #define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) #define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) #define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) #define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) #define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WPA_IE_VENDOR_TYPE 0x0050f201 #define WPS_IE_VENDOR_TYPE 0x0050f204 #define OUI_WFA 0x506f9a #define P2P_IE_VENDOR_TYPE 0x506f9a09 #define WMM_OUI_TYPE 2 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 #define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 #define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 #define WMM_VERSION 1 #define WMM_ACTION_CODE_ADDTS_REQ 0 #define WMM_ACTION_CODE_ADDTS_RESP 1 #define WMM_ACTION_CODE_DELTS 2 #define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0 #define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1 /* 2 - Reserved */ #define WMM_ADDTS_STATUS_REFUSED 3 /* 4-255 - Reserved */ /* WMM TSPEC Direction Field Values */ #define WMM_TSPEC_DIRECTION_UPLINK 0 #define WMM_TSPEC_DIRECTION_DOWNLINK 1 /* 2 - Reserved */ #define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 /* * WMM Information Element (used in (Re)Association Request frames; may also be * used in Beacon frames) */ struct wmm_information_element { /* Element ID: 221 (0xdd); Length: 7 */ /* required fields for WMM version 1 */ u8 oui[3]; /* 00:50:f2 */ u8 oui_type; /* 2 */ u8 oui_subtype; /* 0 */ u8 version; /* 1 for WMM version 1.0 */ u8 qos_info; /* AP/STA specific QoS info */ } STRUCT_PACKED; #define WMM_AC_AIFSN_MASK 0x0f #define WMM_AC_AIFNS_SHIFT 0 #define WMM_AC_ACM 0x10 #define WMM_AC_ACI_MASK 0x60 #define WMM_AC_ACI_SHIFT 5 #define WMM_AC_ECWMIN_MASK 0x0f #define WMM_AC_ECWMIN_SHIFT 0 #define WMM_AC_ECWMAX_MASK 0xf0 #define WMM_AC_ECWMAX_SHIFT 4 struct wmm_ac_parameter { u8 aci_aifsn; /* AIFSN, ACM, ACI */ u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ le16 txop_limit; } STRUCT_PACKED; /* * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association * Response frmaes) */ struct wmm_parameter_element { /* Element ID: 221 (0xdd); Length: 24 */ /* required fields for WMM version 1 */ u8 oui[3]; /* 00:50:f2 */ u8 oui_type; /* 2 */ u8 oui_subtype; /* 1 */ u8 version; /* 1 for WMM version 1.0 */ u8 qos_info; /* AP/STA specific QoS info */ u8 reserved; /* 0 */ struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ } STRUCT_PACKED; /* WMM TSPEC Element */ struct wmm_tspec_element { u8 eid; /* 221 = 0xdd */ u8 length; /* 6 + 55 = 61 */ u8 oui[3]; /* 00:50:f2 */ u8 oui_type; /* 2 */ u8 oui_subtype; /* 2 */ u8 version; /* 1 */ /* WMM TSPEC body (55 octets): */ u8 ts_info[3]; le16 nominal_msdu_size; le16 maximum_msdu_size; le32 minimum_service_interval; le32 maximum_service_interval; le32 inactivity_interval; le32 suspension_interval; le32 service_start_time; le32 minimum_data_rate; le32 mean_data_rate; le32 peak_data_rate; le32 maximum_burst_size; le32 delay_bound; le32 minimum_phy_rate; le16 surplus_bandwidth_allowance; le16 medium_time; } STRUCT_PACKED; /* Access Categories / ACI to AC coding */ enum { WMM_AC_BE = 0 /* Best Effort */ , WMM_AC_BK = 1 /* Background */ , WMM_AC_VI = 2 /* Video */ , WMM_AC_VO = 3 /* Voice */ }; /* Wi-Fi Direct (P2P) */ #define P2P_OUI_TYPE 9 enum p2p_attr_id { P2P_ATTR_STATUS = 0, P2P_ATTR_MINOR_REASON_CODE = 1, P2P_ATTR_CAPABILITY = 2, P2P_ATTR_DEVICE_ID = 3, P2P_ATTR_GROUP_OWNER_INTENT = 4, P2P_ATTR_CONFIGURATION_TIMEOUT = 5, P2P_ATTR_LISTEN_CHANNEL = 6, P2P_ATTR_GROUP_BSSID = 7, P2P_ATTR_EXT_LISTEN_TIMING = 8, P2P_ATTR_INTENDED_INTERFACE_ADDR = 9, P2P_ATTR_MANAGEABILITY = 10, P2P_ATTR_CHANNEL_LIST = 11, P2P_ATTR_NOTICE_OF_ABSENCE = 12, P2P_ATTR_DEVICE_INFO = 13, P2P_ATTR_GROUP_INFO = 14, P2P_ATTR_GROUP_ID = 15, P2P_ATTR_INTERFACE = 16, P2P_ATTR_OPERATING_CHANNEL = 17, P2P_ATTR_INVITATION_FLAGS = 18, P2P_ATTR_VENDOR_SPECIFIC = 221 }; #define P2P_MAX_GO_INTENT 15 /* P2P Capability - Device Capability bitmap */ #define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0) #define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1) #define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2) #define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3) #define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4) #define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5) /* P2P Capability - Group Capability bitmap */ #define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0) #define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1) #define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2) #define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3) #define P2P_GROUP_CAPAB_CROSS_CONN BIT(4) #define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5) #define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6) /* Invitation Flags */ #define P2P_INVITATION_FLAGS_TYPE BIT(0) /* P2P Manageability */ #define P2P_MAN_DEVICE_MANAGEMENT BIT(0) #define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1) #define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2) enum p2p_status_code { P2P_SC_SUCCESS = 0, P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1, P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2, P2P_SC_FAIL_LIMIT_REACHED = 3, P2P_SC_FAIL_INVALID_PARAMS = 4, P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5, P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6, P2P_SC_FAIL_NO_COMMON_CHANNELS = 7, P2P_SC_FAIL_UNKNOWN_GROUP = 8, P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9, P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10, P2P_SC_FAIL_REJECTED_BY_USER = 11, }; #define P2P_WILDCARD_SSID "DIRECT-" #define P2P_WILDCARD_SSID_LEN 7 /* P2P action frames */ enum p2p_act_frame_type { P2P_NOA = 0, P2P_PRESENCE_REQ = 1, P2P_PRESENCE_RESP = 2, P2P_GO_DISC_REQ = 3 }; /* P2P public action frames */ enum p2p_action_frame_type { P2P_GO_NEG_REQ = 0, P2P_GO_NEG_RESP = 1, P2P_GO_NEG_CONF = 2, P2P_INVITATION_REQ = 3, P2P_INVITATION_RESP = 4, P2P_DEV_DISC_REQ = 5, P2P_DEV_DISC_RESP = 6, P2P_PROV_DISC_REQ = 7, P2P_PROV_DISC_RESP = 8 }; enum p2p_service_protocol_type { P2P_SERV_ALL_SERVICES = 0, P2P_SERV_BONJOUR = 1, P2P_SERV_UPNP = 2, P2P_SERV_WS_DISCOVERY = 3, P2P_SERV_VENDOR_SPECIFIC = 255 }; enum p2p_sd_status { P2P_SD_SUCCESS = 0, P2P_SD_PROTO_NOT_AVAILABLE = 1, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2, P2P_SD_BAD_REQUEST = 3 }; #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ #define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ /* cipher suite selectors */ #define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 #define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 #define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 /* reserved: 0x000FAC03 */ #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 /* AKM suite selectors */ #define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_PSK 0x000FAC02 /* IEEE 802.11v - WNM Action field values */ enum wnm_action { WNM_EVENT_REQ = 0, WNM_EVENT_REPORT = 1, WNM_DIAGNOSTIC_REQ = 2, WNM_DIAGNOSTIC_REPORT = 3, WNM_LOCATION_CFG_REQ = 4, WNM_LOCATION_CFG_RESP = 5, WNM_BSS_TRANS_MGMT_QUERY = 6, WNM_BSS_TRANS_MGMT_REQ = 7, WNM_BSS_TRANS_MGMT_RESP = 8, WNM_FMS_REQ = 9, WNM_FMS_RESP = 10, WNM_COLLOCATED_INTERFERENCE_REQ = 11, WNM_COLLOCATED_INTERFERENCE_REPORT = 12, WNM_TFS_REQ = 13, WNM_TFS_RESP = 14, WNM_TFS_NOTIFY = 15, WNM_SLEEP_MODE_REQ = 16, WNM_SLEEP_MODE_RESP = 17, WNM_TIM_BROADCAST_REQ = 18, WNM_TIM_BROADCAST_RESP = 19, WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20, WNM_CHANNEL_USAGE_REQ = 21, WNM_CHANNEL_USAGE_RESP = 22, WNM_DMS_REQ = 23, WNM_DMS_RESP = 24, WNM_TIMING_MEASUREMENT_REQ = 25, WNM_NOTIFICATION_REQ = 26, WNM_NOTIFICATION_RESP = 27 }; /* IEEE 802.11v - BSS Transition Management Request - Request Mode */ #define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0) #define WNM_BSS_TM_REQ_ABRIDGED BIT(1) #define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2) #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3) #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4) #endif /* IEEE802_11_DEFS_H */ ================================================ FILE: modifiche_daniele.txt ================================================ ACBinding.c : n/c ACBinding.h : n/c AC.c : n/c ACConfigFile.c : n/c ACConfigureState.c : n/c ACDataCheckState.c : n/c ACDiscoveryState.c : n/c ACInterface.c line 106: è stata aggiunta la funzione CWActionMenu() per inserire un nuovo menù di scelte. line 243: è stata inserita la funzione CWSetInterfaceCmd() per settare la variabile gWTPs[selection].interfaceCommand al valore passato come parametro. line 404: è stata modificata la funzione CWInterface(), all'interno dello switch sono stati aggiunti due nuovi casi e e modificati alcuni di quelli già esistenti. ACInterface.h line 35: è stata aggiunta la variabile globale CLEAR_CONFIG_MSG_CMD ACJoinState.c : n/c ACMainLoop.c line 614: è stato inserito il case CLEAR_CONFIG_MSG_CMD per prevedere l'assemblaggio del messaggio ClearConfiguration. ACMultiHomedSocket.c : n/c ACMultiHomedSocket.h : n/c ACProtocol.c line 145: è stata aggiunta la funzione CWAssembleMsgElemAddStation() per l'assemblaggio dei messages elements per il msg AddStation. line 517: è stata inserita la funzione CWParseMsgElemDataTransferData() per il parsing dei messages elements contenuti nel msg DataTransfer. ACProtocol.h line 134: è stato aggiunto il prototipo della funzione CWAssembleMsgElemAddStation(); line 146: è stato aggiunto il prototipo della funzione CWParseMsgElemDataTransferData(); ACProtocol_User.c : n/c ACRetransmission.c : n/c ACRunState.c line 46: é stato aggiunto il prototipo della funzione CWParseClearConfigurationResponseMessage(); line 50: è stato aggiunto il prototipo della funzione CWParseStationConfigurationResponseMessage(); line 54: è stato aggiunto il prototipo della funzione CWParseWTPDataTransferRequestMessage(); line 58: è stato aggiunto il prototipo della funzione CWAssembleWTPDataTransferResponse(); line 97: è stata inserita la variabile StationMacAddr[MAC_ADDR_LEN] per mantenere l'indirizzo mac della stazione associata. line 101: è stato inserito un blocco di codice (fino a line 125) per le azioni da compiere nel caso l'AC riceva un pacchetto dati. line 202: è stato aggiunto il case CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_RESPONSE all'interno dello switch (line 136) per gestire la ricezione di un msg di StationConfigurationResponse. line 213: è stato inserito il case CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_RESPONSE per gestire la ricezione di un msg di ClearConfigurationResponse. line 235: è stato aggiunto il case CW_MSG_TYPE_VALUE_DATA_TRANSFER_REQUEST per la gestione di un messaggio DataTransferRequest da parte del WTP. line 388: è stata aggiunta l'implementazione della funzione CWParseClearConfigurationResponseMessage() per il parsing del ClearConfigurationResponseMessage. line 423: è stata aggiunta l'implementazione della funzione CWParseStationConfigurationResponseMessage() per il parsing del StationConfigurationResponseMessage. line 470: è stata aggiunta l'implementazione della funzione CWParseWTPDataTransferRequestMessage() per il parsing del WTPDataTransferRequest. line 735: è stata aggiunta l'implementazione della funzione CWAssembleWTPDataTransferResponse() per l'assemblaggio del WTPDataTransferResponse. line 1030: è stata aggiunta l'implementazione della funzione CWAssembleClearConfigurationRequest() per l'assemblaggio di un ClearConfigurationRequest. line 1051: è stata aggiunta l'implementazione della funzione CWAssembleStationConfigurationRequest() per l'assemblaggio di un StationConfigurationRequest. ACSettingsFile.c : n/c config.h : n/c CWAC.h line 46: è stata aggiunta la variabile MAC_ADDR_LEN line 47: è stata aggiunta la variabile DEST_ADDR_START line 48: è stata aggiunta la variabile SOURCE_ADDR_START line 160: è stato inserito il prototipo della funzione CWAssembleStationConfigurationRequest(); line 165: è stato inserito il prototipo della funzione CWAssembleClearConfigurationRequest(); CWBinding.c : n/c CWBinding.h : n/c CWCommon.c : n/c CWCommon.h : n/c CWConfigFile.c : n/c CWConfigFile.h : n/c CWErrorHandling.c : n/c CWErrorHandling.h : n/c CWList.c : n/c CWList.h : n/c CWLog.c : n/c CWLog.h : n/c CWNetwork.c : n/c CWNetwork.h : n/c CWOpenSSLBio.c : n/c CWProtocol.c : n/c CWProtocol.h line 258: è stato inserito un nuovo valore per la variabile CW_NEIGHBORDEAD_INTERVAL_DEFAULT (tale modifica si rende necessaria a causa di un problema riscontrato con la gestione dei timer a runtime da parte del WTP sull'AP). line 264: è stato inserito un nuovo valore per la variabile CW_ECHO_INTERVAL_DEFAULT (come sopra...). CWRandom.c : n/c CWRandom.h : n/c CWSafeList.c : n/c CWSafeList.h : n/c CWSecurity.c : n/c CWSecurity.h : n/c CWStevens.c : n/c CWStevens.h : n/c CWThread.c : n/c CWThread.h : n/c CWTimer.h : n/c CWWTP.h line 104: è stato aggiunto il prototipo della funzione CWAssembleWTPDataTansferRequest() implementata in WTPRunState.c line 147: è stata inserita la direttiva del preprocessore BCM per distinguere la compilazione normale dalla cross-compilazione line 159: è stata inserito il prototipo della funzione set_wme_cwmin() implementata in WTPBcmDriverInteraction.c line 160: è stata inserito il prototipo della funzione set_wme_cwmax() implementata in WTPBcmDriverInteraction.c line 170: è stata inserito il prototipo della funzione set_wme_aifsn() implementata in WTPBcmDriverInteraction.c timerlib.c : n/c timerlib.h : n/c wireless_copy.h : n/c WTPBcmDriverInteraction.c/.h : nuovo file introdotto per la gestione delle ioctl per l'accesso ai driver Broadcom. WTPBcmFrameReceive.c/.h : nuovo file introdotto per la gestione delle ioctl per l'accesso ai driver Broadcom.(ricezione frame dalle stazioni). WTPBinding.c line 90: è stata inserita la direttiva del preprocessore BCM per distinguere la compilazione normale dalla cross-compilazione line 91: è stata inserito un duplicato della CWWTPInitBinding() per la cross comiplazione per inizializzare i valori del QoS sui driver Broadcom. line 184: è stata inserito un duplicato della CWBindingSetQosValues() per la cross compilazione per la chiamata delle funzioni set_wme_* che agiscono sui driver Broadcom. WTPBinding.h : n/c WTP.c : n/c WTPConfigFile.c : n/c WTPConfigureState.c : n/c WTPDataCheckState.c : n/c WTPDiscoveryState.c : n/c WTPDriverInteraction.c : n/c WTPFrameReceive.c : n/c WTPFrameReceive.h : n/c WTPJoinState.c : n/c WTPProtocol.c line 98: è stata aggiunta l'implementazione della funzione CWAssembleMsgElemDataTransferData() per l'asemblaggio del msg elements Data presente nel messaggio capwap DataTransfer line 806: implementazione della funzione CWParseAddStation() per il parsing del msg element AddStation. WTPProtocol.h line 93: aggiunta del prototipo della funzione CWAssembleMsgElemDataTransferData(); line 115: aggiunta del prototipo della funzione CWParseAddStation(); WTPProtocol_User.c : n/c WTPRetransmission.c : n/c WTPRunState.c line 66: aggiunta del prototipo della funzione CWSaveClearConfigurationRequest(); line 68: aggiunta del prototipo della funzione CWAssembleClearConfigurationResponse(); line 74: aggiunta del prototipo della funzione CWAssembleStationConfigurationResponse(); line 80: aggiunta del prototipo della funzione CWParseStationConfigurationRequest(); line 270: è stato aggiunto il case CW_MSG_TYPE_VALUE_CLEAR_CONFIGURATION_REQUEST per gestire il msg di ClearConfigurationRequest line 285: è stato aggiunto il case CW_MSG_TYPE_VALUE_STATION_CONFIGURATION_REQUEST per gestire il msg di StationConfigurationRequest line 568: è stata aggiunta l'implementazione della CWAssembleWTPDataTransferRequest() per l'assemblaggio del msg DataTransferRequest. line 785: è stata aggiunta l'implementazione della CWAssembleClearConfigurationResponse()per l'assemblaggio della risposta ad un ClearConfigurationRequest line 825: è stata aggiunta l'implementazione della CWAssembleStationConfigurationResponse()per l'assemblaggio della risposta ad uno StationConfigurationRequest line 923: è stata aggiunta l'implementazione della CWParseStationConfigurationRequest() per il parsing di un msg di StationConfigurationRequest line 1040: implementazione della CWSaveClearConfigurationRequest(); WTPRunStateCheck.c : n/c WTPSettingsFile.c : n/c WTPSulkingState.c : n/c ================================================ FILE: modifiche_uci_frequency_2009.txt ================================================ Capwap README 2009: Uci - Frequency DISCLAIMER: If you want to realize new capabilities into the OpenCapwap Protocol, you need to read the IETF draft writed by CAPWAP Working Group and ACAppsProtocol.h (inside Capwap directoy) first, then you need to modify the Application server which we talk about below is just a way of centering application development, it's not meant to bypass coding in the OpenCapwap code base (many message elements are still missing, so you may have to implement some new ones). AC side: - All sockets, previously Unix sockets, are now Inet sockets. To let the Access Controller receive multiple connections from other applications (the ones which add fuctionality), we added to ACInterface a multi-thread TCP server. This TCP server provides to external applications the possibility to talk to the connected Wireless Termination Points tunnelling packets through the Capwap protocol. When the AC server is started, a standalone thread is spawned to manage the various applications' requests. Every time the TCP server receives a new connection, a new thread is spawned to manage that one specific external application. The communication between the AC (through the TCP server) and external applications is ruled by a protocol which (we hope) will be used for every other application (even those which are not yet implemented) as is. This simple protocol is basically made of the command id, the WTP id, the length of the attached payload and the payload itself (refer to ACAppsProtocol.h for header specs). The protocol's main commands are LIST_MSG and CONF_UPDATE_MSG: LIST_MSG returns the list of the WTPs attached to the AC CONF_UPDATE_MSG lets the application send a Capwap Configuration Update Request Message to a single (or all) connected WTP. At the moment, implemented Configuration Update Request/Response message elements are: - OFDM Element Type ( Binding 802.11 ) - Vendor Specific Payload Type *** All other element types are NOT yet implemented in the OpenCapwap protocol (except those already implemented) WTP side: Frequencies Management: To realize Frequencies management inside Capwap WTP we added an additional parsing of Configuration Update Request Message (inside code of 802.11 Binding) with Orthogonal Frequency Division Multiplexing (OFDM) Element Type. (This message, when sent by AC, force the WTP to adhere to received values). When a new OFDM message is received, the WTP provide to forward it, through an inet socket (udp), to an external application that will do the corrispondent operations (scanning, monitoring, setting). We added a new thread too (WTPFreqStatsReceive) inside WTP that receive the statistics packets (or ack packet, for frequency setting operation) and provide to encapsulate them in CAPWAP Data Message that will recognize by AC through an apposite flag (for more informations see CWBinding.h). Remote UCI command execution via Vendor Specific Payload: OpenCapwap was used to deploy basic remote administration and configuration to a number of access points. The access points use OpenWrt (http://openwrt.org/) running the OpenCapwap WTP daemon. Since OpenWrt comes with a very handy, centralized configuration utility called UCI, custom Vendor Specific Payloads have been coded to implement Uci Vendor Specific Payloads. These custom payloads basically carry uci commands to be executed on one or more wtps (the access points). When the AC issues a Configuration Update Request containing an Uci Vendor Specific Payload to a WTP, the WTP daemon unpacks it and forwards the command to be executed to an external application. The WTP daemon and the external application talk through an inet socket (udp). The external application basically executes the command and signals back the daemon if the command succeded/failed. The WTP daemon then forwards this response to the AC via a Configuration Update Response carrying an Uci Vendor Specific Payload. (For more information see CWVendorPayloads.h) These messages have all been handled by some new code which is completely separated from the 802.11 Binding Code. This code is essentially meant to manage Capwap Protocol Element Types (which couldn't be treated as part of a specific Technology Binding). ================================================ FILE: os.h ================================================ /* * OS specific functions * Copyright (c) 2005-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef OS_H #define OS_H typedef long os_time_t; /** * os_sleep - Sleep (sec, usec) * @sec: Number of seconds to sleep * @usec: Number of microseconds to sleep */ void os_sleep(os_time_t sec, os_time_t usec); struct os_time { os_time_t sec; os_time_t usec; }; /** * os_get_time - Get current time (sec, usec) * @t: Pointer to buffer for the time * Returns: 0 on success, -1 on failure */ int os_get_time(struct os_time *t); /* Helper macros for handling struct os_time */ #define os_time_before(a, b) \ ((a)->sec < (b)->sec || \ ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) #define os_time_sub(a, b, res) do { \ (res)->sec = (a)->sec - (b)->sec; \ (res)->usec = (a)->usec - (b)->usec; \ if ((res)->usec < 0) { \ (res)->sec--; \ (res)->usec += 1000000; \ } \ } while (0) /** * os_mktime - Convert broken-down time into seconds since 1970-01-01 * @year: Four digit year * @month: Month (1 .. 12) * @day: Day of month (1 .. 31) * @hour: Hour (0 .. 23) * @min: Minute (0 .. 59) * @sec: Second (0 .. 60) * @t: Buffer for returning calendar time representation (seconds since * 1970-01-01 00:00:00) * Returns: 0 on success, -1 on failure * * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time * which is used by POSIX mktime(). */ int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t * t); struct os_tm { int sec; /* 0..59 or 60 for leap seconds */ int min; /* 0..59 */ int hour; /* 0..23 */ int day; /* 1..31 */ int month; /* 1..12 */ int year; /* Four digit year */ }; int os_gmtime(os_time_t t, struct os_tm *tm); /** * os_daemonize - Run in the background (detach from the controlling terminal) * @pid_file: File name to write the process ID to or %NULL to skip this * Returns: 0 on success, -1 on failure */ int os_daemonize(const char *pid_file); /** * os_daemonize_terminate - Stop running in the background (remove pid file) * @pid_file: File name to write the process ID to or %NULL to skip this */ void os_daemonize_terminate(const char *pid_file); /** * os_get_random - Get cryptographically strong pseudo random data * @buf: Buffer for pseudo random data * @len: Length of the buffer * Returns: 0 on success, -1 on failure */ int os_get_random(unsigned char *buf, size_t len); /** * os_random - Get pseudo random value (not necessarily very strong) * Returns: Pseudo random value */ unsigned long os_random(void); /** * os_rel2abs_path - Get an absolute path for a file * @rel_path: Relative path to a file * Returns: Absolute path for the file or %NULL on failure * * This function tries to convert a relative path of a file to an absolute path * in order for the file to be found even if current working directory has * changed. The returned value is allocated and caller is responsible for * freeing it. It is acceptable to just return the same path in an allocated * buffer, e.g., return strdup(rel_path). This function is only used to find * configuration files when os_daemonize() may have changed the current working * directory and relative path would be pointing to a different location. */ char *os_rel2abs_path(const char *rel_path); /** * os_program_init - Program initialization (called at start) * Returns: 0 on success, -1 on failure * * This function is called when a programs starts. If there are any OS specific * processing that is needed, it can be placed here. It is also acceptable to * just return 0 if not special processing is needed. */ int os_program_init(void); /** * os_program_deinit - Program deinitialization (called just before exit) * * This function is called just before a program exists. If there are any OS * specific processing, e.g., freeing resourced allocated in os_program_init(), * it should be done here. It is also acceptable for this function to do * nothing. */ void os_program_deinit(void); /** * os_setenv - Set environment variable * @name: Name of the variable * @value: Value to set to the variable * @overwrite: Whether existing variable should be overwritten * Returns: 0 on success, -1 on error * * This function is only used for wpa_cli action scripts. OS wrapper does not * need to implement this if such functionality is not needed. */ int os_setenv(const char *name, const char *value, int overwrite); /** * os_unsetenv - Delete environent variable * @name: Name of the variable * Returns: 0 on success, -1 on error * * This function is only used for wpa_cli action scripts. OS wrapper does not * need to implement this if such functionality is not needed. */ int os_unsetenv(const char *name); /** * os_readfile - Read a file to an allocated memory buffer * @name: Name of the file to read * @len: For returning the length of the allocated buffer * Returns: Pointer to the allocated buffer or %NULL on failure * * This function allocates memory and reads the given file to this buffer. Both * binary and text files can be read with this function. The caller is * responsible for freeing the returned buffer with os_free(). */ char *os_readfile(const char *name, size_t * len); /** * os_zalloc - Allocate and zero memory * @size: Number of bytes to allocate * Returns: Pointer to allocated and zeroed memory or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). */ void *os_zalloc(size_t size); /* * The following functions are wrapper for standard ANSI C or POSIX functions. * By default, they are just defined to use the standard function name and no * os_*.c implementation is needed for them. This avoids extra function calls * by allowing the C pre-processor take care of the function name mapping. * * If the target system uses a C library that does not provide these functions, * build_config.h can be used to define the wrappers to use a different * function name. This can be done on function-by-function basis since the * defines here are only used if build_config.h does not define the os_* name. * If needed, os_*.c file can be used to implement the functions that are not * included in the C library on the target system. Alternatively, * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case * these functions need to be implemented in os_*.c file for the target system. */ #ifdef OS_NO_C_LIB_DEFINES /** * os_malloc - Allocate dynamic memory * @size: Size of the buffer to allocate * Returns: Allocated buffer or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). */ void *os_malloc(size_t size); /** * os_realloc - Re-allocate dynamic memory * @ptr: Old buffer from os_malloc() or os_realloc() * @size: Size of the new buffer * Returns: Allocated buffer or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). * If re-allocation fails, %NULL is returned and the original buffer (ptr) is * not freed and caller is still responsible for freeing it. */ void *os_realloc(void *ptr, size_t size); /** * os_free - Free dynamic memory * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL */ void os_free(void *ptr); /** * os_memcpy - Copy memory area * @dest: Destination * @src: Source * @n: Number of bytes to copy * Returns: dest * * The memory areas src and dst must not overlap. os_memmove() can be used with * overlapping memory. */ void *os_memcpy(void *dest, const void *src, size_t n); /** * os_memmove - Copy memory area * @dest: Destination * @src: Source * @n: Number of bytes to copy * Returns: dest * * The memory areas src and dst may overlap. */ void *os_memmove(void *dest, const void *src, size_t n); /** * os_memset - Fill memory with a constant byte * @s: Memory area to be filled * @c: Constant byte * @n: Number of bytes started from s to fill with c * Returns: s */ void *os_memset(void *s, int c, size_t n); /** * os_memcmp - Compare memory areas * @s1: First buffer * @s2: Second buffer * @n: Maximum numbers of octets to compare * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greater than s2. Only first n * characters will be compared. */ int os_memcmp(const void *s1, const void *s2, size_t n); /** * os_strdup - Duplicate a string * @s: Source string * Returns: Allocated buffer with the string copied into it or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). */ char *os_strdup(const char *s); /** * os_strlen - Calculate the length of a string * @s: '\0' terminated string * Returns: Number of characters in s (not counting the '\0' terminator) */ size_t os_strlen(const char *s); /** * os_strcasecmp - Compare two strings ignoring case * @s1: First string * @s2: Second string * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greatred than s2 */ int os_strcasecmp(const char *s1, const char *s2); /** * os_strncasecmp - Compare two strings ignoring case * @s1: First string * @s2: Second string * @n: Maximum numbers of characters to compare * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greater than s2. Only first n * characters will be compared. */ int os_strncasecmp(const char *s1, const char *s2, size_t n); /** * os_strchr - Locate the first occurrence of a character in string * @s: String * @c: Character to search for * Returns: Pointer to the matched character or %NULL if not found */ char *os_strchr(const char *s, int c); /** * os_strrchr - Locate the last occurrence of a character in string * @s: String * @c: Character to search for * Returns: Pointer to the matched character or %NULL if not found */ char *os_strrchr(const char *s, int c); /** * os_strcmp - Compare two strings * @s1: First string * @s2: Second string * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greatred than s2 */ int os_strcmp(const char *s1, const char *s2); /** * os_strncmp - Compare two strings * @s1: First string * @s2: Second string * @n: Maximum numbers of characters to compare * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greater than s2. Only first n * characters will be compared. */ int os_strncmp(const char *s1, const char *s2, size_t n); /** * os_strncpy - Copy a string * @dest: Destination * @src: Source * @n: Maximum number of characters to copy * Returns: dest */ char *os_strncpy(char *dest, const char *src, size_t n); /** * os_strstr - Locate a substring * @haystack: String (haystack) to search from * @needle: Needle to search from haystack * Returns: Pointer to the beginning of the substring or %NULL if not found */ char *os_strstr(const char *haystack, const char *needle); /** * os_snprintf - Print to a memory buffer * @str: Memory buffer to print into * @size: Maximum length of the str buffer * @format: printf format * Returns: Number of characters printed (not including trailing '\0'). * * If the output buffer is truncated, number of characters which would have * been written is returned. Since some C libraries return -1 in such a case, * the caller must be prepared on that value, too, to indicate truncation. * * Note: Some C library implementations of snprintf() may not guarantee null * termination in case the output is truncated. The OS wrapper function of * os_snprintf() should provide this guarantee, i.e., to null terminate the * output buffer if a C library version of the function is used and if that * function does not guarantee null termination. * * If the target system does not include snprintf(), see, e.g., * http://www.ijs.si/software/snprintf/ for an example of a portable * implementation of snprintf. */ int os_snprintf(char *str, size_t size, const char *format, ...); #else /* OS_NO_C_LIB_DEFINES */ #ifdef WPA_TRACE void *os_malloc(size_t size); void *os_realloc(void *ptr, size_t size); void os_free(void *ptr); char *os_strdup(const char *s); #else /* WPA_TRACE */ #ifndef os_malloc #define os_malloc(s) malloc((s)) #endif #ifndef os_realloc #define os_realloc(p, s) realloc((p), (s)) #endif #ifndef os_free #define os_free(p) free((p)) #endif #ifndef os_strdup #ifdef _MSC_VER #define os_strdup(s) _strdup(s) #else #define os_strdup(s) strdup(s) #endif #endif #endif /* WPA_TRACE */ #ifndef os_memcpy #define os_memcpy(d, s, n) memcpy((d), (s), (n)) #endif #ifndef os_memmove #define os_memmove(d, s, n) memmove((d), (s), (n)) #endif #ifndef os_memset #define os_memset(s, c, n) memset(s, c, n) #endif #ifndef os_memcmp #define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) #endif #ifndef os_strlen #define os_strlen(s) strlen(s) #endif #ifndef os_strcasecmp #ifdef _MSC_VER #define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) #else #define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) #endif #endif #ifndef os_strncasecmp #ifdef _MSC_VER #define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) #else #define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) #endif #endif #ifndef os_strchr #define os_strchr(s, c) strchr((s), (c)) #endif #ifndef os_strcmp #define os_strcmp(s1, s2) strcmp((s1), (s2)) #endif #ifndef os_strncmp #define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) #endif #ifndef os_strncpy #define os_strncpy(d, s, n) strncpy((d), (s), (n)) #endif #ifndef os_strrchr #define os_strrchr(s, c) strrchr((s), (c)) #endif #ifndef os_strstr #define os_strstr(h, n) strstr((h), (n)) #endif #ifndef os_snprintf #ifdef _MSC_VER #define os_snprintf _snprintf #else #define os_snprintf snprintf #endif #endif #endif /* OS_NO_C_LIB_DEFINES */ /** * os_strlcpy - Copy a string with size bound and NUL-termination * @dest: Destination * @src: Source * @siz: Size of the target buffer * Returns: Total length of the target string (length of src) (not including * NUL-termination) * * This function matches in behavior with the strlcpy(3) function in OpenBSD. */ size_t os_strlcpy(char *dest, const char *src, size_t siz); #ifdef OS_REJECT_C_LIB_FUNCTIONS #define malloc OS_DO_NOT_USE_malloc #define realloc OS_DO_NOT_USE_realloc #define free OS_DO_NOT_USE_free #define memcpy OS_DO_NOT_USE_memcpy #define memmove OS_DO_NOT_USE_memmove #define memset OS_DO_NOT_USE_memset #define memcmp OS_DO_NOT_USE_memcmp #undef strdup #define strdup OS_DO_NOT_USE_strdup #define strlen OS_DO_NOT_USE_strlen #define strcasecmp OS_DO_NOT_USE_strcasecmp #define strncasecmp OS_DO_NOT_USE_strncasecmp #undef strchr #define strchr OS_DO_NOT_USE_strchr #undef strcmp #define strcmp OS_DO_NOT_USE_strcmp #undef strncmp #define strncmp OS_DO_NOT_USE_strncmp #undef strncpy #define strncpy OS_DO_NOT_USE_strncpy #define strrchr OS_DO_NOT_USE_strrchr #define strstr OS_DO_NOT_USE_strstr #undef snprintf #define snprintf OS_DO_NOT_USE_snprintf #define strcpy OS_DO_NOT_USE_strcpy #endif /* OS_REJECT_C_LIB_FUNCTIONS */ #endif /* OS_H */ ================================================ FILE: packages/FC18/x86_64/README.FC18 ================================================ Installation steps: 1. Flash a firmware with the hostapd-capwap package on a OpenWRT compatible router. 2. Setup a FC18 box where you want to run AC. 3. On the FC18 box: - Copy the RPMS and run: yum -y erase openssl-libs.i686; yum -y install openssl-libs.i686; rpm -ivh --force *.rpm - Edit /etc/hostapd/hostapd.conf - Run /etc/init.d/capwap-ac start - Run /etc/init.d/hostapd start 4. On the OpenWRT router : - Run killall -9 hostapd - Copy /tmp/run/hostapd-phy0.conf to /etc/capwap/hostapd.conf - Edit the driver in /etc/capwap/hostapd.conf line and set it to capwap_wtp - Run cd /etc/capwap; WTP; hostapd hostapd.conf 9. Enjoy the RX_MGMT events flowing trough the radiotap tunnel. Logs: - on WTP /var/log/wtp.log.txt - on AC /var/log/ac.log.txt Notes: - Always run AC first and WTP after otherwise they might get stuck in join state. - When hostapd on AC is closed also the hostapd on WTP needs to be closed. - When AC and WTP don't talk to eachother because they are stuck in join state allways kill hostapd, AC and WTP processes. ================================================ FILE: root.pem ================================================ -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIJAKFrKBWkidxvMA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNV BAYTAlRXMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxDTALBgNVBAoMBFRPREQxFDAS BgNVBAMMC0NBUFdBUF9ST09UMSEwHwYJKoZIhvcNAQkBFhJ0b2RkY2hvdUBnbWFp bC5jb20wHhcNMTIwMjI0MTYzNDI0WhcNMzIwMjI0MTYzNDI0WjBsMQswCQYDVQQG EwJUVzEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MQ0wCwYDVQQKDARUT0REMRQwEgYD VQQDDAtDQVBXQVBfUk9PVDEhMB8GCSqGSIb3DQEJARYSdG9kZGNob3VAZ21haWwu Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtGgC6q7ss4Kbcn4H foWNBaXZOp+F/C5kQlsB5aO6k6FGZzij7nJhOpQASR0kSg8TciTPm1eMxn7pIJ7A b5raDXnIcRCrpZVEdgAhUPKVkPWRIAhJtjqz6ix2ZrJI2hXjf24kvAzfIwCJgtaP 0phaUeAUpofzW5PILwiFLrb59oNaMkUxpv6bWHYYQIh5rGf2nVKDZebf+tGEzCxB jhVVgTfstuTu1tNaQVSR6pTuEoFiOUINLSRfMZ37ajEM+tlK5juETaviT8XMXqMP MSAsjwwd3FxmJYi79iNSqmR0/izjlAD/5R/2ZD+0usEhvTR8R0aKbTPvCvU5ZSWL MJ8ZPwIDAQABo1AwTjAdBgNVHQ4EFgQUrD4UNtUPiyDVWRbnMfqPtgnNucMwHwYD VR0jBBgwFoAUrD4UNtUPiyDVWRbnMfqPtgnNucMwDAYDVR0TBAUwAwEB/zANBgkq hkiG9w0BAQUFAAOCAQEAsfmB0z1C8tYE+sRKSTOPKdsVaiwXdOxWkYK++ZyEJR9H 5zukOQTev5bOQU38JHG7iXMDpSeRwZsaQlJc+/rbn0NDaQa5A3mlQH7EcY7kbxav yQ57wHivqUjbQry8oJ5TSvAytb46oJ08zcfVvp4ZPFURTwnf6N9gFibNoBphKPKZ l/sRfr+zTPTP2kRFVY2/Jf0VQ8MT+rZFU3mRz2v5pxIrvfhfLheEgySTVBUQ34WE Mt4a54zhANOt713ZJPeFMM73A46SIJt1rYWzZZ3dyjBREXgXRoeC5myGULMJyLaK fZU/B2aHf4uOwOtL/iRuFomKPZwyAK4aMxDEUrp6YA== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,3FC7B4CF6DC46853 Lt8A8/KZnD7khLrT10brqWMYg2RQ325Xbi8HQAxcEdfkb15lcucz1eUh4fZ3Fjlf K6b63SUXaIY1rr2uVCv3cUMS2L3aZeyJI68rz28jpZ70vEY399MxXeABEGV4YDhe /x97rI3EQJ9Q2fnNwoXMd58nFIA5odx7xwv37+3UnDi04bCd0aXs+ejnTpcAVDCS ERAbjoBxmwc4uwWXcXV2CTpjUham9h1dzb3LHaRYM0uy2rz38WaixlcFbzkh/t97 /s0L+tiw7N8uwBTsAOF7DxsoB/NXtfaF0FiSnSOdSb8DfXuGH4K1uFZ6XUryyblJ ExlTwveP2uZVhyFoUBj+x5dcX0YyijunJAizr4ca5piXO4LgIjKrCss2HSO1MNLR ubLtXFGh/UtQhpBkebbaYC8XHPiFe3BeUyrp3PL+770bF7XfJeH+U3W731Jc2H1t WkvNa7UUtKjizaeDY6BRxRCwcYmqKNUwCji2E5KehNii7ErUbqc2zaMAxerzUTdC wWw6JdGuRO8jy5Q5QlrBxEaxQUzPxlibe0wFpPp0SKwNwR9CyNhryplTmguhSwbT N3/EtSxY3fDz5AWqD/KKy7iqB/l9VZN97uqlVYArdZQ3bmSp991PxWI7zCi+vPYQ OaMm7RiRU5ssjjb/xutjYp0iRsf/trbZSfyzEgHzHIk7PsQ/azTc/WhwDjPm0W4h Cxf+xhgPMLCxfDt46Gr03tw2s3ohcm1czEowY8gctpAMsx3mGROggS6mrQDPlO+9 gS3Erc8Tn533vYrIVQsYzpLV5UOsc3UHpysc7bBOUUWa4Pcxf6aGxi6EV/BBniKU Crptz/crTGe+xtCFYSR9HewHp1eqV1UtBm8nb5If7KddgHTfskGDNsJiTVBpSS1x mL8debg3dTzmYgnA7lqQ689DexD6GoqBug7SRUL7dpxfIEL+M+ylbr20kxqDo+Vq 0pka/SJbIXlnWQxzwKx+6M2e579wAB9dIRKVVm5QzB2L7H6JN2gQ4n9/b/rkaerR sLnqNdQQI5ULe3rOnPVJiQj/0IvxnQkZv5fJkRNrWGDrGUp+egzU3cyXL0gYFrXO T0wgocPyU/6qfOEGMXJUukgu8id235k+eRRwY3utwPA4gxdTaZmyKtrzjByLUYhU gEwbho07Yaifnb0xEBEO/74iCC4A18ig24vNLVF9jsweiB4UpG7rHXKNxDXEdA/d PUJbOC3XbtfD20MM3oiPm0H9ZHuOhFmZ981R3Qw3CzGIIZlWC3ntycDxHKM9hxTk Zafj7PU121263H3buZz8i3BJNf9qBi697PV6UcluVVgqVJsN4gJspmTJgbblwPZW 2QOg+A2bPNhRBOWXGNPoRnBed36DBS/weR2hmDbZkjpbbYqL1Q964eU3he1Xjrzi xVcz6gyjQqatLChakHSliIBOu+PGCjpP5x0ECqh4jyz3KT3CUGY+8iSIGsAt32Cb eX/1GbaI+GdONVI427N5wY14FRfmvXT04+6FqzOkZGdbCHNi9eqUx+gueTAIm8YX PFQv9AIhjM5U4mLmsVvQrf3FVRP/Pq4IkpuSmxv3iJVMPu6vSAjI/Q== -----END RSA PRIVATE KEY----- ================================================ FILE: server.pem ================================================ -----BEGIN CERTIFICATE----- MIIDaDCCAlCgAwIBAgIJAJI6srPP97u0MA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNV BAYTAlRXMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxDTALBgNVBAoMBFRPREQxFDAS BgNVBAMMC0NBUFdBUF9ST09UMSEwHwYJKoZIhvcNAQkBFhJ0b2RkY2hvdUBnbWFp bC5jb20wHhcNMTIwMjI0MTYzNTUzWhcNMjIwMjIxMTYzNTUzWjBfMQswCQYDVQQG EwJUVzEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRYwFAYDVQQKDA1DQVBXQVBfU0VS VkVSMSEwHwYJKoZIhvcNAQkBFhJ0b2RkY2hvdUBnbWFpbC5jb20wggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3AadIRJYKHVOhsk4J/6gSTJSxljSa5MNe 2pkwZPT0Vi5FUuw7ogTqXfiwutiupxnl1CEX3sDk6j7RlkwY0mnsBwruErlRmeH1 Zkr7kgbfjKcaKhVvJAbfjCOSiYcgi+pGcu1GGTDm9Jkmwy/yKxWW2CBRUGQOrpVa rBQobQ5WYmZm66/mBRHwJzLExLWDzZPhNHcSk1H2VxqaTmHzFeSmN4o2HtupCuOE dvMzgp+RV87mMBQnQv1FjIoeb3Mqir1wgkcaGWrut+t6uatwRU/vu9tJYuPhpC4N D/VmjYnPkR7GFNyncp1ELp2blQls327dTAvjt0gRZCKLxKUGOAh/AgMBAAGjGjAY MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBBQUAA4IBAQAdmZA+ 7E0z086Q7ol99z1UQjQ+O5jSdCdwzmekvAru7vsM5Sbbm5ODMyabauKI0nnRRGrX ISS72BEk5T1I0Nr14YzT8uINnxh/sZWJq1a/hX2/O/YVwfJdSLhCU6oMz1kGaOGG pNoT7SsVxLUBd61FhTIZp7k8QB3tN/gG4pATv0EnzhQCYASWvRu/Loydeu5XE7WV HP6eO1O48l/7CFNW06ilewAURm7Hnnrt7+6HB9bG7Nn9TWoludc54JibrnYw1Q0I rLEv+LRBiZtoKqrscJ6/VoD0uBnC2K69yOdbcgcgiykbD6S777c2iwIvtklysIRX cHPrByM9nQ/jGHK9 -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAtwGnSESWCh1TobJOCf+oEkyUsZY0muTDXtqZMGT09FYuRVLs O6IE6l34sLrYrqcZ5dQhF97A5Oo+0ZZMGNJp7AcK7hK5UZnh9WZK+5IG34ynGioV byQG34wjkomHIIvqRnLtRhkw5vSZJsMv8isVltggUVBkDq6VWqwUKG0OVmJmZuuv 5gUR8CcyxMS1g82T4TR3EpNR9lcamk5h8xXkpjeKNh7bqQrjhHbzM4KfkVfO5jAU J0L9RYyKHm9zKoq9cIJHGhlq7rfrermrcEVP77vbSWLj4aQuDQ/1Zo2Jz5EexhTc p3KdRC6dm5UJbN9u3UwL47dIEWQii8SlBjgIfwIDAQABAoIBAAZRuUwGikPJJXUk 6grwWAZhvJSxQhnDInfpBnckVU0GmMxuA5g/jPnmysqXeRn2zS8hdw8S8wg0inzE OtZ0lZG/4IG+BcYqkSHfKWGsdi5L9g0yPNE8pjwb47KQqyjVi/5ow4azIfwnoA41 mTc8g59U0TDdnMbhAmlCHeQTd/ZFmpZIygD176nahmYENutV1Y+nm9r9m9FpffCs j3Kj7RmjgFx85fQwzLpLKirauVA2RDXCRe0u8xFIH49UmcqkPzFZNeuc/IStVBtp Hzl9fpLLCIjEcrUlHcfsj+LXFoQ5t/BG59hC3Y5Rk2/awCo8HC2oz4lFaNNt4pGv zaDbTiECgYEA53QqVLV7FNBZd+YCnV2SWr4YsoTfounzs4Ro3koP1PRKt7RTerBV 2H1v8PsxbHibyGMlr6Lu8qpyUoSrC3w5eswbhvHsqF7lZiPfA/+yxDdcb0/JN8cp rTqLwR1Yh5XYuMsHTVMmPS5vcUxhBgmeALAzxB6sNAs4puS1I9IxrRECgYEAymor /+08p4NU4oP2l1oR8dBIR++da4LLUu4/GEhfkmcU+zugy0xVdl8pzHvdV2qvFOAz RBybgez7lBW7rj40/34Bs0fcM2J6FQlWkPjORKVMmyuaaREb8JWd56fIJJRrV51K aCthUvEUYhuY6vRc33CEoZS+0lE0MZrNEK7inI8CgYEAvTjoXqacAHExo+dEnfjg 7RTaxiABYYRY+5u1zH3KIbSy3Sss0HIXTM2IVgBW8LJN0e7U4ZmYNoYIvtO9rr8Z kv4JRzLD4wbqDq4m5nMGaIpGJK6a9+H4faoOlYvzU627J6C80Ie5DG3JKFxkOfZk 2XU0bRMSf93oq/Dw8l8mw7ECgYEAogKe2wYgYRduDqt+6J9v83M5F1LDVfTnFqaY m6/5xu14zqloRq//S3JZu1B81eYO4o+cmOyozzJGHr3SbWFe/Av4Am4G4p30hvfl cL2kIy+HBD+/JE9MZKDsNSmGuTiOPh8oGf52tHM/VFMwbwZNe43MqqOqpB3Yv8de UPcZbCMCgYB0Im6UAz6v0j1lPM7P3h8LmHbPiGAUGN5Wx9KmClvmiatxr4EFvX93 lKry92i809q+CNe3nMWwijoICk1h0w86XXfHo/3GS3GehIPeD9i3lvDZm/iNsG59 APP6QvNascmG0mqx/B4xaIqbKz2RUdk+nsob2jhJHbe1g6luYaUFdw== -----END RSA PRIVATE KEY----- ================================================ FILE: settings.ac.txt ================================================ # Settings File for AC. Lines beginning with # and blank lines will be ignored # # # 2 3 1 # # 3 4 1 # # 3 10 2 # # 4 10 7 5543 /tmp/ac_ipc_hostapd ================================================ FILE: settings.wtp.txt ================================================ # Settings File for WTP. Lines beginning with # and blank lines will be ignored # # mon.wlan0 vmnet1 wlan0 vmnet1 eth0 12345678 12345678 6333 /tmp/wtp_ipc_hostapd # mon.wlan0 # eth0 # wlan0 # lo # eth0 # 12345678 # 12345678 ================================================ FILE: smac_code.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Sotiraq Sima (Sotiraq.Sima@gmail.com) * * * *******************************************************************************************/ #include #ifndef AC typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; #endif enum { ERROR = 0, CLOSE = 1, PING = 2, // [2]ping PONG = 3, // [3]pong /* only WTP */ START_WLAN = 4, START_WLAN_R = 5, STOP_WLAN = 6, STOP_WLAN_R = 7, SET_FREQ = 8, // FREQ sec_channel_offset ht_enabled channel MODE ex. "[8]2462 0 0 11 0" SET_FREQ_R = 9, // 0 or 1 ex. "[9]0" GET_FREQ = 10, // ex. "[10]" GET_FREQ_R = 11, // ex. "[11]2462 0 0 11 0" SET_FRAG = 12, // Typically the range used for fragmentation threshold is 256-2346 (-1 == off) ex. "[12]2000" SET_FRAG_R = 13, // ex. "[13]0" GET_FRAG = 14, // ex. "[14]" (-1 == off) GET_FRAG_R = 15, // ex. "[15]2000" SET_BITRATE = 16, SET_BITRATE_R = 17, GET_BITRATE = 18, GET_BITRATE_R = 19, SET_RTS = 20, // 0-2347 (-1 == off) ex. "[20]100" (-1 == off) SET_RTS_R = 21, // ex. "[21]0" GET_RTS = 22, // ex. "]22]" (-1 == off) GET_RTS_R = 23, // ex. "[23]100" SET_TXPOWER = 24, SET_TXPOWER_R = 25, GET_TXPOWER = 26, GET_TXPOWER_R = 27, /* * VO - 0 CWMIN:3 CWMAX:7 AIFS:2 * VI - 1 CWMIN:7 CWMAX:15 AIFS:2 * BE - 2 CWMIN:15 CWMAX:1023 AIFS:3 * BK - 3 CWMIN:15 CWMAX:1023 AIFS:7 */ SET_TXQ = 28, SET_TXQ_R = 29, GET_TXQ = 30, GET_TXQ_R = 31, SET_ADDR = 32, SET_ADDR_R = 33, DEL_ADDR = 34, DEL_ADDR_R = 35, ADD_WLAN = 36, ADD_WLAN_R = 37, DEL_WLAN = 38, DEL_WLAN_R = 39, WTPRINFO = 40, WTPRINFO_R = 41, GET_RATES = 42, GET_RATES_R = 43, GET_MDC = 44, GET_MDC_R = 45, SET_WTPRINFO = 46, SET_WTPRINFO_R = 47, SET_RATES = 48, SET_RATES_R = 49, SET_MDC = 50, SET_MDC_R = 51, GOLIVE = 52, GOLIVE_R = 53, WANT_GOLIVE = 54, HAVE_TO_WAIT = 55, GET_MAC = 56, GET_MAC_R = 57, SET_MAC = 58, SET_MAC_R = 59, //-------- DATE_TO_WTP = 100, DATE_TO_AC = 101, CONNECT = 102, CONNECT_R = 103, GOWAITWLAN = 104, GOWAITWLAN_R = 105, SEND_WLAN_TO_WTP = 106 }; ================================================ FILE: tap.c ================================================ /* * Documentation/networking/tuntap.txt * */ #include "CWAC.h" #include "CWVendorPayloads.h" #include "CWFreqPayloads.h" #include "WUM.h" #include #ifdef DMALLOC #include "../dmalloc-5.5.0/dmalloc.h" #endif int tun_alloc(char *dev, int flags) { struct ifreq ifr; int fd, err; char *clonedev = "/dev/net/tun"; /* Arguments taken by the function: * * char *dev: the name of an interface (or '\0'). MUST have enough * space to hold the interface name if '\0' is passed * int flags: interface flags (eg, IFF_TUN etc.) */ /* open the clone device */ if ((fd = open(clonedev, O_RDWR)) < 0) { return fd; } /* preparation of the struct ifr, of type "struct ifreq" */ memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ if (*dev) { /* if a device name was specified, put it in the structure; otherwise, * the kernel will try to allocate the "next" device of the * specified type */ strncpy(ifr.ifr_name, dev, IFNAMSIZ); } /* try to create the device */ if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) { CWLog("Err to creater tap device"); close(fd); return err; } /* if the operation was successful, write back the name of the * interface to the variable "dev", so the caller can know * it. Note that the caller MUST reserve space in *dev (see calling * code below) */ strcpy(dev, ifr.ifr_name); /* this is the special file descriptor that the caller will use to talk * with the virtual interface */ return fd; } int init_AC_tap_interface(int WTPIndex) { sprintf(gWTPs[WTPIndex].tap_name, "wtp%d", WTPIndex); gWTPs[WTPIndex].tap_fd = tun_alloc(gWTPs[WTPIndex].tap_name, IFF_TAP | IFF_NO_PI); CWDebugLog("gWTPs[%d].tap_name %s,tap_fd %d", WTPIndex, gWTPs[WTPIndex].tap_name, gWTPs[WTPIndex].tap_fd); return 0; } ================================================ FILE: tap.h ================================================ /******************************************************************************************* * Copyright (c) 2006-7 Laboratorio di Sistemi di Elaborazione e Bioingegneria Informatica * * Universita' Campus BioMedico - Italy * * * * 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., 59 Temple Place - Suite 330, Boston, * * MA 02111-1307, USA. * * * * --------------------------------------------------------------------------------------- * * Project: Capwap * * * * Author : Ludovico Rossi (ludo@bluepixysw.com) * * Del Moro Andrea (andrea_delmoro@libero.it) * * Giovannini Federica (giovannini.federica@gmail.com) * * Massimo Vellucci (m.vellucci@unicampus.it) * * Mauro Bisson (mauro.bis@gmail.com) * *******************************************************************************************/ #ifndef __AC_TAP_H__ #define __AC_TAP_H__ int init_AC_tap_interface(int WTPIndex); #endif ================================================ FILE: timerlib.c ================================================ /* * Copyright (C) 2008 * * 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 * * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * * Author(s): Mauro Bisson */ #include /* printf */ #include #include #include #include /* ETIMEDOUT */ #include #include /* memcpy */ #include "timerlib.h" /* time to wait the init of ticker thread in timer_init() function */ #define INIT_WAIT_TIME 5 /* for conversion purpose */ #define NANO_PER_MICRO 1000 #define MICRO_PER_SEC 1000000 /* max number of microsecond in a timeval struct */ #define MAX_USEC 999999 /* microseconds in a millisecond */ #define ALMOST_NOW 1000 #define TIMER_KIND ITIMER_REAL #define SIG_TO_WAIT SIGALRM /* * evals true if struct timeval t1 defines a time strictly before t2; * false otherwise. */ #define TV_LESS_THAN(t1,t2) (((t1).tv_sec < (t2).tv_sec) ||\ (((t1).tv_sec == (t2).tv_sec) &&\ ((t1).tv_usec < (t2).tv_usec))) /* * Assign struct timeval tgt the time interval between the absolute * times t1 and t2. * IT IS ASSUMED THAT t1 > t2, use TV_LESS_THAN macro to test it. */ #define TV_MINUS(t1,t2,tgt) if ((t1).tv_usec >= (t2).tv_usec) {\ (tgt).tv_sec = (t1).tv_sec -\ (t2).tv_sec;\ (tgt).tv_usec = (t1).tv_usec -\ (t2).tv_usec;\ }\ else {\ (tgt).tv_sec = (t1).tv_sec -\ (t2).tv_sec -1;\ (tgt).tv_usec = (t1).tv_usec +\ (MAX_USEC - (t2).tv_usec);\ } typedef struct timer tl_timer_t; static void timer_free(tl_timer_t * /*t */ ); static void timer_dequeue(tl_timer_t * /*t */ ); static void timer_start(struct timeval * /*abs_to */ ); static void *cronometer(void * /*arg */ ); struct timer { struct timeval timeout; void (*handler) (void *); void *handler_arg; int id; int in_use; int cancelled; tl_timer_t *next; tl_timer_t *prev; }; static struct { tl_timer_t *first; tl_timer_t *last; pthread_mutex_t mutex; pthread_cond_t cond; pthread_t ticker; int cur_id; } timerq; static void timer_free(tl_timer_t * t) { if (t == NULL) return; free(t); return; } static void timer_dequeue(tl_timer_t * t) { if (t == NULL) return; if (t->prev == NULL) /* t is the first of the queue */ timerq.first = t->next; else t->prev->next = t->next; if (t->next == NULL) /* t is the last of the queue */ timerq.last = t->prev; else t->next->prev = t->prev; timer_free(t); return; } /* * Set a timer with setititmer syscall to expire on abs_to time. * The parameter abs_to is an absolute time as those returned with * gettimeofday (since epoch). * If abs_to refers to a time in the past the timer will be set to * expire in 1 millisecond. * This function has to be called in a critical section. */ static void timer_start(struct timeval *abs_to) { struct itimerval relative = { {0, 0}, {0, 0} }; struct timeval abs_now; int rv; if (abs_to == NULL) return; /* absolute to relative time */ gettimeofday(&abs_now, NULL); if (TV_LESS_THAN(abs_now, *abs_to)) { /* ok, timeout is in the future */ TV_MINUS(*abs_to, abs_now, relative.it_value); } else { /* * ouch, timeout is in the past! Let's set it * to a very near future value. */ relative.it_value.tv_sec = 0; relative.it_value.tv_usec = ALMOST_NOW; } rv = setitimer(TIMER_KIND, &relative, NULL); if (rv == -1) { /* This should never happen but I dont trust myself */ perror("setitimer"); exit(1); } return; } static void *cronometer(void *arg) { void (*hdl) (void *); void *hdl_arg = arg; /* keep gcc silent */ sigset_t mask; int sig; sigemptyset(&mask); sigaddset(&mask, SIG_TO_WAIT); /* * Set this thread to be cancelled only in the cancellation * points (pthread_cond_wait() and sigwait()). */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); /* signal creator thread of succesful init */ pthread_mutex_lock(&timerq.mutex); pthread_cond_signal(&timerq.cond); /* printf("\tTicker thread: inizializzaione compleata\n"); */ pthread_mutex_unlock(&timerq.mutex); while (1) { pthread_mutex_lock(&timerq.mutex); while (timerq.first == NULL) pthread_cond_wait(&timerq.cond, &timerq.mutex); timer_start(&(timerq.first->timeout)); timerq.first->in_use = 1; pthread_mutex_unlock(&timerq.mutex); /* wait for a pending SIGALRM */ sigwait(&mask, &sig); /* * Poiche' un timer non puo' mai scadere prima del tempo * (semmai dopo), all'uscita della sigwait() timerq.first * punta sempre al tl_timer_t per il quale e' stato ricevuto * il segnale. Nel caso in cui venga aggiunto un timer con * scadenza precedente al tempo di attesa rimasto per il * corrente la funzione timer_add() provvede a risettare il * timer al valore del nuovo, piu' corto, e ad inserire * quest'ultimo come primo della coda. * Se invece il timer corrente viene eliminato con timer_rem() * la struttura non verra' eliminata ma verra' solo settato il * suo flag "cancelled" ad 1. */ pthread_mutex_lock(&timerq.mutex); if (timerq.first->cancelled == 1) { timer_dequeue(timerq.first); pthread_mutex_unlock(&timerq.mutex); continue; } /* * we cannot be cancelled while freeing memory and executing * an handler. */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); hdl = timerq.first->handler; hdl_arg = timerq.first->handler_arg; timer_dequeue(timerq.first); /* * unlock the mutex before executing an handler to avoid * possible deadlock inside it. */ pthread_mutex_unlock(&timerq.mutex); hdl(hdl_arg); /* reset cancel state (cancel type has not been changed) */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); } return NULL; } /* * Initialize the timerq struct, spwan the ticker thread, * wait its initialization and return. */ int timer_init() { int rv; struct timespec ts; struct timeval tv; rv = pthread_mutex_init(&timerq.mutex, NULL); if (rv != 0) return 0; rv = pthread_cond_init(&timerq.cond, NULL); if (rv != 0) { pthread_mutex_destroy(&timerq.mutex); return 0; } timerq.first = timerq.last = NULL; timerq.cur_id = 0; pthread_mutex_lock(&timerq.mutex); rv = pthread_create(&timerq.ticker, NULL, cronometer, NULL); if (rv != 0) { pthread_mutex_unlock(&timerq.mutex); pthread_mutex_destroy(&timerq.mutex); pthread_cond_destroy(&timerq.cond); return 0; } gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec + INIT_WAIT_TIME; ts.tv_nsec = tv.tv_usec * NANO_PER_MICRO; rv = pthread_cond_timedwait(&timerq.cond, &timerq.mutex, &ts); if (rv != 0) { if (rv == ETIMEDOUT) { pthread_cancel(timerq.ticker); pthread_join(timerq.ticker, NULL); } pthread_mutex_destroy(&timerq.mutex); pthread_cond_destroy(&timerq.cond); return 0; } /* * BUG.TRL02 * Here we have to detach the thread in oder to avoid memory leakage. * * 16/10/2009 - Donato Capitella */ pthread_detach(timerq.ticker); pthread_mutex_unlock(&timerq.mutex); return 1; } void timer_destroy() { tl_timer_t *t; pthread_cancel(timerq.ticker); pthread_join(timerq.ticker, NULL); t = timerq.last; while (t != NULL) { timerq.last = t->prev; timer_free(t); t = timerq.last; } pthread_mutex_destroy(&timerq.mutex); pthread_cond_destroy(&timerq.cond); return; } int timer_add(long sec, long usec, void (*hndlr) (void *), void *hndlr_arg) { struct timeval new; tl_timer_t *tmp = NULL; tl_timer_t *app = NULL; int id = 0; if (hndlr == NULL) return -1; /* ensure timeout is in the future */ if ((sec < 0) || (usec < 0) || ((sec == 0) && (usec == 0))) return -1; pthread_mutex_lock(&timerq.mutex); app = (tl_timer_t *) malloc(sizeof(tl_timer_t)); if (app == NULL) { pthread_mutex_unlock(&timerq.mutex); return -1; } /* relative to absolute time for timer */ gettimeofday(&new, NULL); /* add 10^6 microsecond units to seconds */ new.tv_sec += sec + (new.tv_usec + usec) / MICRO_PER_SEC; /* keep microseconds inside allowed range */ new.tv_usec = (new.tv_usec + usec) % MICRO_PER_SEC; memcpy(&app->timeout, &new, sizeof(struct timeval)); app->handler = hndlr; app->handler_arg = hndlr_arg; id = timerq.cur_id++; app->id = id; app->in_use = 0; app->cancelled = 0; if (timerq.first == NULL) { /* timer queue empty */ timerq.first = app; timerq.last = app; app->prev = NULL; app->next = NULL; pthread_cond_signal(&timerq.cond); pthread_mutex_unlock(&timerq.mutex); return id; } /* there is at least a timer in the queue */ tmp = timerq.first; /* find the first timer that expires before app */ while (tmp != NULL) { if (TV_LESS_THAN(app->timeout, tmp->timeout)) break; tmp = tmp->next; } if (tmp == NULL) { /* app is the longest timer */ app->prev = timerq.last; app->next = NULL; timerq.last->next = app; timerq.last = app; pthread_mutex_unlock(&timerq.mutex); return id; } if (tmp->prev == NULL) { /* app is the shoprtest timer */ app->prev = NULL; app->next = tmp; tmp->prev = app; timerq.first = app; /* start app timer */ app->in_use = 1; tmp->in_use = 0; timer_start(&(timerq.first->timeout)); } else { app->prev = tmp->prev; app->next = tmp; tmp->prev->next = app; tmp->prev = app; } pthread_mutex_unlock(&timerq.mutex); return id; } void timer_rem(int id, void (*free_arg) (void *)) { tl_timer_t *t; pthread_mutex_lock(&timerq.mutex); t = timerq.first; /* look for timer id */ while (t != NULL) { if (t->id == id) break; t = t->next; } if (t == NULL) { /* timer id is not in queue (maybe empty) */ pthread_mutex_unlock(&timerq.mutex); return; } if (t->in_use == 1) { /* * timer id has been already activated, so just set * its "cancelled" flag (ticker thread will remove it) */ /* LE-03-02-2010.01 * We have to set handler_arg to NULL, otherwise we * risk to free it more than one time. */ if (free_arg) { free_arg(t->handler_arg); t->handler_arg = NULL; } t->cancelled = 1; pthread_mutex_unlock(&timerq.mutex); return; } /* timer id is in the queue and has not been activated */ if (free_arg) free_arg(t->handler_arg); timer_dequeue(t); pthread_mutex_unlock(&timerq.mutex); return; } void timer_print() { tl_timer_t *t; int i; pthread_mutex_lock(&timerq.mutex); for (t = timerq.first, i = 0; t != NULL; t = t->next, i++) { printf("Timer %d: id=<%d>, expire=<%u,%u>, in_use=<%d>, cancelled=<%d>\n", i, t->id, (unsigned int)t->timeout.tv_sec, (unsigned int)t->timeout.tv_usec, t->in_use, t->cancelled); } pthread_mutex_unlock(&timerq.mutex); return; } ================================================ FILE: timerlib.h ================================================ /* * Copyright (C) 2008 * * 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 * * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * * Author(s): Mauro Bisson */ /* * This C module implements a simple timer library. */ #ifndef TIMERLIB_H #define TIMERLIB_H /* * Initializes the timer library. It is important that the calling thread and * any other thread in the process block the signal SIGALRM. * * Return: 1 in case of success; 0 otherwise. */ int timer_init(); /* * Tears down any data allocated for the library. */ void timer_destroy(); /* * Adds a timer to expire "sec" seconds + "usec" milliseconds after the * invocation. When the timer will expire, function "hndlr" will be executed * with arg "hndlr_arg". The id of the timer (>=0) is returned. * * Return: id>=0 in case of success; -1 in case of error. * * Remarks: sec and usec must define a future time relative to "now". If * one is negative or both equal zero the funtion will return -1. The * library don't manipulate in any way the address pointed by "hndlr_arg", * it is responsibility of the calling thread to free any memory, if * allocated (a good place is at the end of "hndlr" function or when calling * "timer_rem()" ;). * There is no costraint about relative time definition, you can set a two * second timer as (sec,usec)=(2,0) or (sec,usec)=(0,2000000). * Since this library implementation do not rely on "sigaction()" syscall, * inside "hndlr" it is perfectly legal to call any not signal safe and * pthread_* function. The only limitation is that timer_destroy() MUST * NOT be called inside hndlr. * Note that this fuction can be called inside "hndlr" to create * "chain timers". */ int timer_add(long /*sec */ , long /*usec */ , void (* /*hndlr */ )(void *), void * /*hndlr_arg */ ); /* * Remove from the queue the timer of identifier "id", if it retured * from a previous succesful call to timer_add(). The function * "free_arg" is called with the handler argument specified in "timer_add" * call. It should be used to free the memory when the timer is destroyed * before expiring. * * Remarks: if "id" is a value not returned by timer_add() nothing happens. */ void timer_rem(int /*id */ , void (* /*free_arg */ )(void *)); /* * Prints the content of the timer queue (do not use, it's for debug purpose). */ void timer_print(); #endif ================================================ FILE: wireless_copy.h ================================================ /* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 18. * I have just removed kernel related headers and added some typedefs etc. to * make this easier to include into user space programs. * Jouni Malinen, 2005-03-12. * * $Id: wireless_copy.h 1426 2006-02-01 20:07:11Z mrenzmann $ */ /* * This file define a set of standard wireless extensions * * Version : 19 18.3.05 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved. */ #ifndef _LINUX_WIRELESS_H #define _LINUX_WIRELESS_H /************************** DOCUMENTATION **************************/ /* * Initial APIs (1996 -> onward) : * ----------------------------- * Basically, the wireless extensions are for now a set of standard ioctl * call + /proc/net/wireless * * The entry /proc/net/wireless give statistics and information on the * driver. * This is better than having each driver having its entry because * its centralised and we may remove the driver module safely. * * Ioctl are used to configure the driver and issue commands. This is * better than command line options of insmod because we may want to * change dynamically (while the driver is running) some parameters. * * The ioctl mechanimsm are copied from standard devices ioctl. * We have the list of command plus a structure descibing the * data exchanged... * Note that to add these ioctl, I was obliged to modify : * # net/core/dev.c (two place + add include) * # net/ipv4/af_inet.c (one place + add include) * * /proc/net/wireless is a copy of /proc/net/dev. * We have a structure for data passed from the driver to /proc/net/wireless * Too add this, I've modified : * # net/core/dev.c (two other places) * # include/linux/netdevice.h (one place) * # include/linux/proc_fs.h (one place) * * New driver API (2002 -> onward) : * ------------------------------- * This file is only concerned with the user space API and common definitions. * The new driver API is defined and documented in : * # include/net/iw_handler.h * * Note as well that /proc/net/wireless implementation has now moved in : * # net/core/wireless.c * * Wireless Events (2002 -> onward) : * -------------------------------- * Events are defined at the end of this file, and implemented in : * # net/core/wireless.c * * Other comments : * -------------- * Do not add here things that are redundant with other mechanisms * (drivers init, ifconfig, /proc/net/dev, ...) and with are not * wireless specific. * * These wireless extensions are not magic : each driver has to provide * support for them... * * IMPORTANT NOTE : As everything in the kernel, this is very much a * work in progress. Contact me if you have ideas of improvements... */ /***************************** INCLUDES *****************************/ /* jkm - replaced linux headers with C library headers, added typedefs */ #if 0 /* To minimise problems in user space, I might remove those headers * at some point. Jean II */ #include /* for "caddr_t" et al */ #include /* for "struct sockaddr" et al */ #include /* for IFNAMSIZ and co... */ #else #include #include typedef __uint32_t __u32; typedef __int32_t __s32; typedef __uint16_t __u16; typedef __int16_t __s16; typedef __uint8_t __u8; #ifndef __user #define __user #endif /* __user */ #endif /***************************** VERSION *****************************/ /* * This constant is used to know the availability of the wireless * extensions and to know which version of wireless extensions it is * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ #define WIRELESS_EXT 19 /* * Changes : * * V2 to V3 * -------- * Alan Cox start some incompatibles changes. I've integrated a bit more. * - Encryption renamed to Encode to avoid US regulation problems * - Frequency changed from float to struct to avoid problems on old 386 * * V3 to V4 * -------- * - Add sensitivity * * V4 to V5 * -------- * - Missing encoding definitions in range * - Access points stuff * * V5 to V6 * -------- * - 802.11 support (ESSID ioctls) * * V6 to V7 * -------- * - define IW_ESSID_MAX_SIZE and IW_MAX_AP * * V7 to V8 * -------- * - Changed my e-mail address * - More 802.11 support (nickname, rate, rts, frag) * - List index in frequencies * * V8 to V9 * -------- * - Support for 'mode of operation' (ad-hoc, managed...) * - Support for unicast and multicast power saving * - Change encoding to support larger tokens (>64 bits) * - Updated iw_params (disable, flags) and use it for NWID * - Extracted iw_point from iwreq for clarity * * V9 to V10 * --------- * - Add PM capability to range structure * - Add PM modifier : MAX/MIN/RELATIVE * - Add encoding option : IW_ENCODE_NOKEY * - Add TxPower ioctls (work like TxRate) * * V10 to V11 * ---------- * - Add WE version in range (help backward/forward compatibility) * - Add retry ioctls (work like PM) * * V11 to V12 * ---------- * - Add SIOCSIWSTATS to get /proc/net/wireless programatically * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space * - Add new statistics (frag, retry, beacon) * - Add average quality (for user space calibration) * * V12 to V13 * ---------- * - Document creation of new driver API. * - Extract union iwreq_data from struct iwreq (for new driver API). * - Rename SIOCSIWNAME as SIOCSIWCOMMIT * * V13 to V14 * ---------- * - Wireless Events support : define struct iw_event * - Define additional specific event numbers * - Add "addr" and "param" fields in union iwreq_data * - AP scanning stuff (SIOCSIWSCAN and friends) * * V14 to V15 * ---------- * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg * - Make struct iw_freq signed (both m & e), add explicit padding * - Add IWEVCUSTOM for driver specific event/scanning token * - Add IW_MAX_GET_SPY for driver returning a lot of addresses * - Add IW_TXPOW_RANGE for range of Tx Powers * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points * - Add IW_MODE_MONITOR for passive monitor * * V15 to V16 * ---------- * - Increase the number of bitrates in iw_range to 32 (for 802.11g) * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) * - Reshuffle struct iw_range for increases, add filler * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index * * V16 to V17 * ---------- * - Add flags to frequency -> auto/fixed * - Document (struct iw_quality *)->updated, add new flags (INVALID) * - Wireless Event capability in struct iw_range * - Add support for relative TxPower (yick !) * * V17 to V18 (From Jouni Malinen ) * ---------- * - Add support for WPA/WPA2 * - Add extended encoding configuration (SIOCSIWENCODEEXT and * SIOCGIWENCODEEXT) * - Add SIOCSIWGENIE/SIOCGIWGENIE * - Add SIOCSIWMLME * - Add SIOCSIWPMKSA * - Add struct iw_range bit field for supported encoding capabilities * - Add optional scan request parameters for SIOCSIWSCAN * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA * related parameters (extensible up to 4096 parameter values) * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND * * V18 to V19 * ---------- * - Remove (struct iw_point *)->pointer from events and streams * - Remove header includes to help user space * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros */ /**************************** CONSTANTS ****************************/ /* -------------------------- IOCTL LIST -------------------------- */ /* Wireless Identification */ #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ /* SIOCGIWNAME is used to verify the presence of Wireless Extensions. * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... * Don't put the name of your driver there, it's useless. */ /* Basic operations */ #define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ #define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ #define SIOCSIWMODE 0x8B06 /* set operation mode */ #define SIOCGIWMODE 0x8B07 /* get operation mode */ #define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ #define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ /* Informative stuff */ #define SIOCSIWRANGE 0x8B0A /* Unused */ #define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ #define SIOCSIWPRIV 0x8B0C /* Unused */ #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ #define SIOCSIWSTATS 0x8B0E /* Unused */ #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ /* SIOCGIWSTATS is strictly used between user space and the kernel, and * is never passed to the driver (i.e. the driver will never see it). */ /* Spy support (statistics per MAC address - used for Mobile IP support) */ #define SIOCSIWSPY 0x8B10 /* set spy addresses */ #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ #define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ #define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ /* Access Point manipulation */ #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ #define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ #define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ #define SIOCGIWSCAN 0x8B19 /* get scanning results */ /* 802.11 specific support */ #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ #define SIOCGIWESSID 0x8B1B /* get ESSID */ #define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit * within the 'iwreq' structure, so we need to use the 'data' member to * point to a string in user space, like it is done for RANGE... */ /* Other parameters useful in 802.11 and some other devices */ #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ #define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ #define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ #define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ #define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ #define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ #define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ #define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ #define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ #define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ /* Encoding stuff (scrambling, hardware security, WEP...) */ #define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ #define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ /* Power saving stuff (power management, unicast and multicast) */ #define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ #define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ /* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). * This ioctl uses struct iw_point and data buffer that includes IE id and len * fields. More than one IE may be included in the request. Setting the generic * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers * are required to report the used IE as a wireless event, e.g., when * associating with an AP. */ #define SIOCSIWGENIE 0x8B30 /* set generic IE */ #define SIOCGIWGENIE 0x8B31 /* get generic IE */ /* WPA : IEEE 802.11 MLME requests */ #define SIOCSIWMLME 0x8B16 /* request MLME operation; uses * struct iw_mlme */ /* WPA : Authentication mode parameters */ #define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ #define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ /* WPA : Extended version of encoding configuration */ #define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ #define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ /* WPA2 : PMKSA cache management */ #define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ /* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ /* These 32 ioctl are wireless device private, for 16 commands. * Each driver is free to use them for whatever purpose it chooses, * however the driver *must* export the description of those ioctls * with SIOCGIWPRIV and *must* use arguments as defined below. * If you don't follow those rules, DaveM is going to hate you (reason : * it make mixed 32/64bit operation impossible). */ #define SIOCIWFIRSTPRIV 0x8BE0 #define SIOCIWLASTPRIV 0x8BFF /* Previously, we were using SIOCDEVPRIVATE, but we now have our * separate range because of collisions with other tools such as * 'mii-tool'. * We now have 32 commands, so a bit more space ;-). * Also, all 'odd' commands are only usable by root and don't return the * content of ifr/iwr to user (but you are not obliged to use the set/get * convention, just use every other two command). More details in iwpriv.c. * And I repeat : you are not forced to use them with iwpriv, but you * must be compliant with it. */ /* ------------------------- IOCTL STUFF ------------------------- */ /* The first and the last (range) */ #define SIOCIWFIRST 0x8B00 #define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) /* Even : get (world access), odd : set (root access) */ #define IW_IS_SET(cmd) (!((cmd) & 0x1)) #define IW_IS_GET(cmd) ((cmd) & 0x1) /* ----------------------- WIRELESS EVENTS ----------------------- */ /* Those are *NOT* ioctls, do not issue request on them !!! */ /* Most events use the same identifier as ioctl requests */ #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ #define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ #define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ #define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ #define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ #define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) * (scan results); This includes id and * length fields. One IWEVGENIE may * contain more than one IE. Scan * results may contain one or more * IWEVGENIE events. */ #define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure * (struct iw_michaelmicfailure) */ #define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. * The data includes id and length * fields and may contain more than one * IE. This event is required in * Managed mode if the driver * generates its own WPA/RSN IE. This * should be sent just before * IWEVREGISTERED event for the * association. */ #define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association * Response. The data includes id and * length fields and may contain more * than one IE. This may be sent * between IWEVASSOCREQIE and * IWEVREGISTERED events for the * association. */ #define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN * pre-authentication * (struct iw_pmkid_cand) */ #define IWEVFIRST 0x8C00 #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) /* ------------------------- PRIVATE INFO ------------------------- */ /* * The following is used with SIOCGIWPRIV. It allow a driver to define * the interface (name, type of data) for its private ioctl. * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV */ #define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ #define IW_PRIV_TYPE_NONE 0x0000 #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ #define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ #define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ #define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ /* * Note : if the number of args is fixed and the size < 16 octets, * instead of passing a pointer we will put args in the iwreq struct... */ /* ----------------------- OTHER CONSTANTS ----------------------- */ /* Maximum frequencies in the range struct */ #define IW_MAX_FREQUENCIES 32 /* Note : if you have something like 80 frequencies, * don't increase this constant and don't fill the frequency list. * The user will be able to set by channel anyway... */ /* Maximum bit rates in the range struct */ #define IW_MAX_BITRATES 32 /* Maximum tx powers in the range struct */ #define IW_MAX_TXPOWER 8 /* Note : if you more than 8 TXPowers, just set the max and min or * a few of them in the struct iw_range. */ /* Maximum of address that you may set with SPY */ #define IW_MAX_SPY 8 /* Maximum of address that you may get in the list of access points in range */ #define IW_MAX_AP 64 /* Maximum size of the ESSID and NICKN strings */ #define IW_ESSID_MAX_SIZE 32 /* Modes of operation */ #define IW_MODE_AUTO 0 /* Let the driver decides */ #define IW_MODE_ADHOC 1 /* Single cell network */ #define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ /* Statistics flags (bitmask in updated) */ #define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ #define IW_QUAL_LEVEL_UPDATED 0x02 #define IW_QUAL_NOISE_UPDATED 0x04 #define IW_QUAL_ALL_UPDATED 0x07 #define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ #define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ #define IW_QUAL_LEVEL_INVALID 0x20 #define IW_QUAL_NOISE_INVALID 0x40 #define IW_QUAL_ALL_INVALID 0x70 /* Frequency flags */ #define IW_FREQ_AUTO 0x00 /* Let the driver decides */ #define IW_FREQ_FIXED 0x01 /* Force a specific value */ /* Maximum number of size of encoding token available * they are listed in the range structure */ #define IW_MAX_ENCODING_SIZES 8 /* Maximum size of the encoding token in bytes */ #define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ /* Flags for encoding (along with the token) */ #define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ #define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ #define IW_ENCODE_MODE 0xF000 /* Modes defined below */ #define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ #define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ #define IW_ENCODE_TEMP 0x0400 /* Temporary key */ /* Power management flags available (along with the value, if any) */ #define IW_POWER_ON 0x0000 /* No details... */ #define IW_POWER_TYPE 0xF000 /* Type of parameter */ #define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ #define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ #define IW_POWER_MODE 0x0F00 /* Power Management mode */ #define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ #define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ #define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ #define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ #define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ #define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ #define IW_POWER_MIN 0x0001 /* Value is a minimum */ #define IW_POWER_MAX 0x0002 /* Value is a maximum */ #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ /* Transmit Power flags available */ #define IW_TXPOW_TYPE 0x00FF /* Type of value */ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ #define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ #define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ /* Retry limits and lifetime flags available */ #define IW_RETRY_ON 0x0000 /* No details... */ #define IW_RETRY_TYPE 0xF000 /* Type of parameter */ #define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries */ #define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ #define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */ #define IW_RETRY_MIN 0x0001 /* Value is a minimum */ #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ /* Scanning request flags */ #define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ #define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ #define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ #define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ #define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ #define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ #define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ #define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ #define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ /* struct iw_scan_req scan_type */ #define IW_SCAN_TYPE_ACTIVE 0 #define IW_SCAN_TYPE_PASSIVE 1 /* Maximum size of returned data */ #define IW_SCAN_MAX_DATA 4096 /* In bytes */ /* Max number of char in custom event - use multiple of them if needed */ #define IW_CUSTOM_MAX 256 /* In bytes */ /* Generic information element */ #define IW_GENERIC_IE_MAX 1024 /* MLME requests (SIOCSIWMLME / struct iw_mlme) */ #define IW_MLME_DEAUTH 0 #define IW_MLME_DISASSOC 1 /* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ #define IW_AUTH_INDEX 0x0FFF #define IW_AUTH_FLAGS 0xF000 /* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the * parameter that is being set/get to; value will be read/written to * struct iw_param value field) */ #define IW_AUTH_WPA_VERSION 0 #define IW_AUTH_CIPHER_PAIRWISE 1 #define IW_AUTH_CIPHER_GROUP 2 #define IW_AUTH_KEY_MGMT 3 #define IW_AUTH_TKIP_COUNTERMEASURES 4 #define IW_AUTH_DROP_UNENCRYPTED 5 #define IW_AUTH_80211_AUTH_ALG 6 #define IW_AUTH_WPA_ENABLED 7 #define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 #define IW_AUTH_ROAMING_CONTROL 9 #define IW_AUTH_PRIVACY_INVOKED 10 /* IW_AUTH_WPA_VERSION values (bit field) */ #define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 #define IW_AUTH_WPA_VERSION_WPA 0x00000002 #define IW_AUTH_WPA_VERSION_WPA2 0x00000004 /* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ #define IW_AUTH_CIPHER_NONE 0x00000001 #define IW_AUTH_CIPHER_WEP40 0x00000002 #define IW_AUTH_CIPHER_TKIP 0x00000004 #define IW_AUTH_CIPHER_CCMP 0x00000008 #define IW_AUTH_CIPHER_WEP104 0x00000010 /* IW_AUTH_KEY_MGMT values (bit field) */ #define IW_AUTH_KEY_MGMT_802_1X 1 #define IW_AUTH_KEY_MGMT_PSK 2 /* IW_AUTH_80211_AUTH_ALG values (bit field) */ #define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 #define IW_AUTH_ALG_SHARED_KEY 0x00000002 #define IW_AUTH_ALG_LEAP 0x00000004 /* IW_AUTH_ROAMING_CONTROL values */ #define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ #define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming * control */ /* SIOCSIWENCODEEXT definitions */ #define IW_ENCODE_SEQ_MAX_SIZE 8 /* struct iw_encode_ext ->alg */ #define IW_ENCODE_ALG_NONE 0 #define IW_ENCODE_ALG_WEP 1 #define IW_ENCODE_ALG_TKIP 2 #define IW_ENCODE_ALG_CCMP 3 /* struct iw_encode_ext ->ext_flags */ #define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 #define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 #define IW_ENCODE_EXT_GROUP_KEY 0x00000004 #define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 /* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ #define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ #define IW_MICFAILURE_GROUP 0x00000004 #define IW_MICFAILURE_PAIRWISE 0x00000008 #define IW_MICFAILURE_STAKEY 0x00000010 #define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) */ /* Bit field values for enc_capa in struct iw_range */ #define IW_ENC_CAPA_WPA 0x00000001 #define IW_ENC_CAPA_WPA2 0x00000002 #define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 #define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 /* Event capability macros - in (struct iw_range *)->event_capa * Because we have more than 32 possible events, we use an array of * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ #define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ (cmd - SIOCIWFIRSTPRIV + 0x60) : \ (cmd - SIOCSIWCOMMIT)) #define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) #define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) /* Event capability constants - event autogenerated by the kernel * This list is valid for most 802.11 devices, customise as needed... */ #define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ IW_EVENT_CAPA_MASK(0x8B06) | \ IW_EVENT_CAPA_MASK(0x8B1A)) #define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) /* "Easy" macro to set events in iw_range (less efficient) */ #define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) #define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ /* * Generic format for most parameters that fit in an int */ struct iw_param { __s32 value; /* The value of the parameter itself */ __u8 fixed; /* Hardware should not use auto select */ __u8 disabled; /* Disable the feature */ __u16 flags; /* Various specifc flags (if any) */ }; /* * For all data larger than 16 octets, we need to use a * pointer to memory allocated in user space. */ struct iw_point { void __user *pointer; /* Pointer to the data (in user space) */ __u16 length; /* number of fields or size in bytes */ __u16 flags; /* Optional params */ }; /* * A frequency * For numbers lower than 10^9, we encode the number in 'm' and * set 'e' to 0 * For number greater than 10^9, we divide it by the lowest power * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... * The power of 10 is in 'e', the result of the division is in 'm'. */ struct iw_freq { __s32 m; /* Mantissa */ __s16 e; /* Exponent */ __u8 i; /* List index (when in range struct) */ __u8 flags; /* Flags (fixed/auto) */ }; /* * Quality of the link */ struct iw_quality { __u8 qual; /* link quality (%retries, SNR, %missed beacons or better...) */ __u8 level; /* signal level (dBm) */ __u8 noise; /* noise level (dBm) */ __u8 updated; /* Flags to know if updated */ }; /* * Packet discarded in the wireless adapter due to * "wireless" specific problems... * Note : the list of counter and statistics in net_device_stats * is already pretty exhaustive, and you should use that first. * This is only additional stats... */ struct iw_discarded { __u32 nwid; /* Rx : Wrong nwid/essid */ __u32 code; /* Rx : Unable to code/decode (WEP) */ __u32 fragment; /* Rx : Can't perform MAC reassembly */ __u32 retries; /* Tx : Max MAC retries num reached */ __u32 misc; /* Others cases */ }; /* * Packet/Time period missed in the wireless adapter due to * "wireless" specific problems... */ struct iw_missed { __u32 beacon; /* Missed beacons/superframe */ }; /* * Quality range (for spy threshold) */ struct iw_thrspy { struct sockaddr addr; /* Source address (hw/mac) */ struct iw_quality qual; /* Quality of the link */ struct iw_quality low; /* Low threshold */ struct iw_quality high; /* High threshold */ }; /* * Optional data for scan request * * Note: these optional parameters are controlling parameters for the * scanning behavior, these do not apply to getting scan results * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and * provide a merged results with all BSSes even if the previous scan * request limited scanning to a subset, e.g., by specifying an SSID. * Especially, scan results are required to include an entry for the * current BSS if the driver is in Managed mode and associated with an AP. */ struct iw_scan_req { __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ __u8 essid_len; __u8 num_channels; /* num entries in channel_list; * 0 = scan all allowed channels */ __u8 flags; /* reserved as padding; use zero, this may * be used in the future for adding flags * to request different scan behavior */ struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or * individual address of a specific BSS */ /* * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using * the current ESSID. This allows scan requests for specific ESSID * without having to change the current ESSID and potentially breaking * the current association. */ __u8 essid[IW_ESSID_MAX_SIZE]; /* * Optional parameters for changing the default scanning behavior. * These are based on the MLME-SCAN.request from IEEE Std 802.11. * TU is 1.024 ms. If these are set to 0, driver is expected to use * reasonable default values. min_channel_time defines the time that * will be used to wait for the first reply on each channel. If no * replies are received, next channel will be scanned after this. If * replies are received, total time waited on the channel is defined by * max_channel_time. */ __u32 min_channel_time; /* in TU */ __u32 max_channel_time; /* in TU */ struct iw_freq channel_list[IW_MAX_FREQUENCIES]; }; /* ------------------------- WPA SUPPORT ------------------------- */ /* * Extended data structure for get/set encoding (this is used with * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and * only the data contents changes (key data -> this structure, including * key data). * * If the new key is the first group key, it will be set as the default * TX key. Otherwise, default TX key index is only changed if * IW_ENCODE_EXT_SET_TX_KEY flag is set. * * Key will be changed with SIOCSIWENCODEEXT in all cases except for * special "change TX key index" operation which is indicated by setting * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. * * tx_seq/rx_seq are only used when respective * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally * used only by an Authenticator (AP or an IBSS station) to get the * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for * debugging/testing. */ struct iw_encode_ext { __u32 ext_flags; /* IW_ENCODE_EXT_* */ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast * (group) keys or unicast address for * individual keys */ __u16 alg; /* IW_ENCODE_ALG_* */ __u16 key_len; __u8 key[0]; }; /* SIOCSIWMLME data */ struct iw_mlme { __u16 cmd; /* IW_MLME_* */ __u16 reason_code; struct sockaddr addr; }; /* SIOCSIWPMKSA data */ #define IW_PMKSA_ADD 1 #define IW_PMKSA_REMOVE 2 #define IW_PMKSA_FLUSH 3 #define IW_PMKID_LEN 16 struct iw_pmksa { __u32 cmd; /* IW_PMKSA_* */ struct sockaddr bssid; __u8 pmkid[IW_PMKID_LEN]; }; /* IWEVMICHAELMICFAILURE data */ struct iw_michaelmicfailure { __u32 flags; struct sockaddr src_addr; __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ }; /* IWEVPMKIDCAND data */ #define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ struct iw_pmkid_cand { __u32 flags; /* IW_PMKID_CAND_* */ __u32 index; /* the smaller the index, the higher the * priority */ struct sockaddr bssid; }; /* ------------------------ WIRELESS STATS ------------------------ */ /* * Wireless statistics (used for /proc/net/wireless) */ struct iw_statistics { __u16 status; /* Status * - device dependent for now */ struct iw_quality qual; /* Quality of the link * (instant/mean/max) */ struct iw_discarded discard; /* Packet discarded counts */ struct iw_missed miss; /* Packet missed counts */ }; /* ------------------------ IOCTL REQUEST ------------------------ */ /* * This structure defines the payload of an ioctl, and is used * below. * * Note that this structure should fit on the memory footprint * of iwreq (which is the same as ifreq), which mean a max size of * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... * You should check this when increasing the structures defined * above in this file... */ union iwreq_data { /* Config - generic */ char name[IFNAMSIZ]; /* Name : used to verify the presence of wireless extensions. * Name of the protocol/provider... */ struct iw_point essid; /* Extended network name */ struct iw_param nwid; /* network id (or domain - the cell) */ struct iw_freq freq; /* frequency or channel : * 0-1000 = channel * > 1000 = frequency in Hz */ struct iw_param sens; /* signal level threshold */ struct iw_param bitrate; /* default bit rate */ struct iw_param txpower; /* default transmit power */ struct iw_param rts; /* RTS threshold threshold */ struct iw_param frag; /* Fragmentation threshold */ __u32 mode; /* Operation mode */ struct iw_param retry; /* Retry limits & lifetime */ struct iw_point encoding; /* Encoding stuff : tokens */ struct iw_param power; /* PM duration/timeout */ struct iw_quality qual; /* Quality part of statistics */ struct sockaddr ap_addr; /* Access point address */ struct sockaddr addr; /* Destination address (hw/mac) */ struct iw_param param; /* Other small parameters */ struct iw_point data; /* Other large parameters */ }; /* * The structure to exchange data for ioctl. * This structure is the same as 'struct ifreq', but (re)defined for * convenience... * Do I need to remind you about structure size (32 octets) ? */ struct iwreq { union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ } ifr_ifrn; /* Data part (defined just above) */ union iwreq_data u; }; /* -------------------------- IOCTL DATA -------------------------- */ /* * For those ioctl which want to exchange mode data that what could * fit in the above structure... */ /* * Range of parameters */ struct iw_range { /* Informative stuff (to choose between different interface) */ __u32 throughput; /* To give an idea... */ /* In theory this value should be the maximum benchmarked * TCP/IP throughput, because with most of these devices the * bit rate is meaningless (overhead an co) to estimate how * fast the connection will go and pick the fastest one. * I suggest people to play with Netperf or any benchmark... */ /* NWID (or domain id) */ __u32 min_nwid; /* Minimal NWID we are able to set */ __u32 max_nwid; /* Maximal NWID we are able to set */ /* Old Frequency (backward compat - moved lower ) */ __u16 old_num_channels; __u8 old_num_frequency; /* Wireless event capability bitmasks */ __u32 event_capa[6]; /* signal level threshold range */ __s32 sensitivity; /* Quality of link & SNR stuff */ /* Quality range (link, level, noise) * If the quality is absolute, it will be in the range [0 ; max_qual], * if the quality is dBm, it will be in the range [max_qual ; 0]. * Don't forget that we use 8 bit arithmetics... */ struct iw_quality max_qual; /* Quality of the link */ /* This should contain the average/typical values of the quality * indicator. This should be the threshold between a "good" and * a "bad" link (example : monitor going from green to orange). * Currently, user space apps like quality monitors don't have any * way to calibrate the measurement. With this, they can split * the range between 0 and max_qual in different quality level * (using a geometric subdivision centered on the average). * I expect that people doing the user space apps will feedback * us on which value we need to put in each driver... */ struct iw_quality avg_qual; /* Quality of the link */ /* Rates */ __u8 num_bitrates; /* Number of entries in the list */ __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ /* RTS threshold */ __s32 min_rts; /* Minimal RTS threshold */ __s32 max_rts; /* Maximal RTS threshold */ /* Frag threshold */ __s32 min_frag; /* Minimal frag threshold */ __s32 max_frag; /* Maximal frag threshold */ /* Power Management duration & timeout */ __s32 min_pmp; /* Minimal PM period */ __s32 max_pmp; /* Maximal PM period */ __s32 min_pmt; /* Minimal PM timeout */ __s32 max_pmt; /* Maximal PM timeout */ __u16 pmp_flags; /* How to decode max/min PM period */ __u16 pmt_flags; /* How to decode max/min PM timeout */ __u16 pm_capa; /* What PM options are supported */ /* Encoder stuff */ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ __u8 num_encoding_sizes; /* Number of entry in the list */ __u8 max_encoding_tokens; /* Max number of tokens */ /* For drivers that need a "login/passwd" form */ __u8 encoding_login_index; /* token index for login token */ /* Transmit power */ __u16 txpower_capa; /* What options are supported */ __u8 num_txpower; /* Number of entries in the list */ __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ /* Wireless Extension version info */ __u8 we_version_compiled; /* Must be WIRELESS_EXT */ __u8 we_version_source; /* Last update of source */ /* Retry limits and lifetime */ __u16 retry_capa; /* What retry options are supported */ __u16 retry_flags; /* How to decode max/min retry limit */ __u16 r_time_flags; /* How to decode max/min retry life */ __s32 min_retry; /* Minimal number of retries */ __s32 max_retry; /* Maximal number of retries */ __s32 min_r_time; /* Minimal retry lifetime */ __s32 max_r_time; /* Maximal retry lifetime */ /* Frequency */ __u16 num_channels; /* Number of channels [0; num - 1] */ __u8 num_frequency; /* Number of entry in the list */ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ /* Note : this frequency list doesn't need to fit channel numbers, * because each entry contain its channel index */ __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ }; /* * Private ioctl interface information */ struct iw_priv_args { __u32 cmd; /* Number of the ioctl to issue */ __u16 set_args; /* Type and number of args */ __u16 get_args; /* Type and number of args */ char name[IFNAMSIZ]; /* Name of the extension */ }; /* ----------------------- WIRELESS EVENTS ----------------------- */ /* * Wireless events are carried through the rtnetlink socket to user * space. They are encapsulated in the IFLA_WIRELESS field of * a RTM_NEWLINK message. */ /* * A Wireless Event. Contains basically the same data as the ioctl... */ struct iw_event { __u16 len; /* Real length of this stuff */ __u16 cmd; /* Wireless IOCTL */ union iwreq_data u; /* IOCTL fixed payload */ }; /* Size of the Event prefix (including padding and alignement junk) */ #define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) /* Size of the various events */ #define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) #define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) #define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) #define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) #define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) #define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) /* iw_point events are special. First, the payload (extra data) come at * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, * we omit the pointer, so start at an offset. */ #define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ (char *) NULL) #define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ IW_EV_POINT_OFF) #endif /* _LINUX_WIRELESS_H */ ================================================ FILE: wum/README ================================================ WUM - WTP Update Manager Wum (WTP Update Manager) is the command line tool used to send update requests to the WTPs. Of course it is executed on the AC machine and interacts with the AC Interface. To compile it, just run 'make'. For further details about how to use it, refer to the document WTPUpdateSystem.pdf in the docs sub-directory of this source tree. ================================================ FILE: wum/wum.c ================================================ #include #include #include #include #include #include #include #include "wumLib.h" void printWTPList(struct WTPInfo *wtpList, int nWTPs); void printVersionHeader(); void printVersionInfo(struct version_info v_info, int wtpId, struct WTPInfo *wtpList); void printVersionFooter(); void do_version_cmd(int acserver, char *wtpIds, char *wtpNames); void do_update_cmd(int acserver, char *wtpIds, char *wtpNames, char *cup_path); void do_cancel_cmd(int acserver, char *wtpIds, char *wtpNames); int get_cmd_id(char *cmd); char *WTP_id2name(int id); void usage(char *name); #define ACSERVER_ADDRESS "127.0.0.1" #define ACSERVER_PORT 1235 /* Commands */ #define CMD_NUM 4 typedef struct { char id; const char *name; } cmd_t; enum { NO_CMD, WTPS_CMD, VERSION_CMD, UPDATE_CMD, CANCEL_CMD }; cmd_t CMDs[] = { {WTPS_CMD, "wtps"}, {VERSION_CMD, "version"}, {UPDATE_CMD, "update"}, {CANCEL_CMD, "cancel"}, {NO_CMD, ""} }; /* Global WTP List */ struct WTPInfo *wtpList; int nWTPs; int main(int argc, char *argv[]) { int acserver, wtpId, cmd_id; void *cup; struct version_info update_v; char *command = NULL, *cup_path = NULL; char *wtpIds = NULL, *wtpNames = NULL; char *acserver_address = ACSERVER_ADDRESS; int acserver_port = ACSERVER_PORT;; int index; int c; opterr = 0; /* Parse options */ while ((c = getopt(argc, argv, "ha:p:w:c:f:n:")) != -1) switch (c) { case 'a': acserver_address = optarg; break; case 'p': acserver_port = atoi(optarg); break; case 'w': wtpIds = optarg; break; case 'n': wtpNames = optarg; break; case 'c': command = optarg; break; case 'f': cup_path = optarg; break; case 'h': usage(argv[0]); break; case '?': if (optopt == 'w' || optopt == 'c' || optopt == 'f' || optopt == 'n') fprintf(stderr, "Option -%c requires an argument.\n", optopt); else if (isprint(optopt)) fprintf(stderr, "Unknown option `-%c'.\n", optopt); else fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); exit(EXIT_FAILURE); default: usage(argv[0]); abort(); } /* Check arguments */ if (command == NULL) { fprintf(stderr, "No command specified!\n"); exit(EXIT_FAILURE); } if ((cmd_id = get_cmd_id(command)) == NO_CMD) { fprintf(stderr, "Wrong command specified!"); } /* Connect to server and get WTPs list */ acserver = ACServerConnect(acserver_address, acserver_port); wtpList = ACServerWTPList(acserver, &nWTPs); /* Execute command */ switch (cmd_id) { case WTPS_CMD: printWTPList(wtpList, nWTPs); break; case VERSION_CMD: do_version_cmd(acserver, wtpIds, wtpNames); break; case UPDATE_CMD: do_update_cmd(acserver, wtpIds, wtpNames, cup_path); break; case CANCEL_CMD: do_cancel_cmd(acserver, wtpIds, wtpNames); break; } freeWTPList(wtpList, nWTPs); ACServerDisconnect(acserver); exit(EXIT_SUCCESS); } int sanitize_wtp_list(int *work_list, int n) { int i, j, z, new_size = n; /* Delete unknown wtp ids */ for (i = 0; i < new_size; i++) { if (WTP_id2name(work_list[i]) == NULL) { for (j = i; j < new_size - 1; j++) { work_list[j] = work_list[j + 1]; } i--; new_size--; } } /* Delete duplicates */ for (i = 0; i < new_size; i++) { for (j = i + 1; j < new_size; j++) { if (work_list[i] == work_list[j]) { for (z = j; z < new_size - 1; z++) { work_list[z] = work_list[z + 1]; } j--; new_size--; } } } return new_size; } int *all_WTPs() { int *ret, i; ret = malloc(nWTPs * sizeof(int)); for (i = 0; i < nWTPs; i++) { ret[i] = wtpList[i].wtpId; } return ret; } int count_tokens(char *str1, char *str2) { int n = 1; char *ptr; if (str1 != NULL) ptr = str1; else if (str2 != NULL) ptr = str2; else return 0; while (*ptr != '\0') { if (*ptr == ',' && *(ptr + 1) != ',' && *(ptr + 1) != '\0') n++; ptr++; } return n; } int *get_id_list(char *wtpIds, char *wtpNames, int *n) { char *token, *ptr; int *ret = NULL; int i; *n = count_tokens(wtpIds, wtpNames); if (*n <= 0) return NULL; /* allocate memory */ ret = malloc(*n * sizeof(int)); if (ret == NULL) { perror("malloc error!"); return NULL; } if (wtpIds != NULL) { /* read ids */ token = (char *)strtok(wtpIds, ","); ret[0] = atoi(token); if (ret[0] == -1) return all_WTPs(); for (i = 1; i < *n; i++) ret[i] = atoi((const char *)strtok(NULL, ",")); } else { /* read names and convert into ids */ for (i = 0; i < *n; i++) { int id; if (i == 0) { token = (char *)strtok(wtpNames, ","); if (strcmp(token, "all") == 0) return all_WTPs(); } else { token = (char *)strtok(NULL, ","); } if ((id = WTP_name2id(token)) == -1) { fprintf(stderr, "%s: specified WTP does not exits\n", token); } ret[i] = id; } } /* remove duplicated and unknown WTP ids */ *n = sanitize_wtp_list(ret, *n); return ret; } void do_version_cmd(int acserver, char *wtpIds, char *wtpNames) { int *wtps, n, i; struct version_info v_info; /* WTP work list */ wtps = get_id_list(wtpIds, wtpNames, &n); if (wtps == NULL) { fprintf(stderr, "Either a list of wtp ids or wtp names must be specified!\n"); return; } printVersionHeader(); for (i = 0; i < n; i++) { WUMGetWTPVersion(acserver, wtps[i], &v_info); printVersionInfo(v_info, wtps[i], wtpList); } printVersionFooter(); } void do_update_cmd(int acserver, char *wtpIds, char *wtpNames, char *cup_path) { int *wtps, n, i, ret; struct version_info update_v; void *cup; if (cup_path == NULL) { fprintf(stderr, "In order to execute an update, an update package must be specified! (-f pathname)\n"); return; } /* WTP work list */ wtps = get_id_list(wtpIds, wtpNames, &n); if (wtps == NULL) { fprintf(stderr, "Either a list of wtp ids or wtp names must be specified!\n"); return; } int fd = open(cup_path, O_RDONLY); if (fd < 0) { perror("open error"); return; } if (WUMReadCupVersion(cup_path, &update_v)) { return; } cup = mmap(NULL, update_v.size, PROT_READ, MAP_SHARED, fd, 0); if (cup == NULL) { perror("mmap error"); return; } printf("*--------*--------------------------------*------------*\n"); printf("| %-6s | %-30s | %-10s |\n", "WTP Id", "WTp Name", "Result"); printf("*--------*--------------------------------*------------*\n"); for (i = 0; i < n; i++) { ret = WUMUpdate(acserver, i, cup, update_v); printf("| %-6d | %-30s | %-10s |\n", wtpList[i].wtpId, wtpList[i].name, (ret == 0) ? "SUCCESS" : "FAILURE"); } printf("*--------*--------------------------------*------------*\n"); munmap(cup, update_v.size); close(fd); } void do_cancel_cmd(int acserver, char *wtpIds, char *wtpNames) { int *wtps, n, i; struct version_info v_info; /* WTP work list */ wtps = get_id_list(wtpIds, wtpNames, &n); if (wtps == NULL) { fprintf(stderr, "Either a list of wtp ids or wtp names must be specified!\n"); return; } for (i = 0; i < n; i++) { if (WUMSendCancelRequest(acserver, wtps[i])) { fprintf(stderr, "Error while handling cancel request to WTP %d.\n", wtps[i]); } else { printf("Cancel request sent for WTP %d\n", wtps[i]); } } } int WTP_name2id(char *name) { int i; for (i = 0; i < nWTPs; i++) { if (strcmp(name, wtpList[i].name) == 0) { /* found WTP! */ return wtpList[i].wtpId; } } return -1; } char *WTP_id2name(int id) { int i; for (i = 0; i < nWTPs; i++) { if (wtpList[i].wtpId == id) return wtpList[i].name; } return NULL; } int get_cmd_id(char *cmd) { int i; for (i = 0; i < CMD_NUM; i++) { if (strcmp(CMDs[i].name, cmd) == 0) break; } return CMDs[i].id; } void printWTPList(struct WTPInfo *wtpList, int nWTPs) { int i; printf("*-------*--------------------------------*\n"); printf("| %5s | %-30s |\n", "WTPId", "WTPName"); printf("*-------*--------------------------------*\n"); printf("| %5s | %-30s |\n", "-1", "all"); if (wtpList != NULL) { for (i = 0; i < nWTPs; i++) { printf("| %5d | %-30s |\n", wtpList[i].wtpId, wtpList[i].name); } } printf("*-------*--------------------------------*\n"); } void printVersionHeader() { printf("*-------*--------------------------------*-----------------*\n"); printf("| %5s | %-30s | %-15s |\n", "WTPId", "WTPName", "Version"); printf("*-------*--------------------------------*-----------------*\n"); } void printVersionInfo(struct version_info v_info, int wtpId, struct WTPInfo *wtpList) { char buf[15]; snprintf(buf, 15, "%d.%d.%d", v_info.major, v_info.minor, v_info.revision); printf("| %5d | %-30s | %-15s |\n", wtpList[wtpId].wtpId, wtpList[wtpId].name, buf); } void printVersionFooter() { printf("*-------*--------------------------------*-----------------*\n"); } void usage(char *name) { printf("%s -c command [-w id1,...] [-n name1,...] [-f cup_file] [-a address] [-p port]\n", name); printf("\nAvailable commands:\n"); printf(" wtps: list of active wtps.\n"); printf("version: version of the specified list of wtps (use -w or -n).\n"); printf(" update: sends a cup (specified with -f) to the specified list of wtps (use -w or -n).\n"); printf(" cancel: cancel a pending update on the desired wtps (use -w or -n).\n"); } ================================================ FILE: wum/wumLib.c ================================================ #include #include #include #include #include #include #include #include #include #include "wumLib.h" #define SA const struct sockaddr #define BUF_SIZE 1024 int Readn(int fd, void *ptr, size_t nbytes); int Writen(int fd, void *ptr, size_t nbytes); void readWTPInfo(int acserver, struct WTPInfo *WTPInfo, int pos); typedef struct __attribute__ ((__packed__)) { char cmd_msg; char msg_elem; int wtpId; char wum_type; int payload_len; char *payload; } wum_req_t; typedef struct { int wtpId; int resultCode; char wum_type; int payload_len; char *payload; int offset; } wum_resp_t; #define WUM_INIT_REQ_MSG(msg, size) do { msg.payload_len = 0; msg.payload=malloc(size); } while(0); #define WUM_DESTROY_MSG(msg) do { if (msg.payload_len != 0) free(msg.payload); } while(0); int Read32(int fd, int *ptr); int Write32(int fd, void *ptr); int WUMSendMessage(int acserver, wum_req_t msg); int WUMReceiveMessage(int acserver, wum_resp_t * msg); char WUMPayloadRetrieve8(wum_resp_t * resp); void WUMPayloadStore8(wum_req_t * req, char c); void WUMPayloadStore32(wum_req_t * req, int i); void WUMPayloadStoreRawBytes(wum_req_t * req, void *buf, int size); #define MIN(a,b) (a < b) ? (a) : (b) int ACServerConnect(char *address, int port) { int sockfd, ret; struct sockaddr_in servaddr; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error:"); exit(1); } bzero(&servaddr, sizeof(struct sockaddr_in)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(port); inet_pton(AF_INET, address, &servaddr.sin_addr); if (connect(sockfd, (SA *) & servaddr, sizeof(servaddr)) < 0) { perror("connect error:"); exit(1); } if (Read32(sockfd, &ret) != 4) { exit(1); } if (ret == -1) { fprintf(stderr, "The AC Server's Client Queue Is Currently Full.\n"); exit(1); } else if (ret != 1) { fprintf(stderr, "Something Wrong Happened While Connecting To The AC Server.\n"); exit(1); } return sockfd; } void ACServerDisconnect(int acserver) { char msg = QUIT_MSG; if (Writen(acserver, &msg, 1) != 1) { fprintf(stderr, "Error while sending QUIT message.\n"); } if (close(acserver) < 0) { perror("close error:"); } } struct WTPInfo *ACServerWTPList(int acserver, int *nWTPs) { char msg = LIST_MSG; int activeWTPs, i; struct WTPInfo *WTPList; if (Writen(acserver, &msg, 1) != 1) { fprintf(stderr, "Error while sending LIST message.\n"); return NULL; } if (Read32(acserver, &activeWTPs) != 4) { fprintf(stderr, "Error while receiving WTP Number.\n"); return NULL; } if ((WTPList = malloc(activeWTPs * sizeof(struct WTPInfo))) == NULL) { perror("malloc error"); return NULL; } for (i = 0; i < activeWTPs; i++) { readWTPInfo(acserver, WTPList, i); } *nWTPs = activeWTPs; return WTPList; } void readWTPInfo(int acserver, struct WTPInfo *WTPInfo, int pos) { int nameLen; if (Read32(acserver, &(WTPInfo[pos].wtpId)) != 4) { fprintf(stderr, "Error while reading wtp index.\n"); goto err; } if (Read32(acserver, &nameLen) != 4) { fprintf(stderr, "Error while reading wtp name len.\n"); goto err; } if ((WTPInfo[pos].name = malloc(nameLen + 1)) == NULL) { fprintf(stderr, "Malloc error\n"); goto err; } if (Readn(acserver, WTPInfo[pos].name, nameLen) != nameLen) { fprintf(stderr, "Error while reading wtp name len.\n"); goto err; } WTPInfo[pos].name[nameLen] = '\0'; return; err: ACServerDisconnect(acserver); exit(1); } void freeWTPList(struct WTPInfo *wtpList, int nWTPs) { int i; /* We do not free the first name, the default one */ for (i = 0; i < nWTPs; i++) { free(wtpList[i].name); } free(wtpList); } int WUMGetWTPVersion(int acserver, int wtpId, struct version_info *v_info) { wum_req_t msg; wum_resp_t resp; WUM_INIT_REQ_MSG(msg, 0); msg.cmd_msg = CONF_UPDATE_MSG; msg.msg_elem = MSG_ELEMENT_TYPE_VENDOR_WUM; msg.wtpId = wtpId; msg.wum_type = WTP_VERSION_REQUEST; if (WUMSendMessage(acserver, msg) != 0) { fprintf(stderr, "Error while sending WUM message"); return ERROR; } if (WUMReceiveMessage(acserver, &resp) != 0) { fprintf(stderr, "Error while reading response message"); return ERROR; } resp.wum_type = WUMPayloadRetrieve8(&resp); if (resp.wum_type != WTP_VERSION_RESPONSE) { fprintf(stderr, "Received wrong response message!"); return ERROR; } v_info->major = WUMPayloadRetrieve8(&resp); v_info->minor = WUMPayloadRetrieve8(&resp); v_info->revision = WUMPayloadRetrieve8(&resp); return SUCCESS; } void StringToLower(char *str) { for (; *str != '\0'; str++) *str = tolower(*str); } int WUMReadCupVersion(char *cup_pathname, struct version_info *update_v) { int ret; char buf[BUF_SIZE]; char *token; struct stat s_buf; FILE *cud; snprintf(buf, BUF_SIZE, "tar xzf %s -C /tmp update.cud", cup_pathname); ret = system(buf); if (ret != 0) return ERROR; cud = fopen("/tmp/update.cud", "r"); if (cud == NULL) { fprintf(stderr, "Error while opening cud descriptor.\n"); return ERROR; } while (fgets(buf, BUF_SIZE, cud) != NULL) { token = strtok(buf, " "); StringToLower(token); if (strncmp(token, "version", 7) == 0) { token = strtok(NULL, " "); if (token == NULL) { fprintf(stderr, "Error while parsing update version."); return ERROR; } token = strtok(token, "."); update_v->major = atoi(token); token = strtok(NULL, "."); update_v->minor = atoi(token); token = strtok(NULL, "."); update_v->revision = atoi(token); } } fclose(cud); remove("/tmp/update.cud"); if (stat(cup_pathname, &s_buf) != 0) { fprintf(stderr, "Stat error!.\n"); return ERROR; } update_v->size = s_buf.st_size; return SUCCESS; } int WUMSendCommitRequest(int acserver, int wtpId) { wum_req_t msg; wum_resp_t resp; WUM_INIT_REQ_MSG(msg, 0); msg.cmd_msg = CONF_UPDATE_MSG; msg.msg_elem = MSG_ELEMENT_TYPE_VENDOR_WUM; msg.wtpId = wtpId; msg.wum_type = WTP_COMMIT_UPDATE; if (WUMSendMessage(acserver, msg) != 0) { fprintf(stderr, "Error while sending WUM message"); return ERROR; } if (WUMReceiveMessage(acserver, &resp) != 0) { fprintf(stderr, "Error while reading response message"); return ERROR; } resp.wum_type = WUMPayloadRetrieve8(&resp); if (resp.wum_type != WTP_COMMIT_ACK) { fprintf(stderr, "Received wrong response message!"); return ERROR; } return resp.resultCode; } int WUMSendCancelRequest(int acserver, int wtpId) { wum_req_t msg; wum_resp_t resp; WUM_INIT_REQ_MSG(msg, 0); msg.cmd_msg = CONF_UPDATE_MSG; msg.msg_elem = MSG_ELEMENT_TYPE_VENDOR_WUM; msg.wtpId = wtpId; msg.wum_type = WTP_CANCEL_UPDATE_REQUEST; if (WUMSendMessage(acserver, msg) != 0) { fprintf(stderr, "Error while sending WUM message"); return ERROR; } if (WUMReceiveMessage(acserver, &resp) != 0) { fprintf(stderr, "Error while reading response message"); return ERROR; } resp.wum_type = WUMPayloadRetrieve8(&resp); if (resp.wum_type != WTP_CANCEL_UPDATE_RESPONSE) { fprintf(stderr, "Received wrong response message!"); return ERROR; } return resp.resultCode; } int WUMSendFragment(int acserver, int wtpId, void *buf, int size, int seq) { wum_req_t msg; wum_resp_t resp; WUM_INIT_REQ_MSG(msg, size + 2 * sizeof(int)); msg.cmd_msg = CONF_UPDATE_MSG; msg.msg_elem = MSG_ELEMENT_TYPE_VENDOR_WUM; msg.wtpId = wtpId; msg.wum_type = WTP_CUP_FRAGMENT; WUMPayloadStore32(&msg, seq); WUMPayloadStore32(&msg, size); WUMPayloadStoreRawBytes(&msg, buf, size); if (WUMSendMessage(acserver, msg) != 0) { fprintf(stderr, "Error while sending WUM message"); return ERROR; } if (WUMReceiveMessage(acserver, &resp) != 0) { fprintf(stderr, "Error while reading response message"); return ERROR; } resp.wum_type = WUMPayloadRetrieve8(&resp); if (resp.wum_type != WTP_CUP_ACK) { fprintf(stderr, "Received wrong response message!"); return ERROR; } WUM_DESTROY_MSG(msg); return resp.resultCode; } int WUMUpdate(int acserver, int wtpId, void *cup_buf, struct version_info update_v) { int i, left, toSend, sent; if (WUMSendUpdateRequest(acserver, wtpId, update_v)) { fprintf(stderr, "Update request failed for WTP: %d\n", wtpId); return ERROR; } /* Send update fragments */ sent = 0; left = update_v.size; toSend = MIN(FRAGMENT_SIZE, left); for (i = 0; left > 0; i++) { if (WUMSendFragment(acserver, wtpId, cup_buf + sent, toSend, i)) { fprintf(stderr, "Error while sending fragment #%d\n", i); return ERROR; } left -= toSend; sent += toSend; toSend = MIN(FRAGMENT_SIZE, left); } if (WUMSendCommitRequest(acserver, wtpId)) { fprintf(stderr, "Update request failed for WTP: %d\n", wtpId); return ERROR; } return SUCCESS; } int WUMSendUpdateRequest(int acserver, int wtpId, struct version_info update_v) { wum_req_t msg; wum_resp_t resp; WUM_INIT_REQ_MSG(msg, 3 + sizeof(int)); msg.cmd_msg = CONF_UPDATE_MSG; msg.msg_elem = MSG_ELEMENT_TYPE_VENDOR_WUM; msg.wtpId = wtpId; msg.wum_type = WTP_UPDATE_REQUEST; WUMPayloadStore8(&msg, update_v.major); WUMPayloadStore8(&msg, update_v.minor); WUMPayloadStore8(&msg, update_v.revision); WUMPayloadStore32(&msg, update_v.size); if (WUMSendMessage(acserver, msg) != 0) { fprintf(stderr, "Error while sending WUM message"); return ERROR; } if (WUMReceiveMessage(acserver, &resp) != 0) { fprintf(stderr, "Error while reading response message"); return ERROR; } WUM_DESTROY_MSG(msg) return resp.resultCode; } int WUMSendMessage(int acserver, wum_req_t msg) { /* Fix byte order issues */ msg.wtpId = htonl(msg.wtpId); if (Writen(acserver, &msg, 7) != 7) { fprintf(stderr, "Error while sending CONF_UPDATE_MSG message.\n"); return ERROR; } if (msg.payload_len > 0) { if (Writen(acserver, msg.payload, msg.payload_len) != msg.payload_len) { fprintf(stderr, "Error while sending CONF_UPDATE_MSG message.\n"); return ERROR; } } return SUCCESS; } int WUMReceiveMessage(int acserver, wum_resp_t * msg) { int len; msg->offset = 0; if (Read32(acserver, &(msg->wtpId)) != 4) { fprintf(stderr, "Error while reading wtpId.\n"); return ERROR; } if (Read32(acserver, &(msg->resultCode)) != 4) { fprintf(stderr, "Error while reading result code.\n"); return ERROR; } if (Read32(acserver, &(msg->payload_len)) != 4) { fprintf(stderr, "Error while reading payload length.\n"); return ERROR; } if (msg->payload_len > 0) { msg->payload = malloc(msg->payload_len); if (Readn(acserver, msg->payload, msg->payload_len) != msg->payload_len) { fprintf(stderr, "Error while reading payload.\n"); return ERROR; } } return SUCCESS; } char WUMPayloadRetrieve8(wum_resp_t * resp) { return resp->payload[resp->offset++]; } void WUMPayloadStore8(wum_req_t * req, char c) { req->payload[req->payload_len++] = c; } void WUMPayloadStore32(wum_req_t * req, int i) { i = htonl(i); memcpy(req->payload + req->payload_len, &i, 4); req->payload_len += 4; } void WUMPayloadStoreRawBytes(wum_req_t * req, void *buf, int size) { memcpy(req->payload + req->payload_len, buf, size); req->payload_len += size; } int /* Read "n" bytes from a descriptor. */ readn(int fd, void *vptr, size_t n) { size_t nleft; ssize_t nread; char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nread = recv(fd, ptr, nleft, 0)) < 0) { if (errno == EINTR) nread = 0; /* and call read() again */ else return (-1); } else if (nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } return (n - nleft); /* return >= 0 */ } int Readn(int fd, void *ptr, size_t nbytes) { int n; if ((n = readn(fd, ptr, nbytes)) < 0) perror("readn error"); return (n); } int /* Write "n" bytes to a descriptor. */ writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nwritten = send(fd, ptr, nleft, 0)) <= 0) { if (errno == EINTR) nwritten = 0; /* and call write() again */ else return (-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return (n); } int Writen(int fd, void *ptr, size_t nbytes) { int n; while ((n = writen(fd, ptr, nbytes)) < 0) perror("writen error"); return n; } int Read32(int fd, int *ptr) { int ret; ret = Readn(fd, ptr, 4); *ptr = ntohl(*ptr); return ret; } int Write32(int fd, void *ptr) { } ================================================ FILE: wum/wumLib.h ================================================ #include #define QUIT_MSG 0 #define LIST_MSG 1 #define CONF_UPDATE_MSG 2 #define MSG_ELEMENT_TYPE_VENDOR_WUM 3 #define WTP_VERSION_REQUEST 1 #define WTP_VERSION_RESPONSE 2 #define WTP_UPDATE_REQUEST 3 #define WTP_UPDATE_RESPONSE 4 #define WTP_CUP_FRAGMENT 5 #define WTP_CUP_ACK 6 #define WTP_COMMIT_UPDATE 7 #define WTP_COMMIT_ACK 8 #define WTP_CANCEL_UPDATE_REQUEST 9 #define WTP_CANCEL_UPDATE_RESPONSE 10 #define SUCCESS 0 #define ERROR 1 #define FRAGMENT_SIZE 4000 struct WTPInfo { int wtpId; char *name; }; struct version_info { char major; char minor; char revision; int size; }; int ACServerConnect(char *address, int port); void ACServerDisconnect(int acserver); struct WTPInfo *ACServerWTPList(int acserver, int *nWTPs); void freeWTPList(struct WTPInfo *wtpList, int nWTPs); int WUMGetWTPVersion(int acserver, int wtpId, struct version_info *); int WUMReadCupVersion(char *cup_pathname, struct version_info *update_v); int WUMUpdate(int acserver, int wtpId, void *cup_buf, struct version_info update_v); int WUMSendCancelRequest(int acserver, int wtpId);