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; i