mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #4306 from c1728p9/remove_unsupported_net_libraries
Remove unsupported net librariespull/4183/head
commit
01f02b4b8c
|
@ -1,78 +0,0 @@
|
|||
/* CellularModem.h */
|
||||
/* Copyright (C) 2013 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef CELLULARMODEM_H_
|
||||
#define CELLULARMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
class CellularModem
|
||||
{
|
||||
public:
|
||||
//Internet-related functions
|
||||
|
||||
/** Open a 3G internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL) = 0;
|
||||
|
||||
/** Close the internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int disconnect() = 0;
|
||||
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int sendSM(const char* number, const char* message) = 0;
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSM(char* number, char* message, size_t maxLength) = 0;
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSMCount(size_t* pCount) = 0;
|
||||
|
||||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
virtual ATCommandsInterface* getATCommandsInterface() = 0;
|
||||
|
||||
/** Switch power on or off
|
||||
In order to use this function, a pin name must have been entered in the constructor
|
||||
@param enable true to switch the dongle on, false to switch it off
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int power(bool enable) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* CELLULARMODEM_H_ */
|
|
@ -1,902 +0,0 @@
|
|||
/* ATCommandsInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 2 //ERR+WARN
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "ATCommandsInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring> //For memset, strstr...
|
||||
|
||||
using std::memmove;
|
||||
|
||||
#include "ATCommandsInterface.h"
|
||||
|
||||
ATCommandsInterface::ATCommandsInterface(IOStream* pStream) :
|
||||
m_pStream(pStream), m_open(false), m_transactionState(IDLE), m_env2AT(), m_AT2Env(), m_processingMtx(),
|
||||
m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192),
|
||||
m_eventsMgmtMtx(), m_eventsProcessingMtx()
|
||||
{
|
||||
memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*));
|
||||
|
||||
m_processingMtx.lock();
|
||||
}
|
||||
|
||||
//Open connection to AT Interface in order to execute command & register/unregister events
|
||||
int ATCommandsInterface::open()
|
||||
{
|
||||
if( m_open )
|
||||
{
|
||||
WARN("AT interface is already open");
|
||||
return OK;
|
||||
}
|
||||
DBG("Opening AT interface");
|
||||
//Start processing
|
||||
m_processingThread.signal_set(AT_SIG_PROCESSING_START);
|
||||
|
||||
m_processingMtx.unlock();
|
||||
|
||||
m_open = true;
|
||||
|
||||
DBG("AT interface opened");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//Initialize AT link & start events processing
|
||||
int ATCommandsInterface::init(bool reset /* = true*/)
|
||||
{
|
||||
|
||||
//Lock transaction mutex
|
||||
m_transactionMtx.lock();
|
||||
|
||||
if (reset)
|
||||
{
|
||||
DBG("Sending ATZ E1 V1");
|
||||
//Should we flush m_pStream at this point ???
|
||||
int err;
|
||||
int tries = 5;
|
||||
do
|
||||
{
|
||||
err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
|
||||
if(err && tries)
|
||||
{
|
||||
WARN("No response, trying again");
|
||||
Thread::wait(1000); //Give dongle time to recover
|
||||
}
|
||||
} while(err && tries--);
|
||||
if( err )
|
||||
{
|
||||
ERR("Sending ATZ E1 V1 returned with err code %d", err);
|
||||
m_transactionMtx.unlock();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
//Enable events handling and execute events enabling commands
|
||||
enableEvents();
|
||||
|
||||
DBG("AT interface initialized");
|
||||
|
||||
//Unlock transaction mutex
|
||||
m_transactionMtx.unlock();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//Close connection
|
||||
int ATCommandsInterface::close()
|
||||
{
|
||||
if( !m_open )
|
||||
{
|
||||
WARN("AT interface is already closed");
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Closing AT interface");
|
||||
|
||||
//Lock transaction mutex
|
||||
m_transactionMtx.lock();
|
||||
|
||||
//Disable events handling and advertize this to the events handlers
|
||||
disableEvents();
|
||||
|
||||
//Stop processing
|
||||
m_processingThread.signal_set(AT_SIG_PROCESSING_STOP);
|
||||
//m_stopSphre.release();
|
||||
|
||||
int* msg = m_env2AT.alloc(osWaitForever);
|
||||
*msg = AT_STOP;
|
||||
m_env2AT.put(msg); //Used to unstall the process if needed
|
||||
|
||||
//Unlock process routine (abort read)
|
||||
m_pStream->abortRead(); //This is thread-safe
|
||||
m_processingMtx.lock();
|
||||
m_open = false;
|
||||
|
||||
//Unlock transaction mutex
|
||||
m_transactionMtx.unlock();
|
||||
|
||||
DBG("AT interface closed");
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool ATCommandsInterface::isOpen()
|
||||
{
|
||||
return m_open;
|
||||
}
|
||||
|
||||
int ATCommandsInterface::executeSimple(const char* command, ATResult* pResult, uint32_t timeout/*=1000*/)
|
||||
{
|
||||
return execute(command, this, pResult, timeout);
|
||||
}
|
||||
|
||||
int ATCommandsInterface::execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
|
||||
{
|
||||
if(!m_open)
|
||||
{
|
||||
WARN("Interface is not open!");
|
||||
return NET_INVALID;
|
||||
}
|
||||
|
||||
//Lock transaction mutex
|
||||
m_transactionMtx.lock();
|
||||
|
||||
disableEvents(); //Disable unsollicited result codes
|
||||
int ret = executeInternal(command, pProcessor, pResult, timeout);
|
||||
enableEvents(); //Re-enable unsollicited result codes whatever the result of the command is
|
||||
|
||||
//Unlock transaction mutex
|
||||
m_transactionMtx.unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr)
|
||||
{
|
||||
m_eventsMgmtMtx.lock();
|
||||
m_eventsProcessingMtx.lock();
|
||||
for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
|
||||
{
|
||||
if( m_eventsHandlers[i] == NULL )
|
||||
{
|
||||
m_eventsHandlers[i] = pHdlr;
|
||||
m_eventsProcessingMtx.unlock();
|
||||
m_eventsMgmtMtx.unlock();
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
m_eventsProcessingMtx.unlock();
|
||||
m_eventsMgmtMtx.unlock();
|
||||
return NET_OOM; //No room left
|
||||
}
|
||||
|
||||
int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr)
|
||||
{
|
||||
m_eventsMgmtMtx.lock();
|
||||
m_eventsProcessingMtx.lock();
|
||||
for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find handler in list
|
||||
{
|
||||
if( m_eventsHandlers[i] == pHdlr )
|
||||
{
|
||||
m_eventsHandlers[i] = NULL;
|
||||
m_eventsProcessingMtx.unlock();
|
||||
m_eventsMgmtMtx.unlock();
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
m_eventsProcessingMtx.unlock();
|
||||
m_eventsMgmtMtx.unlock();
|
||||
return NET_NOTFOUND; //Not found
|
||||
}
|
||||
|
||||
//Private methods
|
||||
|
||||
int ATCommandsInterface::executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
|
||||
{
|
||||
DBG("Executing command %s", command);
|
||||
|
||||
//Discard previous result if it arrived too late
|
||||
osEvent evt = m_AT2Env.get(0);
|
||||
|
||||
if(evt.status == osEventMail)
|
||||
{
|
||||
m_AT2Env.free((int*)evt.value.p);
|
||||
WARN("Previous result discarded");
|
||||
}
|
||||
|
||||
//Send params to the process routine
|
||||
m_transactionCommand = command;
|
||||
if(pProcessor != NULL)
|
||||
{
|
||||
m_pTransactionProcessor = pProcessor;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pTransactionProcessor = this; //Use default behaviour
|
||||
}
|
||||
|
||||
DBG("Sending command ready signal to AT thread & aborting current blocking read operation");
|
||||
|
||||
//Produce command ready signal
|
||||
int* msg = m_env2AT.alloc(osWaitForever);
|
||||
*msg = AT_CMD_READY;
|
||||
m_env2AT.put(msg);
|
||||
|
||||
DBG("Trying to enter abortRead()");
|
||||
//Unlock process routine (abort read)
|
||||
m_pStream->abortRead(); //This is thread-safe
|
||||
|
||||
//Wait for a result (get result message)
|
||||
evt = m_AT2Env.get(timeout);
|
||||
|
||||
if(evt.status != osEventMail)
|
||||
{
|
||||
//Cancel request
|
||||
msg = m_env2AT.alloc(osWaitForever);
|
||||
*msg = AT_TIMEOUT;
|
||||
m_env2AT.put(msg);
|
||||
|
||||
DBG("Trying to enter abortRead()");
|
||||
//Unlock process routine (abort read)
|
||||
m_pStream->abortRead(); //This is thread-safe
|
||||
|
||||
//Wait for acknowledge
|
||||
int msgResult;
|
||||
do
|
||||
{
|
||||
evt = m_AT2Env.get(osWaitForever);
|
||||
msgResult = *((int*) evt.value.p);
|
||||
m_AT2Env.free((int*)evt.value.p);
|
||||
} while(msgResult != AT_TIMEOUT);
|
||||
|
||||
WARN("Command returned no message");
|
||||
WARN("Command \"%s\" returned no message", command);
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
DBG("Command returned with message %d", *msg);
|
||||
|
||||
m_AT2Env.free((int*)evt.value.p);
|
||||
|
||||
if(pResult != NULL)
|
||||
{
|
||||
*pResult = m_transactionResult;
|
||||
}
|
||||
|
||||
int ret = ATResultToReturnCode(m_transactionResult);
|
||||
if(ret != OK)
|
||||
{
|
||||
WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code);
|
||||
WARN("Command \"%s\" returned AT result %d with code %d", command, m_transactionResult.result, m_transactionResult.code);
|
||||
}
|
||||
|
||||
DBG("Command returned successfully");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ATCommandsInterface::tryReadLine()
|
||||
{
|
||||
static bool lineDetected = false;
|
||||
|
||||
//Block on serial read or incoming command
|
||||
DBG("Trying to read a new line from stream");
|
||||
int ret = m_pStream->waitAvailable(); //This can be aborted
|
||||
size_t readLen = 0;
|
||||
if(ret == OK)
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)m_inputBuf + m_inputPos, &readLen, AT_INPUT_BUF_SIZE - 1 - m_inputPos, 0); //Do NOT wait at this point
|
||||
}
|
||||
if(ret == OK)
|
||||
{
|
||||
m_inputPos+=readLen;
|
||||
m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions
|
||||
DBG("In buffer: [%s]", m_inputBuf);
|
||||
}
|
||||
|
||||
if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted
|
||||
{
|
||||
DBG("Read was interrupted");
|
||||
return NET_INTERRUPTED; //0 chars were read
|
||||
}
|
||||
else if(readLen == 0)
|
||||
{
|
||||
DBG("Nothing read");
|
||||
return OK; //0 chars were read
|
||||
}
|
||||
|
||||
DBG("Trying to process incoming line");
|
||||
bool lineProcessed = false;
|
||||
|
||||
do
|
||||
{
|
||||
lineProcessed = false; //Reset flag
|
||||
|
||||
DBG("New iteration");
|
||||
|
||||
//Look for a new line
|
||||
if(!lineDetected)
|
||||
{
|
||||
DBG("No line detected yet");
|
||||
//Try to look for a starting CRLF
|
||||
char* crPtr = strchr(m_inputBuf, CR);
|
||||
/*
|
||||
Different cases at this point:
|
||||
- CRLF%c sequence: this is the start of a line
|
||||
- CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one)
|
||||
- LF: this is the trailing LF char of the previous line, discard
|
||||
- CR / CRLF incomplete sequence: more data is needed to determine which action to take
|
||||
- %c ... CR sequence: this should be the echo of the previous sequence
|
||||
- %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take
|
||||
|
||||
In every case, move mem at the beginning
|
||||
*/
|
||||
if(crPtr != NULL)
|
||||
{
|
||||
DBG("CR char found");
|
||||
|
||||
#if 0
|
||||
//Discard all preceding characters (can do nothing if m_inputBuf == crPtr)
|
||||
memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos
|
||||
#endif
|
||||
|
||||
//If the line starts with CR, this should be a result code
|
||||
if( crPtr == m_inputBuf )
|
||||
{
|
||||
//To determine the sequence we need at least 3 chars
|
||||
if(m_inputPos >= 3)
|
||||
{
|
||||
//Look for a LF char next to the CR char
|
||||
if(m_inputBuf[1] == LF)
|
||||
{
|
||||
//At this point we can check whether this is the end of a preceding line or the beginning of a new one
|
||||
if(m_inputBuf[2] != CR)
|
||||
{
|
||||
DBG("Beginning of new line found");
|
||||
//Beginning of a line
|
||||
lineDetected = true; //Move to next state-machine step
|
||||
}
|
||||
else
|
||||
{
|
||||
//End of an unprocessed line
|
||||
WARN("End of unprocessed line");
|
||||
}
|
||||
//In both cases discard CRLF
|
||||
DBG("Discarding CRLF");
|
||||
memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - 2; //Adjust m_inputPos
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is completely unexpected, discard the CR char to try to recover good state
|
||||
WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]);
|
||||
memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - 1; //Adjust m_inputPos
|
||||
}
|
||||
}
|
||||
}
|
||||
//if the line does NOT begin with CR, this can be an echo of the previous command, process it
|
||||
else
|
||||
{
|
||||
int crPos = crPtr - m_inputBuf;
|
||||
int lfOff = 0; //Offset for LF if present
|
||||
DBG("New line found (possible echo of command)");
|
||||
//This is the end of line
|
||||
//Replace m_inputBuf[crPos] with null-terminating char
|
||||
m_inputBuf[crPos] = '\0';
|
||||
//Check if there is a LF char afterwards
|
||||
if(m_inputPos - crPos >= 1)
|
||||
{
|
||||
if(m_inputBuf[crPos+1] == LF)
|
||||
{
|
||||
lfOff++; //We will discard LF char as well
|
||||
}
|
||||
}
|
||||
//Process line
|
||||
int ret = processReadLine();
|
||||
if(ret)
|
||||
{
|
||||
m_inputPos = 0;
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
lineDetected = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//If sendData has been called, all incoming data has been discarded
|
||||
if(m_inputPos > 0)
|
||||
{
|
||||
memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos
|
||||
}
|
||||
DBG("One line was successfully processed");
|
||||
lineProcessed = true; //Line was processed with success
|
||||
lineDetected = false; //Search now for a new line
|
||||
}
|
||||
}
|
||||
else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it
|
||||
{
|
||||
DBG("Discarding single LF char");
|
||||
memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - 1; //Adjust m_inputPos
|
||||
}
|
||||
}
|
||||
|
||||
//Look for the end of line
|
||||
if(lineDetected)
|
||||
{
|
||||
DBG("Looking for end of line");
|
||||
//Try to look for a terminating CRLF
|
||||
char* crPtr = strchr(m_inputBuf, CR);
|
||||
/*
|
||||
Different cases at this point:
|
||||
- CRLF sequence: this is the end of the line
|
||||
- CR%c sequence : unexpected
|
||||
- CR incomplete sequence: more data is needed to determine which action to take
|
||||
*/
|
||||
|
||||
//Try to look for a '>' (greater than character) that marks an entry prompt
|
||||
char* greaterThanPtr = strchr(m_inputBuf, GD);
|
||||
/*
|
||||
This character must be detected as there is no CRLF sequence at the end of an entry prompt
|
||||
*/
|
||||
|
||||
if(crPtr != NULL)
|
||||
{
|
||||
DBG("CR char found");
|
||||
int crPos = crPtr - m_inputBuf;
|
||||
//To determine the sequence we need at least 2 chars
|
||||
if(m_inputPos - crPos >= 2)
|
||||
{
|
||||
//Look for a LF char next to the CR char
|
||||
if(m_inputBuf[crPos + 1] == LF)
|
||||
{
|
||||
DBG("End of new line found");
|
||||
//This is the end of line
|
||||
//Replace m_inputBuf[crPos] with null-terminating char
|
||||
m_inputBuf[crPos] = '\0';
|
||||
//Process line
|
||||
int ret = processReadLine();
|
||||
if(ret)
|
||||
{
|
||||
m_inputPos = 0;
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
lineDetected = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//If sendData has been called, all incoming data has been discarded
|
||||
if(m_inputPos > 0)
|
||||
{
|
||||
//Shift remaining data to beginning of buffer
|
||||
memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos
|
||||
}
|
||||
|
||||
DBG("One line was successfully processed");
|
||||
lineProcessed = true; //Line was processed with success
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is completely unexpected, discard all chars till the CR char to try to recover good state
|
||||
WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]);
|
||||
memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos
|
||||
}
|
||||
lineDetected = false; //In both case search now for a new line
|
||||
}
|
||||
}
|
||||
else if(greaterThanPtr != NULL)
|
||||
{
|
||||
DBG("> char found");
|
||||
int gdPos = greaterThanPtr - m_inputBuf;
|
||||
//To determine the sequence we need at least 2 chars
|
||||
if(m_inputPos - gdPos >= 2)
|
||||
{
|
||||
//Look for a space char next to the GD char
|
||||
if(m_inputBuf[gdPos + 1] == ' ')
|
||||
{
|
||||
//This is an entry prompt
|
||||
//Replace m_inputBuf[gdPos] with null-terminating char
|
||||
m_inputBuf[gdPos] = '\0';
|
||||
|
||||
//Shift remaining data to beginning of buffer
|
||||
memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
|
||||
|
||||
//Process prompt
|
||||
ret = processEntryPrompt();
|
||||
if(ret)
|
||||
{
|
||||
m_inputPos = 0;
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
lineDetected = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBG("One line was successfully processed");
|
||||
lineProcessed = true; //Line was processed with success
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is completely unexpected, discard all chars till the GD char to try to recover good state
|
||||
WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]);
|
||||
memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
|
||||
m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
|
||||
}
|
||||
lineDetected = false; //In both case search now for a new line
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(lineProcessed); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again
|
||||
|
||||
//If the line could not be processed AND buffer is full, it means that we won't ever be able to process it (buffer too short)
|
||||
if(m_inputPos == AT_INPUT_BUF_SIZE - 1)
|
||||
{
|
||||
//Discard everything
|
||||
m_inputPos = 0;
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
WARN("Incoming buffer is too short to process incoming line");
|
||||
//Look for a new line
|
||||
lineDetected = false;
|
||||
}
|
||||
|
||||
DBG("Processed every full incoming lines");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ATCommandsInterface::trySendCommand()
|
||||
{
|
||||
osEvent evt = m_env2AT.get(0);
|
||||
DBG("status = %d, msg = %d", evt.status, evt.value.p);
|
||||
if(evt.status == osEventMail)
|
||||
{
|
||||
int* msg = (int*) evt.value.p;
|
||||
if( *msg == AT_CMD_READY ) //Command pending
|
||||
{
|
||||
if(m_transactionState != IDLE)
|
||||
{
|
||||
WARN("Previous command not processed!");
|
||||
}
|
||||
DBG("Sending pending command");
|
||||
m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever);
|
||||
char cr = CR;
|
||||
m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator
|
||||
m_transactionState = COMMAND_SENT;
|
||||
}
|
||||
else //Timeout
|
||||
{
|
||||
//Acknowledge
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_TIMEOUT;
|
||||
m_AT2Env.put(msg); //Command has timed out
|
||||
m_transactionState = IDLE; //State-machine reset
|
||||
}
|
||||
m_env2AT.free(msg);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ATCommandsInterface::processReadLine()
|
||||
{
|
||||
DBG("Processing read line [%s]", m_inputBuf);
|
||||
//The line is stored in m_inputBuf
|
||||
if(m_transactionState == COMMAND_SENT)
|
||||
{
|
||||
//If the command has been sent, checks echo to see if it has been received properly
|
||||
if( strcmp(m_transactionCommand, m_inputBuf) == 0 )
|
||||
{
|
||||
DBG("Command echo received");
|
||||
//If so, it means that the following lines will only be solicited results
|
||||
m_transactionState = READING_RESULT;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT)
|
||||
{
|
||||
bool found = false;
|
||||
char* pSemicol = strchr(m_inputBuf, ':');
|
||||
char* pData = NULL;
|
||||
if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
|
||||
{
|
||||
*pSemicol = '\0';
|
||||
pData = pSemicol + 1;
|
||||
if(pData[0]==' ')
|
||||
{
|
||||
pData++; //Suppress whitespace
|
||||
}
|
||||
}
|
||||
//Looks for a unsolicited result code; we can have m_transactionState == COMMAND_SENT as the code may have arrived just before we sent the command
|
||||
m_eventsProcessingMtx.lock();
|
||||
//Go through the list
|
||||
for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
|
||||
{
|
||||
if( m_eventsHandlers[i] != NULL )
|
||||
{
|
||||
if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) )
|
||||
{
|
||||
m_eventsHandlers[i]->onEvent(m_inputBuf, pData);
|
||||
found = true; //Do not break here as there might be multiple handlers for one event type
|
||||
}
|
||||
}
|
||||
}
|
||||
m_eventsProcessingMtx.unlock();
|
||||
if(found)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
if(m_transactionState == READING_RESULT)
|
||||
{
|
||||
//The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s)
|
||||
if(strcmp("OK", m_inputBuf) == 0)
|
||||
{
|
||||
DBG("OK result received");
|
||||
m_transactionResult.code = 0;
|
||||
m_transactionResult.result = ATResult::AT_OK;
|
||||
m_transactionState = IDLE;
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_RESULT_READY;
|
||||
m_AT2Env.put(msg); //Command has been processed
|
||||
return OK;
|
||||
}
|
||||
else if(strcmp("ERROR", m_inputBuf) == 0)
|
||||
{
|
||||
DBG("ERROR result received");
|
||||
m_transactionResult.code = 0;
|
||||
m_transactionResult.result = ATResult::AT_ERROR;
|
||||
m_transactionState = IDLE;
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_RESULT_READY;
|
||||
m_AT2Env.put(msg); //Command has been processed
|
||||
return OK;
|
||||
}
|
||||
else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate
|
||||
{
|
||||
DBG("CONNECT result received");
|
||||
m_transactionResult.code = 0;
|
||||
m_transactionResult.result = ATResult::AT_CONNECT;
|
||||
m_transactionState = IDLE;
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_RESULT_READY;
|
||||
m_AT2Env.put(msg); //Command has been processed
|
||||
return OK;
|
||||
}
|
||||
else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized
|
||||
{
|
||||
DBG("COMMAND NOT SUPPORT result received");
|
||||
m_transactionResult.code = 0;
|
||||
m_transactionResult.result = ATResult::AT_ERROR;
|
||||
m_transactionState = IDLE;
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_RESULT_READY;
|
||||
m_AT2Env.put(msg); //Command has been processed
|
||||
return OK;
|
||||
}
|
||||
else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error
|
||||
{
|
||||
std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
|
||||
DBG("+CME ERROR: %d result received", m_transactionResult.code);
|
||||
m_transactionResult.result = ATResult::AT_CME_ERROR;
|
||||
m_transactionState = IDLE;
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_RESULT_READY;
|
||||
m_AT2Env.put(msg); //Command has been processed
|
||||
return OK;
|
||||
}
|
||||
else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error
|
||||
{
|
||||
std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
|
||||
DBG("+CMS ERROR: %d result received", m_transactionResult.code);
|
||||
m_transactionResult.result = ATResult::AT_CMS_ERROR;
|
||||
m_transactionState = IDLE;
|
||||
int* msg = m_AT2Env.alloc(osWaitForever);
|
||||
*msg = AT_RESULT_READY;
|
||||
m_AT2Env.put(msg); //Command has been processed
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Unprocessed result received: '%s'", m_inputBuf);
|
||||
//Must call transaction processor to complete line processing
|
||||
int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ATCommandsInterface::processEntryPrompt()
|
||||
{
|
||||
DBG("Calling prompt handler");
|
||||
int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called
|
||||
|
||||
if( ret != NET_MOREINFO ) //A new prompt is expected
|
||||
{
|
||||
DBG("Sending break character");
|
||||
//Send CTRL+Z (break sequence) to exit prompt
|
||||
char seq[2] = {BRK, 0x00};
|
||||
sendData(seq);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
//This will be called on initialization & after the execution of a command
|
||||
void ATCommandsInterface::enableEvents()
|
||||
{
|
||||
//Advertize this to events handlers
|
||||
m_eventsMgmtMtx.lock();
|
||||
for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
|
||||
{
|
||||
if( m_eventsHandlers[i] != NULL )
|
||||
{
|
||||
m_eventsHandlers[i]->onDispatchStart();
|
||||
//Enable this kind of events
|
||||
const char* cmd = m_eventsHandlers[i]->getEventsEnableCommand();
|
||||
if(cmd != NULL)
|
||||
{
|
||||
int ret = executeInternal(cmd, this, NULL); //Execute enable command
|
||||
if(ret)
|
||||
{
|
||||
WARN("Events enabling command \"%s\" failed", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_eventsMgmtMtx.unlock();
|
||||
}
|
||||
|
||||
//This will be called on de-initialization & before the execution of a command to prevent unsollicited result codes from polluting the results
|
||||
void ATCommandsInterface::disableEvents()
|
||||
{
|
||||
//Advertize this to events handlers
|
||||
m_eventsMgmtMtx.lock();
|
||||
for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
|
||||
{
|
||||
if( m_eventsHandlers[i] != NULL )
|
||||
{
|
||||
m_eventsHandlers[i]->onDispatchStart();
|
||||
//Disable this kind of events
|
||||
const char* cmd = m_eventsHandlers[i]->getEventsDisableCommand();
|
||||
if(cmd != NULL)
|
||||
{
|
||||
int ret = executeInternal(cmd, this, NULL); //Execute disable command
|
||||
if(ret)
|
||||
{
|
||||
WARN("Events disabling command \"%s\" failed", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_eventsMgmtMtx.unlock();
|
||||
}
|
||||
|
||||
//Commands that can be called during onNewATResponseLine callback, additionally to close()
|
||||
//Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
|
||||
int ATCommandsInterface::sendData(const char* data)
|
||||
{
|
||||
//m_inputBuf is cleared at this point (and MUST therefore be empty)
|
||||
int dataLen = strlen(data);
|
||||
DBG("Sending raw string of length %d", dataLen);
|
||||
int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Could not write to stream (returned %d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dataPos = 0;
|
||||
do
|
||||
{
|
||||
//Read echo
|
||||
size_t readLen;
|
||||
int ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, MIN(dataLen - dataPos, AT_INPUT_BUF_SIZE - 1), osWaitForever); //Make sure we do not read more than needed otherwise it could break the parser
|
||||
if(ret)
|
||||
{
|
||||
WARN("Could not read from stream (returned %d)", ret);
|
||||
m_inputPos = 0; //Reset input buffer state
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
return ret;
|
||||
}
|
||||
|
||||
if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 )
|
||||
{
|
||||
//Echo does not match output
|
||||
m_inputBuf[readLen] = '\0';
|
||||
WARN("Echo does not match output, got '%s' instead", m_inputBuf);
|
||||
m_inputPos = 0; //Reset input buffer state
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
return NET_DIFF;
|
||||
}
|
||||
|
||||
dataPos += readLen;
|
||||
//If all characters have not been read yet
|
||||
|
||||
} while(dataPos < dataLen);
|
||||
|
||||
DBG("String sent successfully");
|
||||
|
||||
m_inputPos = 0; //Reset input buffer state
|
||||
m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*static*/ void ATCommandsInterface::staticCallback(void const* p)
|
||||
{
|
||||
((ATCommandsInterface*)p)->process();
|
||||
}
|
||||
|
||||
int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper
|
||||
{
|
||||
if(result.result == ATResult::AT_OK)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NET_MOREINFO;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ATCommandsInterface::process() //Processing thread
|
||||
{
|
||||
DBG("AT Thread started");
|
||||
while(true)
|
||||
{
|
||||
DBG("AT Processing on hold");
|
||||
m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started
|
||||
|
||||
m_processingMtx.lock();
|
||||
DBG("AT Processing started");
|
||||
//First of all discard buffer
|
||||
int ret;
|
||||
size_t readLen;
|
||||
do //Drop everything
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point
|
||||
} while(ret == OK);
|
||||
m_inputPos = 0; //Clear input buffer
|
||||
do
|
||||
{
|
||||
DBG("Trying to send a pending command");
|
||||
trySendCommand(); //This must be tried first as we discarded the buffer before and therefore would be blocking though there is a pending command
|
||||
DBG("Trying to read a new line");
|
||||
tryReadLine();
|
||||
} while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted
|
||||
m_processingMtx.unlock();
|
||||
DBG("AT Processing stopped");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
/* ATCommandsInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ATCOMMANDSINTERFACE_H_
|
||||
#define ATCOMMANDSINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
#include "rtos.h"
|
||||
|
||||
#define MAX_AT_EVENTS_HANDLERS 4
|
||||
|
||||
class ATCommandsInterface;
|
||||
|
||||
/** Interface implemented by components handling AT events
|
||||
*
|
||||
*/
|
||||
class IATEventsHandler
|
||||
{
|
||||
protected:
|
||||
virtual bool isATCodeHandled(const char* atCode) = 0; //Is this AT code handled
|
||||
virtual void onDispatchStart() = 0;
|
||||
virtual void onDispatchStop() = 0;
|
||||
virtual char* getEventsEnableCommand() = 0;
|
||||
virtual char* getEventsDisableCommand() = 0;
|
||||
virtual void onEvent(const char* atCode, const char* evt) = 0;
|
||||
friend class ATCommandsInterface;
|
||||
};
|
||||
|
||||
/** Interface implemented by components executing complex AT commands
|
||||
*
|
||||
*/
|
||||
class IATCommandsProcessor
|
||||
{
|
||||
protected:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) = 0;
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst) = 0;
|
||||
friend class ATCommandsInterface;
|
||||
};
|
||||
|
||||
#define AT_INPUT_BUF_SIZE 192//64
|
||||
|
||||
//Signals to be sent to the processing thread
|
||||
#define AT_SIG_PROCESSING_START 1
|
||||
#define AT_SIG_PROCESSING_STOP 2
|
||||
//Messages to be sent to the processing thread
|
||||
#define AT_CMD_READY 1
|
||||
#define AT_TIMEOUT 2
|
||||
#define AT_STOP 3
|
||||
//Messages to be sent from the processing thread
|
||||
#define AT_RESULT_READY 1
|
||||
|
||||
/** AT Commands interface class
|
||||
*
|
||||
*/
|
||||
class ATCommandsInterface : protected IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
ATCommandsInterface(IOStream* pStream);
|
||||
|
||||
//Open connection to AT Interface in order to execute command & register/unregister events
|
||||
int open();
|
||||
|
||||
//Initialize AT link
|
||||
int init(bool reset = true);
|
||||
|
||||
//Close connection
|
||||
int close();
|
||||
|
||||
bool isOpen();
|
||||
|
||||
class ATResult
|
||||
{
|
||||
public:
|
||||
enum { AT_OK, AT_ERROR, AT_CONNECT, AT_CMS_ERROR, AT_CME_ERROR } result;
|
||||
int code;
|
||||
};
|
||||
|
||||
int executeSimple(const char* command, ATResult* pResult, uint32_t timeout=1000);
|
||||
int execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000);
|
||||
|
||||
int registerEventsHandler(IATEventsHandler* pHdlr);
|
||||
int deregisterEventsHandler(IATEventsHandler* pHdlr);
|
||||
|
||||
//Commands that can be called during onNewATResponseLine callback, additionally to close()
|
||||
//Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
|
||||
int sendData(const char* data);
|
||||
|
||||
static void staticCallback(void const* p);
|
||||
private:
|
||||
int executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000);
|
||||
|
||||
int tryReadLine();
|
||||
int trySendCommand();
|
||||
int processReadLine();
|
||||
int processEntryPrompt();
|
||||
|
||||
void enableEvents();
|
||||
void disableEvents();
|
||||
|
||||
int ATResultToReturnCode(ATResult result); //Helper
|
||||
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); //Default implementation for simple commands handling
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst); //Default implementation (just sends Ctrl+Z to exit the prompt)
|
||||
|
||||
void process(); //Processing thread
|
||||
|
||||
IOStream* m_pStream;
|
||||
|
||||
bool m_open; //< TRUE when the AT interface is open, and FALSE when it is not.
|
||||
|
||||
const char* m_transactionCommand;
|
||||
const char* m_transactionData;
|
||||
|
||||
IATCommandsProcessor* m_pTransactionProcessor;
|
||||
ATResult m_transactionResult;
|
||||
|
||||
enum { IDLE, COMMAND_SENT, READING_RESULT, ABORTED } m_transactionState;
|
||||
|
||||
char m_inputBuf[AT_INPUT_BUF_SIZE]; // Stores characters received from the modem.
|
||||
int m_inputPos; // Current position of fill pointer in the input buffer.
|
||||
|
||||
Mutex m_transactionMtx;
|
||||
|
||||
// These are RTOS queues, concurrent access protected. In this case both only contain an integer.
|
||||
Mail<int,1> m_env2AT; // used by calling function to inform processing thread of events
|
||||
Mail<int,1> m_AT2Env; // used by processing thread to inform calling function of events
|
||||
|
||||
IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS]; // all registered events handlers
|
||||
|
||||
Mutex m_processingMtx;
|
||||
Thread m_processingThread;
|
||||
|
||||
Mutex m_eventsMgmtMtx; //Lock events use within the calling thread
|
||||
Mutex m_eventsProcessingMtx; //Lock events use within the processing thread
|
||||
};
|
||||
|
||||
#endif /* ATCOMMANDSINTERFACE_H_ */
|
|
@ -1,59 +0,0 @@
|
|||
/* IOStream.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IOSTREAM_H_
|
||||
#define IOSTREAM_H_
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
class IStream
|
||||
{
|
||||
public:
|
||||
//IStream();
|
||||
//virtual ~IStream();
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever) = 0;
|
||||
virtual size_t available() = 0;
|
||||
virtual int waitAvailable(uint32_t timeout=osWaitForever) = 0; //Wait for data to be available
|
||||
virtual int abortRead() = 0; //Abort current reading (or waiting) operation
|
||||
};
|
||||
|
||||
class OStream
|
||||
{
|
||||
public:
|
||||
//OStream();
|
||||
//virtual ~OStream();
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever) = 0;
|
||||
virtual size_t space() = 0;
|
||||
virtual int waitSpace(uint32_t timeout=osWaitForever) = 0; //Wait for space to be available
|
||||
virtual int abortWrite() = 0; //Abort current writing (or waiting) operation
|
||||
};
|
||||
|
||||
class IOStream : public IStream, public OStream
|
||||
{
|
||||
public:
|
||||
//IOStream();
|
||||
//virtual ~IOStream();
|
||||
};
|
||||
|
||||
|
||||
#endif /* IOSTREAM_H_ */
|
|
@ -1,95 +0,0 @@
|
|||
/* MtxCircBuf.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MTXCIRCBUFFER_H
|
||||
#define MTXCIRCBUFFER_H
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
//Mutex protected circualr buffer
|
||||
template<typename T, int size>
|
||||
class MtxCircBuffer
|
||||
{
|
||||
public:
|
||||
MtxCircBuffer() //:
|
||||
//mtx()
|
||||
{
|
||||
write = 0;
|
||||
read = 0;
|
||||
}
|
||||
|
||||
bool isFull()
|
||||
{
|
||||
mtx.lock();
|
||||
bool r = (((write + 1) % size) == read);
|
||||
mtx.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
bool isEmpty()
|
||||
{
|
||||
mtx.lock();
|
||||
bool r = (read == write);
|
||||
mtx.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
void queue(T k)
|
||||
{
|
||||
mtx.lock();
|
||||
buf[write++] = k;
|
||||
write %= size;
|
||||
if (isFull())
|
||||
{
|
||||
read++;
|
||||
read %= size;
|
||||
}
|
||||
mtx.unlock();
|
||||
}
|
||||
|
||||
uint16_t available()
|
||||
{
|
||||
mtx.lock();
|
||||
uint16_t a = (write >= read) ? (write - read) : (size - read + write);
|
||||
mtx.unlock();
|
||||
return a;
|
||||
}
|
||||
|
||||
bool dequeue(T * c)
|
||||
{
|
||||
mtx.lock();
|
||||
bool empty = (read == write);
|
||||
if (!empty)
|
||||
{
|
||||
*c = buf[read++];
|
||||
read %= size;
|
||||
}
|
||||
mtx.unlock();
|
||||
return (!empty);
|
||||
}
|
||||
|
||||
private:
|
||||
volatile uint16_t write;
|
||||
volatile uint16_t read;
|
||||
volatile T buf[size];
|
||||
Mutex mtx;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/* config.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
|
||||
//Configuration
|
||||
#define AT_THREAD_PRIORITY 0
|
||||
|
||||
|
||||
#endif /* CONFIG_H_ */
|
|
@ -1,127 +0,0 @@
|
|||
/* dbg.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dbg.h"
|
||||
|
||||
#include "mbed.h"
|
||||
#include "rtos.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static Serial debug_pc(USBTX, USBRX);
|
||||
|
||||
static char debug_newline[3];
|
||||
|
||||
static void debug_lock(bool set)
|
||||
{
|
||||
static Mutex* mtx = new Mutex(); //Singleton runtime initialisation to avoid static initialisation chaos problems
|
||||
static bool init = false;
|
||||
if(set)
|
||||
{
|
||||
mtx->lock();
|
||||
if(!init)
|
||||
{
|
||||
strncpy( debug_newline, "\n", 2 );
|
||||
printf("[START]\n");
|
||||
fflush(stdout);
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void debug_init()
|
||||
{
|
||||
debug_lock(true); //Force init
|
||||
debug_lock(false);
|
||||
}
|
||||
|
||||
void debug_set_newline(const char* newline)
|
||||
{
|
||||
debug_lock(true);
|
||||
strncpy( debug_newline, newline, 2 );
|
||||
debug_newline[2] = '\0';
|
||||
debug_lock(false);
|
||||
}
|
||||
|
||||
void debug_set_speed(int speed)
|
||||
{
|
||||
debug_pc.baud(speed);
|
||||
}
|
||||
|
||||
void debug(int level, const char* module, int line, const char* fmt, ...)
|
||||
{
|
||||
debug_lock(true);
|
||||
switch(level)
|
||||
{
|
||||
default:
|
||||
case 1:
|
||||
printf("[ERROR]");
|
||||
break;
|
||||
case 2:
|
||||
printf("[WARN]");
|
||||
break;
|
||||
case 3:
|
||||
printf("[INFO]");
|
||||
break;
|
||||
case 4:
|
||||
printf("[DBG]");
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" Module %s - Line %d: ", module, line);
|
||||
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, fmt);
|
||||
vprintf(fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
printf(debug_newline);
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
debug_lock(false);
|
||||
|
||||
}
|
||||
|
||||
void debug_error(const char* module, int line, int ret)
|
||||
{
|
||||
debug_lock(true);
|
||||
printf("[RC] Module %s - Line %d : Error %d\n", module, line, ret);
|
||||
fflush(stdout);
|
||||
debug_lock(false);
|
||||
}
|
||||
|
||||
void debug_exact(const char* fmt, ...)
|
||||
{
|
||||
debug_lock(true);
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, fmt);
|
||||
vprintf(fmt, argp);
|
||||
va_end(argp);
|
||||
debug_lock(false);
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/* dbg.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DBG_H_
|
||||
#define DBG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void debug_init(void);
|
||||
void debug(int level, const char* module, int line, const char* fmt, ...);
|
||||
void debug_set_newline(const char* newline);
|
||||
void debug_set_speed(int speed);
|
||||
void debug_error(const char* module, int line, int ret);
|
||||
void debug_exact(const char* fmt, ...);
|
||||
|
||||
#define DBG_INIT() do{ debug_init(); }while(0)
|
||||
|
||||
#define DBG_SET_NEWLINE( x ) do{ debug_set_newline(x); }while(0)
|
||||
|
||||
#define DBG_SET_SPEED( x ) do{ debug_set_speed(x); }while(0)
|
||||
|
||||
#if __DEBUG__ > 0
|
||||
#ifndef __MODULE__
|
||||
#error "__MODULE__ must be defined"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __DEBUG__ >= 1
|
||||
#define ERR(...) do{ debug(1, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
|
||||
#else
|
||||
#define ERR(...) do{ }while(0)
|
||||
#endif
|
||||
|
||||
#if __DEBUG__ >= 2
|
||||
#define WARN(...) do{ debug(2, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
|
||||
#else
|
||||
#define WARN(...) do{ }while(0)
|
||||
#endif
|
||||
|
||||
#if __DEBUG__ >= 3
|
||||
#define INFO(...) do{ debug(3, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
|
||||
#define CHECK(ret) do{ if(ret){ debug_error(__MODULE__, __LINE__, ret); } }while(0)
|
||||
#else
|
||||
#define INFO(...) do{ }while(0)
|
||||
#define CHECK(ret) do{ }while(0)
|
||||
#endif
|
||||
|
||||
#if __DEBUG__ >= 4
|
||||
#define DBG(...) do{ debug(4, __MODULE__, __LINE__, __VA_ARGS__); }while(0)
|
||||
#define DBGX(...) do{ debug_exact(__VA_ARGS__); }while(0)
|
||||
#else
|
||||
#define DBG(...) do{ }while(0)
|
||||
#define DBGX(...) do{ }while(0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DBG_H_ */
|
|
@ -1,47 +0,0 @@
|
|||
/* errors.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ERRORS_H_
|
||||
#define ERRORS_H_
|
||||
|
||||
/** \page Network-related errors */
|
||||
|
||||
#define OK 0 //No error
|
||||
|
||||
#define NET_FULL 1 //>All available resources are already used
|
||||
#define NET_EMPTY 2 //>No resource
|
||||
#define NET_NOTFOUND 3 //>Element cannot be found
|
||||
#define NET_INVALID 4 //>Invalid
|
||||
#define NET_CONTEXT 5 //>Called in a wrong context (eg during an interrupt)
|
||||
#define NET_TIMEOUT 6 //>Timeout
|
||||
#define NET_UNKNOWN 7 //>Unknown error
|
||||
#define NET_OVERFLOW 8 //>Overflow
|
||||
#define NET_PROCESSING 9 //>Command is processing
|
||||
#define NET_INTERRUPTED 10 //>Current operation has been interrupted
|
||||
#define NET_MOREINFO 11 //>More info on this error can be retrieved elsewhere (eg in a parameter passed as ptr)
|
||||
#define NET_ABORT 12 //>Current operation must be aborted
|
||||
#define NET_DIFF 13 //>Items that should match are different
|
||||
#define NET_AUTH 14 //>Authentication failed
|
||||
#define NET_PROTOCOL 15 //>Protocol error
|
||||
#define NET_OOM 16 //>Out of memory
|
||||
#define NET_CONN 17 //>Connection error
|
||||
#define NET_CLOSED 18 //>Connection was closed by remote end
|
||||
#define NET_TOOSMALL 19 //>Buffer is too small
|
||||
|
||||
#endif /* ERRORS_H_ */
|
|
@ -1,61 +0,0 @@
|
|||
/* fwk.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FWK_H_
|
||||
#define FWK_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "string.h"
|
||||
//using namespace std;
|
||||
|
||||
#include "stdint.h"
|
||||
typedef unsigned int size_t;
|
||||
|
||||
#ifndef __cplusplus
|
||||
//boolean type compatibility
|
||||
typedef byte bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#define CR '\x0D'
|
||||
#define LF '\x0A'
|
||||
#define GD '\x3E'
|
||||
#define BRK '\x1A'
|
||||
|
||||
//Custom utility classes
|
||||
#include "IOStream.h"
|
||||
//#include "String.h"
|
||||
|
||||
//Error codes
|
||||
#include "errors.h"
|
||||
|
||||
//Debug
|
||||
#include "dbg.h"
|
||||
|
||||
//Utility macros
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#define MAX(x,y) (((x)>(y))?(x):(y))
|
||||
|
||||
#endif /* FWK_H_ */
|
|
@ -1,81 +0,0 @@
|
|||
/* IPInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "IPInterface.h"
|
||||
|
||||
#include <cstring> //For strcpy
|
||||
|
||||
|
||||
IPInterface::IPInterface() : m_connected(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ IPInterface::~IPInterface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IPInterface::registerAsDefaultInterface() //First come, first served
|
||||
{
|
||||
s_pDefaultInterface = this;
|
||||
}
|
||||
|
||||
void IPInterface::unregisterAsDefaultInterface() //Must be called before inst is destroyed to avoid invalid ptr fault
|
||||
{
|
||||
s_pDefaultInterface = NULL;
|
||||
}
|
||||
|
||||
/*static*/ IPInterface* IPInterface::getDefaultInterface() //For use by TCP, UDP sockets library
|
||||
{
|
||||
return s_pDefaultInterface;
|
||||
}
|
||||
|
||||
/*static*/ IPInterface* IPInterface::s_pDefaultInterface = NULL;
|
||||
|
||||
|
||||
char* IPInterface::getIPAddress() //Get IP Address as a string ('a.b.c.d')
|
||||
{
|
||||
if(isConnected())
|
||||
{
|
||||
return m_ipAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool IPInterface::isConnected() //Is the interface connected?
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void IPInterface::setIPAddress(char* ipAddr)
|
||||
{
|
||||
std::strcpy(m_ipAddr, ipAddr); //Let's trust the derived class not to buffer overflow us
|
||||
}
|
||||
|
||||
void IPInterface::setConnected(bool connected)
|
||||
{
|
||||
m_connected = connected;
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/* IPInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IPINTERFACE_H_
|
||||
#define IPINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
/** Generic IP-based network interface
|
||||
*
|
||||
*/
|
||||
class IPInterface
|
||||
{
|
||||
public:
|
||||
IPInterface();
|
||||
virtual ~IPInterface();
|
||||
|
||||
//int init(); //Initialize interface; no connection should be performed at this stage
|
||||
virtual int connect() = 0; //Do connect the interface
|
||||
virtual int disconnect() = 0;
|
||||
//It is encouraged that the derived class implement a "setup(...)" function to configure the interface before the connection
|
||||
|
||||
char* getIPAddress(); //Get IP Address as a string ('a.b.c.d')
|
||||
bool isConnected(); //Is the interface connected?
|
||||
|
||||
static IPInterface* getDefaultInterface(); //For use by TCP, UDP sockets library
|
||||
|
||||
//WARN: Implementation will have to be more careful in case of multiple interfaces (or implement a routing protocol based on local IP addresses differentiation)
|
||||
void registerAsDefaultInterface(); //First come, first served
|
||||
void unregisterAsDefaultInterface(); //Must be called before inst is destroyed to avoid invalid ptr fault
|
||||
|
||||
protected:
|
||||
//Must be called by subclasses
|
||||
void setIPAddress(char* ipAddr);
|
||||
void setConnected(bool connected);
|
||||
|
||||
private:
|
||||
char m_ipAddr[16];
|
||||
bool m_connected;
|
||||
|
||||
static IPInterface* s_pDefaultInterface;
|
||||
};
|
||||
|
||||
#endif /* IPINTERFACE_H_ */
|
|
@ -1,52 +0,0 @@
|
|||
/* LwIPInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "LwIPInterface.h"
|
||||
|
||||
extern "C" {
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/tcpip.h"
|
||||
}
|
||||
|
||||
LwIPInterface::LwIPInterface() : IPInterface(), m_rdySphre(1)
|
||||
{
|
||||
m_rdySphre.wait();
|
||||
}
|
||||
|
||||
LwIPInterface::~LwIPInterface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int LwIPInterface::init() //Init LwIP-specific stuff, create the right bindings, etc
|
||||
{
|
||||
//lwip_init(); //All LwIP initialisation functions called on a per-module basis (according to lwipopts.h)
|
||||
tcpip_init(LwIPInterface::tcpipRdyCb, this); //Start TCP/IP processing thread
|
||||
m_rdySphre.wait(); //Wait for callback to produce resource
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*static*/ void LwIPInterface::tcpipRdyCb(void* ctx) //Result of TCP/IP thread launch
|
||||
{
|
||||
LwIPInterface* pIf = (LwIPInterface*) ctx;
|
||||
pIf->m_rdySphre.release();
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/* LwIPInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPINTERFACE_H_
|
||||
#define LWIPINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
#include "IPInterface.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
/** LwIP-based network interface
|
||||
*
|
||||
*/
|
||||
class LwIPInterface : public IPInterface
|
||||
{
|
||||
public:
|
||||
LwIPInterface();
|
||||
virtual ~LwIPInterface();
|
||||
|
||||
int init(); //Init LwIP-specific stuff, create the right bindings, etc
|
||||
|
||||
private:
|
||||
static void tcpipRdyCb(void* ctx); //Result of TCP/IP thread launch
|
||||
Semaphore m_rdySphre;
|
||||
};
|
||||
|
||||
#endif /* LWIPINTERFACE_H_ */
|
|
@ -1,466 +0,0 @@
|
|||
/* PPPIPInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "PPPIPInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
#include "rtos.h"
|
||||
|
||||
#include <cstdio>
|
||||
using std::sscanf;
|
||||
using std::sprintf;
|
||||
|
||||
#include "PPPIPInterface.h"
|
||||
|
||||
#define MSISDN "*99#"
|
||||
|
||||
#define CONNECT_CMD_PREFIX "ATD "
|
||||
#define CONNECT_CMD_SUFFIX "\x0D"
|
||||
#define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
|
||||
#define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
|
||||
#define EXPECTED_RESP_MIN_LEN 20
|
||||
#define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
|
||||
#define ESCAPE_SEQ "+++"
|
||||
#define HANGUP_CMD "ATH" "\x0D"
|
||||
#define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
|
||||
extern "C" {
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include "netif/ppp/ppp.h"
|
||||
}
|
||||
|
||||
PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
|
||||
{
|
||||
m_linkStatusSphre.wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*virtual*/ PPPIPInterface::~PPPIPInterface()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
|
||||
{
|
||||
DBG("Initializing LwIP");
|
||||
LwIPInterface::init(); //Init LwIP, NOT including PPP
|
||||
DBG("Initializing PPP");
|
||||
pppInit();
|
||||
DBG("Done");
|
||||
return OK;
|
||||
}
|
||||
|
||||
int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn)
|
||||
{
|
||||
DBG("Configuring PPP authentication method");
|
||||
pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
|
||||
m_msisdn = msisdn;
|
||||
DBG("Done");
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int PPPIPInterface::connect()
|
||||
{
|
||||
int ret;
|
||||
char cmd[32];
|
||||
int cmdLen;
|
||||
char buf[32];
|
||||
size_t len;
|
||||
DBG("Trying to connect with PPP");
|
||||
|
||||
cleanupLink();
|
||||
|
||||
cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
|
||||
DBG("Sending %s", cmd);
|
||||
ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
size_t readLen;
|
||||
ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
len += readLen;
|
||||
while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) )
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
len += readLen;
|
||||
}
|
||||
|
||||
buf[len]=0;
|
||||
|
||||
DBG("Got %s[len %d]", buf, len);
|
||||
|
||||
int datarate = 0;
|
||||
strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX);
|
||||
if( (sscanf(buf, cmd, &datarate ) != 1))
|
||||
{
|
||||
strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
|
||||
if (strcmp(cmd, buf) != 0)
|
||||
{
|
||||
//Discard buffer
|
||||
do //Clear buf
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
|
||||
} while( (ret == OK) && (len > 0) );
|
||||
return NET_CONN;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("Transport link open");
|
||||
if(datarate != 0)
|
||||
{
|
||||
DBG("Datarate: %d bps", datarate);
|
||||
}
|
||||
m_linkStatusSphre.wait(0);
|
||||
if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected
|
||||
{
|
||||
return NET_INVALID;
|
||||
}
|
||||
|
||||
ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
|
||||
if(ret < 0)
|
||||
{
|
||||
switch(ret)
|
||||
{
|
||||
case PPPERR_OPEN:
|
||||
default:
|
||||
return NET_FULL; //All available resources are already used
|
||||
}
|
||||
}
|
||||
m_pppd = ret; //PPP descriptor
|
||||
m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
|
||||
if(m_pppErrCode != PPPERR_NONE)
|
||||
{
|
||||
m_pppd = -1;
|
||||
}
|
||||
switch(m_pppErrCode)
|
||||
{
|
||||
case PPPERR_NONE: //Connected OK
|
||||
return OK;
|
||||
case PPPERR_CONNECT: //Connection lost
|
||||
return NET_INTERRUPTED;
|
||||
case PPPERR_AUTHFAIL: //Authentication failed
|
||||
return NET_AUTH;
|
||||
case PPPERR_PROTOCOL: //Protocol error
|
||||
return NET_PROTOCOL;
|
||||
default:
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ int PPPIPInterface::disconnect()
|
||||
{
|
||||
int ret = m_linkStatusSphre.wait(0);
|
||||
if(ret > 0) //Already disconnected?
|
||||
{
|
||||
m_pppd = -1; //Discard PPP descriptor
|
||||
switch(m_pppErrCode)
|
||||
{
|
||||
case PPPERR_CONNECT: //Connection terminated
|
||||
case PPPERR_AUTHFAIL: //Authentication failed
|
||||
case PPPERR_PROTOCOL: //Protocol error
|
||||
case PPPERR_USER:
|
||||
return OK;
|
||||
default:
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_pppd == -1)
|
||||
{
|
||||
return NET_INVALID;
|
||||
}
|
||||
pppClose(m_pppd);
|
||||
do
|
||||
{
|
||||
m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
|
||||
DBG("Received PPP err code %d", m_pppErrCode);
|
||||
} while(m_pppErrCode != PPPERR_USER);
|
||||
m_pppd = -1; //Discard PPP descriptor
|
||||
}
|
||||
|
||||
DBG("Sending %s", ESCAPE_SEQ);
|
||||
|
||||
ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
|
||||
cleanupLink();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int PPPIPInterface::cleanupLink()
|
||||
{
|
||||
int ret;
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
do //Clear buf
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
|
||||
if(ret == OK)
|
||||
{
|
||||
buf[len] = '\0';
|
||||
DBG("Got %s", buf);
|
||||
}
|
||||
} while( (ret == OK) && (len > 0) );
|
||||
|
||||
DBG("Sending %s", HANGUP_CMD);
|
||||
|
||||
ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
|
||||
size_t readLen;
|
||||
|
||||
//Hangup
|
||||
DBG("Expect %s", HANGUP_CMD);
|
||||
|
||||
len = 0;
|
||||
while( len < strlen(HANGUP_CMD) )
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100);
|
||||
if( ret != OK )
|
||||
{
|
||||
break;
|
||||
}
|
||||
len += readLen;
|
||||
/////
|
||||
buf[len]=0;
|
||||
DBG("Got %s", buf);
|
||||
}
|
||||
|
||||
buf[len]=0;
|
||||
|
||||
DBG("Got %s[len %d]", buf, len);
|
||||
|
||||
//OK response
|
||||
DBG("Expect %s", OK_RESP);
|
||||
|
||||
len = 0;
|
||||
while( len < strlen(OK_RESP) )
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100);
|
||||
if( ret != OK )
|
||||
{
|
||||
break;
|
||||
}
|
||||
len += readLen;
|
||||
/////
|
||||
buf[len]=0;
|
||||
DBG("Got %s", buf);
|
||||
}
|
||||
|
||||
buf[len]=0;
|
||||
|
||||
DBG("Got %s[len %d]", buf, len);
|
||||
|
||||
//NO CARRIER event
|
||||
DBG("Expect %s", NO_CARRIER_RESP);
|
||||
|
||||
len = 0;
|
||||
while( len < strlen(NO_CARRIER_RESP) )
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100);
|
||||
if( ret != OK )
|
||||
{
|
||||
break;
|
||||
}
|
||||
len += readLen;
|
||||
/////
|
||||
buf[len]=0;
|
||||
DBG("Got %s", buf);
|
||||
}
|
||||
|
||||
buf[len]=0;
|
||||
|
||||
DBG("Got %s[len %d]", buf, len);
|
||||
|
||||
do //Clear buf
|
||||
{
|
||||
ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
|
||||
if(ret == OK)
|
||||
{
|
||||
buf[len] = '\0';
|
||||
DBG("Got %s", buf);
|
||||
}
|
||||
} while( (ret == OK) && (len > 0) );
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
|
||||
{
|
||||
PPPIPInterface* pIf = (PPPIPInterface*)ctx;
|
||||
struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
|
||||
|
||||
switch(errCode)
|
||||
{
|
||||
case PPPERR_NONE:
|
||||
WARN("Connected via PPP.");
|
||||
DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
|
||||
DBG("Netmask: %s", inet_ntoa(addrs->netmask));
|
||||
DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
|
||||
DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
|
||||
DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
|
||||
//Setup DNS
|
||||
if (addrs->dns1.addr != 0)
|
||||
{
|
||||
dns_setserver(0, (struct ip_addr*)&(addrs->dns1));
|
||||
}
|
||||
if (addrs->dns2.addr != 0)
|
||||
{
|
||||
dns_setserver(1, (struct ip_addr*)&(addrs->dns1));
|
||||
}
|
||||
|
||||
pIf->setConnected(true);
|
||||
pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr));
|
||||
break;
|
||||
case PPPERR_CONNECT: //Connection lost
|
||||
WARN("Connection lost/terminated");
|
||||
pIf->setConnected(false);
|
||||
break;
|
||||
case PPPERR_AUTHFAIL: //Authentication failed
|
||||
WARN("Authentication failed");
|
||||
pIf->setConnected(false);
|
||||
break;
|
||||
case PPPERR_PROTOCOL: //Protocol error
|
||||
WARN("Protocol error");
|
||||
pIf->setConnected(false);
|
||||
break;
|
||||
case PPPERR_USER:
|
||||
WARN("Disconnected by user");
|
||||
pIf->setConnected(false);
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown error (%d)", errCode);
|
||||
pIf->setConnected(false);
|
||||
break;
|
||||
}
|
||||
|
||||
pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
|
||||
pIf->m_pppErrCode = errCode;
|
||||
pIf->m_linkStatusSphre.release();
|
||||
}
|
||||
|
||||
//LwIP PPP implementation
|
||||
extern "C"
|
||||
{
|
||||
|
||||
/**
|
||||
* Writes to the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data to send
|
||||
* @param len length (in bytes) of data to send
|
||||
* @return number of bytes actually sent
|
||||
*
|
||||
* @note This function will block until all data can be sent.
|
||||
*/
|
||||
u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
|
||||
{
|
||||
DBG("sio_write");
|
||||
PPPIPInterface* pIf = (PPPIPInterface*)fd;
|
||||
int ret;
|
||||
if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
|
||||
if(ret != OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data buffer for receiving
|
||||
* @param len maximum length (in bytes) of data to receive
|
||||
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
|
||||
*
|
||||
* @note This function will block until data can be received. The blocking
|
||||
* can be cancelled by calling sio_read_abort().
|
||||
*/
|
||||
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
|
||||
{
|
||||
DBG("sio_read");
|
||||
PPPIPInterface* pIf = (PPPIPInterface*)fd;
|
||||
int ret;
|
||||
size_t readLen;
|
||||
if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
|
||||
{
|
||||
WARN("EXIT NOT AVAIL");
|
||||
return 0;
|
||||
}
|
||||
ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
|
||||
if(ret != OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
DBG("ret");
|
||||
return readLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts a blocking sio_read() call.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
*/
|
||||
void sio_read_abort(sio_fd_t fd)
|
||||
{
|
||||
DBG("sio_read_abort");
|
||||
PPPIPInterface* pIf = (PPPIPInterface*)fd;
|
||||
if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
|
||||
{
|
||||
return;
|
||||
}
|
||||
pIf->m_pStream->abortRead();
|
||||
DBG("ret");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/* PPPIPInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PPPIPINTERFACE_H_
|
||||
#define PPPIPINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "LwIPInterface.h"
|
||||
|
||||
#include "lwip/sio.h"
|
||||
|
||||
namespace rtos {
|
||||
class Semaphore;
|
||||
}
|
||||
using namespace rtos;
|
||||
|
||||
#define DEFAULT_MSISDN_GSM "*99#"
|
||||
#define DEFAULT_MSISDN_CDMA "#777"
|
||||
|
||||
/** Interface using PPP to connect to an IP-based network
|
||||
*
|
||||
*/
|
||||
class PPPIPInterface : public LwIPInterface
|
||||
{
|
||||
public:
|
||||
PPPIPInterface(IOStream* pStream);
|
||||
virtual ~PPPIPInterface();
|
||||
|
||||
int init(); //Init PPP-specific stuff, create the right bindings, etc
|
||||
int setup(const char* user, const char* pw, const char* msisdn); //Setup authentication
|
||||
virtual int connect();
|
||||
virtual int disconnect();
|
||||
|
||||
private:
|
||||
int cleanupLink();
|
||||
|
||||
static void linkStatusCb(void *ctx, int errCode, void *arg); //PPP link status
|
||||
Semaphore m_linkStatusSphre;
|
||||
int m_pppErrCode;
|
||||
|
||||
IOStream* m_pStream; //Serial stream
|
||||
bool m_streamAvail;
|
||||
const char* m_msisdn;
|
||||
|
||||
int m_pppd;
|
||||
|
||||
friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
friend void sio_read_abort(sio_fd_t fd);
|
||||
};
|
||||
|
||||
#endif /* PPPIPINTERFACE_H_ */
|
|
@ -1,175 +0,0 @@
|
|||
/* LinkMonitor.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "LinkMonitor.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "LinkMonitor.h"
|
||||
|
||||
#include <cstdio>
|
||||
using std::sscanf;
|
||||
|
||||
#define DEFAULT_TIMEOUT 10000
|
||||
|
||||
LinkMonitor::LinkMonitor(ATCommandsInterface* pIf) : m_pIf(pIf), m_rssi(0), m_registrationState(REGISTRATION_STATE_UNKNOWN), m_bearer(BEARER_UNKNOWN)
|
||||
{
|
||||
m_gsm = true;
|
||||
}
|
||||
|
||||
int LinkMonitor::init(bool gsm)
|
||||
{
|
||||
m_gsm = gsm;
|
||||
if (m_gsm)
|
||||
{
|
||||
// we need to make sure that we setup the operator selection to be in 'numeric' format.
|
||||
// i.e. it is made up of a network and country code when returned by the modem e.g. Operator = 23415. This allows easy logic parsing for
|
||||
// setting up other network parameters in future.
|
||||
DBG("LinkMonitor::init() being called. This should only happen once: executinging AT+COPS=0,2");
|
||||
int ret = m_pIf->executeSimple("AT+COPS=0,2", NULL, DEFAULT_TIMEOUT); //Configure to set the operator string to Country Code and mobile network code
|
||||
if(ret != OK)
|
||||
{
|
||||
WARN(" NET_PROTOCOL error from sending the AT+COPS command to the modem. ");
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int LinkMonitor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
DBG("Line is %s", line);
|
||||
char n[32] = "";
|
||||
char s[32] = "";
|
||||
int v;
|
||||
if( sscanf(line, "+CREG: %*d,%d", &v) >= 1 ) //Reg state is valid
|
||||
{
|
||||
DBG("+CREG %d", v);
|
||||
switch( v )
|
||||
{
|
||||
case 0:
|
||||
m_registrationState = REGISTRATION_STATE_UNKNOWN;
|
||||
break;
|
||||
case 1:
|
||||
m_registrationState = REGISTRATION_STATE_HOME_NETWORK;
|
||||
break;
|
||||
case 2:
|
||||
m_registrationState = REGISTRATION_STATE_REGISTERING;
|
||||
break;
|
||||
case 3:
|
||||
m_registrationState = REGISTRATION_STATE_DENIED;
|
||||
break;
|
||||
case 4:
|
||||
m_registrationState = REGISTRATION_STATE_NO_SIGNAL;
|
||||
break;
|
||||
case 5:
|
||||
m_registrationState = REGISTRATION_STATE_ROAMING;
|
||||
break;
|
||||
default:
|
||||
m_registrationState = REGISTRATION_STATE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( sscanf(line, "+COPS: %*d,%*d,\"%*[^\"]\",%d", &v) >= 1 )
|
||||
{
|
||||
DBG("+COPS %d", v);
|
||||
switch( v )
|
||||
{
|
||||
case 0:
|
||||
m_bearer = BEARER_GSM;
|
||||
break;
|
||||
case 2:
|
||||
m_bearer = BEARER_UMTS;
|
||||
break;
|
||||
case 3:
|
||||
m_bearer = BEARER_EDGE;
|
||||
break;
|
||||
case 4: //HSDPA
|
||||
case 5: //HSUPA
|
||||
case 6: //HSDPA + HSUPA
|
||||
m_bearer = BEARER_HSPA;
|
||||
break;
|
||||
case 7:
|
||||
m_bearer = BEARER_LTE;
|
||||
break;
|
||||
case 1: //GSM Compact
|
||||
default:
|
||||
m_bearer = BEARER_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( sscanf(line, "+CSQ: %d,%*d", &v) >= 1 )
|
||||
{
|
||||
DBG("+CSQ %d", v);
|
||||
if(v == 99) //Unknown
|
||||
{
|
||||
m_rssi = 0; //Unknown
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rssi = -113 + 2*v;
|
||||
}
|
||||
}
|
||||
else if ( (sscanf(line, "+CNUM: \"%[^\"]\",\"%[^\"]\",%d", n, s, &v) == 3) ||
|
||||
(sscanf(line, "+CNUM: \"\",\"%[^\"]\",%d", s, &v) == 2) )
|
||||
{
|
||||
if (*s && ((v == 145/*number includes + */) || (v == 129/*otherwise*/))) {
|
||||
strcpy(m_phoneNumber, s);
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int LinkMonitor::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
int LinkMonitor::getState(int* pRssi, REGISTRATION_STATE* pRegistrationState, BEARER* pBearer)
|
||||
{
|
||||
m_rssi = 0;
|
||||
m_registrationState = REGISTRATION_STATE_UNKNOWN;
|
||||
m_bearer = BEARER_UNKNOWN;
|
||||
int ret = m_pIf->execute(m_gsm ? "AT+CREG?;+COPS?;+CSQ" : "AT+CREG?;+CSQ", this, NULL, DEFAULT_TIMEOUT); //Configure to get registration info & get it; get signal quality
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
*pRssi = m_rssi;
|
||||
*pRegistrationState = m_registrationState;
|
||||
*pBearer = m_bearer;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int LinkMonitor::getPhoneNumber(char* phoneNumber)
|
||||
{
|
||||
*m_phoneNumber = '\0';
|
||||
if (m_gsm) {
|
||||
int ret = m_pIf->execute("AT+CNUM", this, NULL, DEFAULT_TIMEOUT);
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
}
|
||||
strcpy(phoneNumber, m_phoneNumber);
|
||||
return OK;
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/* LinkMonitor.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LINKMONITOR_H_
|
||||
#define LINKMONITOR_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
/** Component to monitor link quality
|
||||
*
|
||||
*/
|
||||
class LinkMonitor : protected IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
/** Create LinkMonitor instance
|
||||
@param pIf Pointer to the ATCommandsInterface instance to use
|
||||
*/
|
||||
LinkMonitor(ATCommandsInterface* pIf);
|
||||
|
||||
/** Initialize monitor
|
||||
*/
|
||||
int init(bool gsm = true);
|
||||
|
||||
/** Registration State
|
||||
*/
|
||||
enum REGISTRATION_STATE
|
||||
{
|
||||
REGISTRATION_STATE_UNKNOWN, //!< Unknown
|
||||
REGISTRATION_STATE_REGISTERING, //!< Registering
|
||||
REGISTRATION_STATE_DENIED, //!< Denied
|
||||
REGISTRATION_STATE_NO_SIGNAL, //!< No Signal
|
||||
REGISTRATION_STATE_HOME_NETWORK, //!< Registered on home network
|
||||
REGISTRATION_STATE_ROAMING //!< Registered on roaming network
|
||||
};
|
||||
|
||||
/** Bearer type
|
||||
*/
|
||||
enum BEARER
|
||||
{
|
||||
BEARER_UNKNOWN, //!< Unknown
|
||||
BEARER_GSM, //!< GSM (2G)
|
||||
BEARER_EDGE, //!< EDGE (2.5G)
|
||||
BEARER_UMTS, //!< UMTS (3G)
|
||||
BEARER_HSPA, //!< HSPA (3G+)
|
||||
BEARER_LTE //!< LTE (4G)
|
||||
};
|
||||
|
||||
/** Get link state
|
||||
@param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
|
||||
@param pRegistrationState pointer to store the current registration state
|
||||
@param pBearer pointer to store the current bearer
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int getState(int* pRssi, REGISTRATION_STATE* pRegistrationState, BEARER* pBearer);
|
||||
|
||||
/** Get my phone number
|
||||
@param phoneNumber pointer to store the current phoneNumber
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int getPhoneNumber(char* phoneNumber);
|
||||
protected:
|
||||
//IATCommandsProcessor
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
|
||||
|
||||
private:
|
||||
ATCommandsInterface* m_pIf;
|
||||
|
||||
int m_rssi;
|
||||
bool m_gsm;
|
||||
REGISTRATION_STATE m_registrationState;
|
||||
BEARER m_bearer;
|
||||
char m_phoneNumber[16];
|
||||
};
|
||||
|
||||
#endif /* LINKMONITOR_H_ */
|
|
@ -1,26 +0,0 @@
|
|||
/* lwipopts.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPOPTS_CONF_H_
|
||||
#define LWIPOPTS_CONF_H_
|
||||
|
||||
#define LWIP_TRANSPORT_PPP 1
|
||||
|
||||
#endif /* LWIPOPTS_CONF_H_ */
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
/* CDMASMSInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "CDMASMSInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "CDMASMSInterface.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
using std::sscanf;
|
||||
|
||||
#define DEFAULT_TIMEOUT 10000
|
||||
|
||||
CDMASMSInterface::CDMASMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
int CDMASMSInterface::init()
|
||||
{
|
||||
m_state = SMS_IDLE;
|
||||
|
||||
DBG("Get number of messages in the different inboxes");
|
||||
int ret = updateInbox();
|
||||
if(ret)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("Initialization done");
|
||||
return OK;
|
||||
}
|
||||
|
||||
int CDMASMSInterface::send(const char* number, const char* message)
|
||||
{
|
||||
if( strlen(number) > 16 )
|
||||
{
|
||||
return NET_INVALID; //Number too long
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
//Prepare infos
|
||||
m_state = SMS_SEND_CMD_SENT;
|
||||
|
||||
bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US)
|
||||
|
||||
DBG("Send SM");
|
||||
//Send command
|
||||
char cmd[32+strlen(message)];
|
||||
std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority
|
||||
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
|
||||
if(ret != OK)
|
||||
{
|
||||
WARN("ret %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("Check status");
|
||||
m_txState = SMS_PENDING;
|
||||
|
||||
int tries = 10;
|
||||
while(tries--)
|
||||
{
|
||||
m_state = SMS_GET_TX_STATUS_CMD_SENT;
|
||||
ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT);
|
||||
if(ret)
|
||||
{
|
||||
m_state = SMS_IDLE;
|
||||
return ret;
|
||||
}
|
||||
m_state = SMS_IDLE;
|
||||
if(m_txState == SMS_PENDING) //Wait more
|
||||
{
|
||||
Thread::wait(1000);
|
||||
continue;
|
||||
}
|
||||
else if(m_txState == SMS_FAILED)
|
||||
{
|
||||
ERR("The modem could not send the SM");
|
||||
return NET_CONN; //Probably a conenction issue, the user can retry
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!tries)
|
||||
{
|
||||
ERR("The is still trying to send the SM");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int CDMASMSInterface::get(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
if( maxLength < 1 )
|
||||
{
|
||||
return NET_INVALID; //Buffer too short
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
DBG("Get next message");
|
||||
if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
|
||||
{
|
||||
DBG("Message list count is 0 and needs updating. Running updateInbox.");
|
||||
ret = updateInbox();
|
||||
if (ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
|
||||
{
|
||||
DBG("Message list count is 0");
|
||||
return NET_EMPTY; //No message to read
|
||||
}
|
||||
|
||||
//Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular)
|
||||
int index;
|
||||
if(m_msgInListsCount[2])
|
||||
{
|
||||
index = 3;
|
||||
}
|
||||
else if(m_msgInListsCount[0])
|
||||
{
|
||||
index = 1;
|
||||
}
|
||||
else //if(m_msgInListsCount[1])
|
||||
{
|
||||
index = 2;
|
||||
}
|
||||
|
||||
//Prepare infos
|
||||
m_state = SMS_GET_CMD_SENT;
|
||||
m_msisdn = (char*) number;
|
||||
m_msg = (char*) message;
|
||||
m_maxMsgLength = maxLength;
|
||||
m_headersToRead = 3;
|
||||
|
||||
m_msisdn[0] = '\0';
|
||||
|
||||
DBG("Get SMS");
|
||||
//Read command
|
||||
char cmd[32];
|
||||
std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message
|
||||
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT!GSMS returned %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
//If message is not read, it will be put at the end of the read list
|
||||
int item;
|
||||
if( index != 3 )
|
||||
{
|
||||
//Decrement count in relevant list
|
||||
m_msgInListsCount[index-1]--;
|
||||
//Increment count in read list
|
||||
m_msgInListsCount[3-1]++;
|
||||
item = m_msgInListsCount[3-1];
|
||||
//Normally item should be equal to 1 as we'd have read any older messages first
|
||||
if( item != 1 )
|
||||
{
|
||||
WARN("Still some older messages pending in the read inbox");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//The item is still the oldest one
|
||||
item = 1;
|
||||
}
|
||||
|
||||
DBG("Deleting message");
|
||||
//Delete message from inbox
|
||||
std::sprintf(cmd, "AT!DSMS=3"/*,%d", item*/); //FIXME why doesn't that work when specifying the index??
|
||||
ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
|
||||
if(ret != OK)
|
||||
{
|
||||
ERR("Could not delete message");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Now we can decrease the number of read messages
|
||||
m_msgInListsCount[3-1]--;
|
||||
}
|
||||
|
||||
if (m_state != SMS_CMD_PROCESSED)
|
||||
{
|
||||
WARN("Message could not be retrieved properly");
|
||||
m_state = SMS_IDLE;
|
||||
return NET_EMPTY;
|
||||
}
|
||||
|
||||
m_state = SMS_IDLE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int CDMASMSInterface::getCount(size_t* pCount)
|
||||
{
|
||||
int ret = updateInbox();
|
||||
if(ret)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
*pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ int CDMASMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
if(m_state == SMS_SEND_CMD_SENT)
|
||||
{
|
||||
DBG("SMS Send: %s", line);
|
||||
}
|
||||
else if(m_state == SMS_GET_TX_STATUS_CMD_SENT)
|
||||
{
|
||||
if(!strcmp(line, "sent"))
|
||||
{
|
||||
m_txState = SMS_SENT;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(!strcmp(line, "failed"))
|
||||
{
|
||||
m_txState = SMS_FAILED;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(!strcmp(line, "none"))
|
||||
{
|
||||
m_txState = SMS_NONE;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(!strcmp(line, "pending"))
|
||||
{
|
||||
m_txState = SMS_PENDING;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_CMD_SENT)
|
||||
{
|
||||
DBG("Header: %s", line);
|
||||
|
||||
if(m_msisdn[0]=='\0')
|
||||
{
|
||||
sscanf(line, "From: %16s", m_msisdn);
|
||||
}
|
||||
|
||||
m_headersToRead--;
|
||||
|
||||
if(m_headersToRead==0) //End of headers
|
||||
{
|
||||
if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved
|
||||
{
|
||||
m_state = SMS_GET_HDR_RECEIVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = SMS_IDLE; //Error, signal it
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_HDR_RECEIVED)
|
||||
{
|
||||
DBG("Message: %s", line);
|
||||
size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
|
||||
std::memcpy( m_msg, line, cpyLen );
|
||||
m_msg[cpyLen] = '\0';
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(m_state == SMS_GET_COUNT_CMD_SENT)
|
||||
{
|
||||
DBG("Inbox: %s", line);
|
||||
int index;
|
||||
size_t count;
|
||||
if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2)
|
||||
{
|
||||
if((index > 0) && (index <=4))
|
||||
{
|
||||
m_msgInListsCount[index-1] = count;
|
||||
}
|
||||
if(index == 4)
|
||||
{
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int CDMASMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int CDMASMSInterface::updateInbox()
|
||||
{
|
||||
//Get number of unread/read messages
|
||||
|
||||
DBG("Updating inbox");
|
||||
m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts
|
||||
|
||||
//Get counts
|
||||
m_state = SMS_GET_COUNT_CMD_SENT;
|
||||
int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT!CNTSMS returned %d", ret);
|
||||
m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/* SMSInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef CDMASMSINTERFACE_H_
|
||||
#define CDMASMSINTERFACE_H_
|
||||
|
||||
#include "SMSInterface.h"
|
||||
|
||||
#define MAX_SM 8
|
||||
|
||||
/** Component to use the Short Messages Service (SMS)
|
||||
*
|
||||
*/
|
||||
class CDMASMSInterface : public ISMSInterface, protected IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
/** Create SMSInterface instance
|
||||
@param pIf Pointer to the ATCommandsInterface instance to use
|
||||
*/
|
||||
CDMASMSInterface(ATCommandsInterface* pIf);
|
||||
|
||||
/** Initialize interface
|
||||
Configure SMS commands & register for SMS-related unsolicited result codes
|
||||
*/
|
||||
virtual int init();
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int send(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int get(char* number, char* message, size_t maxLength);
|
||||
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getCount(size_t* pCount);
|
||||
|
||||
protected:
|
||||
//IATCommandsProcessor
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
|
||||
|
||||
int updateInbox(); //Update messages count in the different inboxes
|
||||
|
||||
private:
|
||||
ATCommandsInterface* m_pIf;
|
||||
|
||||
//Current message
|
||||
char* m_msg;
|
||||
size_t m_maxMsgLength;
|
||||
char* m_msisdn;
|
||||
|
||||
//Messages list
|
||||
size_t m_msgInListsCount[4]; //4 lists
|
||||
|
||||
size_t m_headersToRead;
|
||||
|
||||
enum { SMS_NONE, SMS_SENT, SMS_PENDING, SMS_FAILED } m_txState;
|
||||
enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_TX_STATUS_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_CMD_PROCESSED } m_state;
|
||||
};
|
||||
|
||||
#endif /* CDMASMSINTERFACE_H_ */
|
|
@ -1,423 +0,0 @@
|
|||
/* GSMSMSInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 2
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "GSMSMSInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "GSMSMSInterface.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define DEFAULT_TIMEOUT 10000
|
||||
|
||||
GSMSMSInterface::GSMSMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
|
||||
{
|
||||
m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
|
||||
}
|
||||
|
||||
int GSMSMSInterface::init()
|
||||
{
|
||||
m_msgRefListCount = 0;
|
||||
m_needsUpdate = true;
|
||||
m_state = SMS_IDLE;
|
||||
|
||||
DBG("Set format");
|
||||
//Set Text mode format
|
||||
int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("Setup new messages indication");
|
||||
//Setup new messages indication
|
||||
ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("Try to fetch inbox");
|
||||
m_inboxMtx.lock();
|
||||
if( m_needsUpdate )
|
||||
{
|
||||
ret = updateInbox(); //Fetch existing messages references
|
||||
if(ret)
|
||||
{
|
||||
m_inboxMtx.unlock();
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
}
|
||||
m_inboxMtx.unlock();
|
||||
|
||||
DBG("Initialization done");
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GSMSMSInterface::send(const char* number, const char* message)
|
||||
{
|
||||
if( strlen(number) > 16 )
|
||||
{
|
||||
return NET_INVALID; //Number too long to match 3GPP spec
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
//Prepare infos
|
||||
m_state = SMS_SEND_CMD_SENT;
|
||||
m_msg = (char*) message;
|
||||
|
||||
DBG("Send SM");
|
||||
//Send command
|
||||
char cmd[32];
|
||||
std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
|
||||
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
|
||||
if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
|
||||
{
|
||||
WARN("ret %d, state %d", ret, m_state);
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("SM sent");
|
||||
m_state = SMS_IDLE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int GSMSMSInterface::get(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
if( maxLength < 1 )
|
||||
{
|
||||
return NET_INVALID; //Buffer too short
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
DBG("Get next message");
|
||||
m_inboxMtx.lock();
|
||||
if( ((m_msgRefListCount == 0) && m_needsUpdate) || ((m_msgRefListCount > 0) && (m_msgRefList[0] == -1)) )
|
||||
{
|
||||
DBG("Message list count is 0 and needs updating or next index is unknown, calling updateInbox()");
|
||||
ret = updateInbox();
|
||||
|
||||
if (ret)
|
||||
{
|
||||
m_inboxMtx.unlock();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("%d messages to read", m_msgRefListCount);
|
||||
|
||||
if(m_msgRefListCount == 0)
|
||||
{
|
||||
m_inboxMtx.unlock();
|
||||
DBG("Message list count is 0, I think it's empty and returning.");
|
||||
return NET_EMPTY; //No message to read
|
||||
}
|
||||
|
||||
//Prepare infos
|
||||
m_state = SMS_GET_CMD_SENT;
|
||||
m_msisdn = (char*) number;
|
||||
m_msg = (char*) message;
|
||||
m_maxMsgLength = maxLength;
|
||||
|
||||
DBG("Get SMS");
|
||||
//List command
|
||||
char cmd[32];
|
||||
std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
|
||||
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT+CMGR returned %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
m_inboxMtx.unlock();
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
if (m_state != SMS_CMD_PROCESSED)
|
||||
{
|
||||
WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
|
||||
}
|
||||
|
||||
DBG("Deleting message from index number: %d", m_msgRefList[0] );
|
||||
//Delete message from outbox
|
||||
std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
|
||||
ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
|
||||
if(ret != OK)
|
||||
{
|
||||
ERR("Could not delete message");
|
||||
}
|
||||
//Remove message from list
|
||||
std::memmove(&m_msgRefList[0], &m_msgRefList[1], MIN(m_msgRefListCount-1,MAX_SM-1)*sizeof(m_msgRefList[0]));
|
||||
m_msgRefListCount--;
|
||||
|
||||
if(m_msgRefListCount > MAX_SM - 1) //Last message index is unknown, so put -1 to tell the lib to fetch it when needed
|
||||
{
|
||||
DBG("Last message index is unknown, will need to be updated");
|
||||
m_msgRefList[MAX_SM - 1] = -1;
|
||||
}
|
||||
|
||||
DBG("%d messages to read", m_msgRefListCount);
|
||||
|
||||
if (m_state != SMS_CMD_PROCESSED)
|
||||
{
|
||||
m_state = SMS_IDLE;
|
||||
m_inboxMtx.unlock();
|
||||
return NET_EMPTY;
|
||||
}
|
||||
|
||||
m_state = SMS_IDLE;
|
||||
m_inboxMtx.unlock();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int GSMSMSInterface::getCount(size_t* pCount)
|
||||
{
|
||||
int ret;
|
||||
|
||||
m_inboxMtx.lock();
|
||||
if( m_needsUpdate )
|
||||
{
|
||||
ret = updateInbox();
|
||||
if(ret)
|
||||
{
|
||||
m_inboxMtx.unlock();
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
*pCount = m_msgRefListCount;
|
||||
m_inboxMtx.unlock();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
if(m_state == SMS_SEND_CMD_SENT)
|
||||
{
|
||||
if( std::sscanf(line, "+CMGS: %*d") == 0 )
|
||||
{
|
||||
DBG("SM sent");
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_CMD_SENT)
|
||||
{
|
||||
DBG("Header: %s", line);
|
||||
if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
|
||||
{
|
||||
m_state = SMS_GET_HDR_RECEIVED;
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_HDR_RECEIVED)
|
||||
{
|
||||
DBG("Message: %s", line);
|
||||
size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
|
||||
std::memcpy( m_msg, line, cpyLen );
|
||||
m_msg[cpyLen] = '\0';
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(m_state == SMS_GET_COUNT_CMD_SENT)
|
||||
{
|
||||
DBG("Header: %s", line);
|
||||
int msgRef;
|
||||
if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages
|
||||
{
|
||||
m_state = SMS_GET_COUNT_HDR_RECEIVED;
|
||||
//Add message to list
|
||||
if(m_msgRefListCount < MAX_SM)
|
||||
{
|
||||
m_msgRefList[m_msgRefListCount] = msgRef;
|
||||
}
|
||||
m_msgRefListCount++; //Always count message
|
||||
DBG("m_msgRefListCount=%d",m_msgRefListCount);
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
|
||||
{
|
||||
DBG("Message (debug only): %s", line); //For debug only
|
||||
m_state = SMS_GET_COUNT_CMD_SENT;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int GSMSMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
if(m_state == SMS_SEND_CMD_SENT)
|
||||
{
|
||||
char* crPtr = strchr(m_msg, CR);
|
||||
if(crPtr != NULL)
|
||||
{
|
||||
int crPos = crPtr - m_msg;
|
||||
//Replace m_inputBuf[crPos] with null-terminating char
|
||||
m_msg[crPos] = '\x0';
|
||||
|
||||
//If there is a CR char, split message there
|
||||
|
||||
//Do print the message
|
||||
int ret = pInst->sendData(m_msg);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
char cr[2] = {CR, '\0'};
|
||||
ret = pInst->sendData(cr);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
m_msg += crPos;
|
||||
|
||||
if(m_msg[0] == LF)
|
||||
{
|
||||
m_msg++; //Discard LF char as well
|
||||
}
|
||||
|
||||
return NET_MOREINFO;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Do print the message
|
||||
pInst->sendData(m_msg);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ bool GSMSMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
|
||||
{
|
||||
DBG("AT code is %s", atCode);
|
||||
if( strcmp("+CMTI", atCode) == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DBG("Not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ void GSMSMSInterface::onDispatchStart()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ void GSMSMSInterface::onDispatchStop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
|
||||
{
|
||||
return "AT+CNMI=2,1,0,0,0";
|
||||
}
|
||||
|
||||
/*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
|
||||
{
|
||||
return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
|
||||
}
|
||||
|
||||
/*virtual*/ void GSMSMSInterface::onEvent(const char* atCode, const char* evt)
|
||||
{
|
||||
if( strcmp("+CMTI", atCode) != 0 )
|
||||
{
|
||||
return; //Not supported
|
||||
}
|
||||
|
||||
DBG("Unsollicited result code: %s - %s", atCode, evt);
|
||||
|
||||
//Get index
|
||||
int msgRef;
|
||||
if(( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) ||
|
||||
( std::sscanf(evt, "\"ME\",%d", &msgRef) == 1 ))
|
||||
{
|
||||
DBG("Adding message to list (ref %d)", msgRef);
|
||||
if(m_inboxMtx.trylock())
|
||||
{
|
||||
//Add message to list
|
||||
if(m_msgRefListCount < MAX_SM)
|
||||
{
|
||||
m_msgRefList[m_msgRefListCount] = msgRef;
|
||||
}
|
||||
m_msgRefListCount++; //Always count message
|
||||
m_inboxMtx.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("Could not get lock");
|
||||
m_needsUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GSMSMSInterface::updateInbox()
|
||||
{
|
||||
//Get memory indexes of unread messages
|
||||
|
||||
DBG("Updating inbox");
|
||||
m_msgRefListCount = 0; //Reset list
|
||||
m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
|
||||
|
||||
//First list the "REC READ" messages that were not processed in the previous session
|
||||
m_state = SMS_GET_COUNT_CMD_SENT;
|
||||
int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT+CMGL returned %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
m_msgRefListCount = 0; //List could be invalid
|
||||
m_needsUpdate = true;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
//Now list the "REC UNREAD" messages that were received by the modem since
|
||||
m_state = SMS_GET_COUNT_CMD_SENT;
|
||||
ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT+CMGL returned %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
m_msgRefListCount = 0; //List could be invalid
|
||||
m_needsUpdate = true;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("%d incoming messages in inbox", m_msgRefListCount);
|
||||
|
||||
m_state = SMS_IDLE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/* SMSInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GSMSMSINTERFACE_H_
|
||||
#define GSMSMSINTERFACE_H_
|
||||
|
||||
#include "SMSInterface.h"
|
||||
|
||||
/** Component to use the Short Messages Service (SMS)
|
||||
*
|
||||
*/
|
||||
class GSMSMSInterface : public ISMSInterface, protected IATCommandsProcessor, IATEventsHandler
|
||||
{
|
||||
public:
|
||||
/** Create SMSInterface instance
|
||||
@param pIf Pointer to the ATCommandsInterface instance to use
|
||||
*/
|
||||
GSMSMSInterface(ATCommandsInterface* pIf);
|
||||
|
||||
/** Initialize interface
|
||||
Configure SMS commands & register for SMS-related unsolicited result codes
|
||||
*/
|
||||
virtual int init();
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int send(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int get(char* number, char* message, size_t maxLength);
|
||||
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getCount(size_t* pCount);
|
||||
|
||||
protected:
|
||||
//IATCommandsProcessor
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
|
||||
|
||||
//IATEventsHandler
|
||||
virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled
|
||||
virtual void onDispatchStart();
|
||||
virtual void onDispatchStop();
|
||||
virtual char* getEventsEnableCommand();
|
||||
virtual char* getEventsDisableCommand();
|
||||
virtual void onEvent(const char* atCode, const char* evt);
|
||||
|
||||
//Updates messages count/references
|
||||
int updateInbox();
|
||||
|
||||
private:
|
||||
ATCommandsInterface* m_pIf;
|
||||
|
||||
//Current message
|
||||
char* m_msg;
|
||||
size_t m_maxMsgLength;
|
||||
char* m_msisdn;
|
||||
|
||||
//Messages list
|
||||
int m_msgRefList[MAX_SM];
|
||||
size_t m_msgRefListCount;
|
||||
bool m_needsUpdate;
|
||||
Mutex m_inboxMtx; //To protect concurrent accesses btw the user's thread and the AT thread
|
||||
|
||||
enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_GET_COUNT_HDR_RECEIVED, SMS_CMD_PROCESSED } m_state;
|
||||
};
|
||||
|
||||
#endif /* GSMSMSINTERFACE_H_ */
|
|
@ -1,67 +0,0 @@
|
|||
/* SMSInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ISMSINTERFACE_H_
|
||||
#define ISMSINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
#define MAX_SM 8
|
||||
|
||||
/** Component to use the Short Messages Service (SMS)
|
||||
*
|
||||
*/
|
||||
class ISMSInterface
|
||||
{
|
||||
public:
|
||||
/** Initialize interface
|
||||
Configure SMS commands & register for SMS-related unsolicited result codes
|
||||
*/
|
||||
virtual int init() = 0;
|
||||
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int send(const char* number, const char* message) = 0;
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int get(char* number, char* message, size_t maxLength) = 0;
|
||||
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getCount(size_t* pCount) = 0;
|
||||
};
|
||||
|
||||
#endif /* ISMSINTERFACE_H_ */
|
|
@ -1,196 +0,0 @@
|
|||
/* USSDInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "USSDInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "USSDInterface.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#define DEFAULT_TIMEOUT 10000
|
||||
#define USSD_TIMEOUT 15000
|
||||
|
||||
USSDInterface::USSDInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_responseMtx(), m_responseSphre(1), m_result(NULL), m_maxResultLength(0)
|
||||
{
|
||||
m_responseSphre.wait(0); //Take ownership of the semaphore
|
||||
m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
|
||||
}
|
||||
|
||||
int USSDInterface::init()
|
||||
{
|
||||
DBG("Initialization done");
|
||||
return OK;
|
||||
}
|
||||
|
||||
int USSDInterface::send(const char* command, char* result, size_t maxLength)
|
||||
{
|
||||
if (strlen(command) > 20) //Prevent buffer overflow
|
||||
{
|
||||
return NET_TOOSMALL;
|
||||
}
|
||||
|
||||
m_responseMtx.lock();
|
||||
m_result = result;
|
||||
m_maxResultLength = maxLength;
|
||||
m_responseMtx.unlock();
|
||||
|
||||
m_responseSphre.wait(0); //Make sure there is not a pending result that needs to be discarded
|
||||
|
||||
DBG("Send USSD command & register for unsolicited result codes");
|
||||
//Send USSD command to the network
|
||||
char cmd[32];
|
||||
std::sprintf(cmd, "AT+CUSD=1,\"%s\"", command);
|
||||
int ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
//Did we already get a response (3GPP rev < 6) ?
|
||||
|
||||
//Now wait for response
|
||||
int res = m_responseSphre.wait(USSD_TIMEOUT);
|
||||
|
||||
//Reset data
|
||||
m_responseMtx.lock();
|
||||
m_result = NULL;
|
||||
m_maxResultLength = 0;
|
||||
m_responseMtx.unlock();
|
||||
|
||||
if(res <= 0)
|
||||
{
|
||||
DBG("No result received");
|
||||
ret = m_pIf->executeSimple("AT+CUSD=2", NULL, DEFAULT_TIMEOUT); //Cancel command
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
|
||||
DBG("Result received: %s", result);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int USSDInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
const char* pSemicol = strchr(line, ':');
|
||||
if( ( (pSemicol - line) != strlen("+CUSD") ) || ( memcmp(line, "+CUSD", strlen("+CUSD")) != 0) )
|
||||
{
|
||||
WARN("Unknown code");
|
||||
return OK;
|
||||
}
|
||||
|
||||
const char* pData = NULL;
|
||||
if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
|
||||
{
|
||||
pData = pSemicol + 1;
|
||||
if(pData[0]==' ')
|
||||
{
|
||||
pData++; //Suppress whitespace
|
||||
}
|
||||
processResult(pData);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int USSDInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ bool USSDInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
|
||||
{
|
||||
DBG("AT code is %s", atCode);
|
||||
if( strcmp("+CUSD", atCode) == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DBG("Not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ void USSDInterface::onDispatchStart()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ void USSDInterface::onDispatchStop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ char* USSDInterface::getEventsEnableCommand()
|
||||
{
|
||||
return NULL; //No need to disable events here
|
||||
}
|
||||
|
||||
/*virtual*/ char* USSDInterface::getEventsDisableCommand()
|
||||
{
|
||||
return NULL; //No need to re-enable events here
|
||||
}
|
||||
|
||||
/*virtual*/ void USSDInterface::onEvent(const char* atCode, const char* evt)
|
||||
{
|
||||
if( strcmp("+CUSD", atCode) != 0 )
|
||||
{
|
||||
WARN("Wrong AT Code");
|
||||
return; //Not supported
|
||||
}
|
||||
|
||||
processResult(evt);
|
||||
}
|
||||
|
||||
void USSDInterface::processResult(const char* data)
|
||||
{
|
||||
char* pStart = (char*) strchr(data,'\"');
|
||||
if(pStart==NULL)
|
||||
{
|
||||
WARN("Could not find opening quote");
|
||||
return; //Invalid/incomplete response
|
||||
}
|
||||
pStart++; //Point to first char of response
|
||||
char* pEnd = (char*) strchr(pStart,'\"');
|
||||
if(pEnd==NULL)
|
||||
{
|
||||
WARN("Could not find closing quote");
|
||||
return; //Invalid/incomplete response
|
||||
}
|
||||
m_responseMtx.lock();
|
||||
if(m_maxResultLength == 0) //No pending command
|
||||
{
|
||||
WARN("No pending command");
|
||||
m_responseMtx.unlock();
|
||||
return;
|
||||
}
|
||||
size_t cpyLen = MIN( pEnd - pStart, m_maxResultLength - 1 );
|
||||
memcpy((void*)m_result, pStart, cpyLen);
|
||||
m_result[cpyLen] = '\0';
|
||||
DBG("Got USSD response: %s", m_result);
|
||||
m_responseMtx.unlock();
|
||||
m_responseSphre.release(); //Signal user thread that response is ready
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/* USSDInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef USSDINTERFACE_H_
|
||||
#define USSDINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
/** Component to send/receive Unstructured Supplementary Service Data (USSD)
|
||||
*
|
||||
*/
|
||||
class USSDInterface : protected IATCommandsProcessor, IATEventsHandler
|
||||
{
|
||||
public:
|
||||
/** Create USSDInterface instance
|
||||
@param pIf Pointer to the ATCommandsInterface instance to use
|
||||
*/
|
||||
USSDInterface(ATCommandsInterface* pIf);
|
||||
|
||||
/** Initialize interface
|
||||
Configure USSD commands & register for USSD-related unsolicited result codes
|
||||
*/
|
||||
int init();
|
||||
|
||||
/** Send a USSD command & wait for its result
|
||||
@param command The command to send
|
||||
@param result Buffer in which to store the result
|
||||
@param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int send(const char* command, char* result, size_t maxLength);
|
||||
|
||||
protected:
|
||||
//IATCommandsProcessor, needed for implementations of 3GGP standard < r06
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
|
||||
|
||||
//IATEventsHandler, needed for implementations of 3GGP standard >= r06
|
||||
virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled
|
||||
virtual void onDispatchStart();
|
||||
virtual void onDispatchStop();
|
||||
virtual char* getEventsEnableCommand();
|
||||
virtual char* getEventsDisableCommand();
|
||||
virtual void onEvent(const char* atCode, const char* evt);
|
||||
|
||||
private:
|
||||
void processResult(const char* data);
|
||||
|
||||
ATCommandsInterface* m_pIf;
|
||||
Mutex m_responseMtx; //To protect concurrent accesses btw the user's thread and the AT thread
|
||||
Semaphore m_responseSphre;
|
||||
|
||||
//Result
|
||||
volatile char* m_result;
|
||||
volatile size_t m_maxResultLength;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* USSDINTERFACE_H_ */
|
|
@ -1,253 +0,0 @@
|
|||
/* IOSerialStream.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0 //Maximum verbosity
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "IOSerialStream.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "IOSerialStream.h"
|
||||
|
||||
#define UART_X ((LPC_UART_TypeDef *)(UART_1))
|
||||
|
||||
IOSerialStream::IOSerialStream(mbed::RawSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
|
||||
m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf()
|
||||
{
|
||||
m_availableSphre.wait();
|
||||
m_spaceSphre.wait();
|
||||
//Attach interrupts
|
||||
m_serial.attach(this, &IOSerialStream::readable, mbed::SerialBase::RxIrq);
|
||||
m_serial.attach(this, &IOSerialStream::writeable, mbed::SerialBase::TxIrq);
|
||||
}
|
||||
|
||||
/*virtual*/ IOSerialStream::~IOSerialStream()
|
||||
{
|
||||
m_serial.attach(NULL, mbed::SerialBase::RxIrq);
|
||||
m_serial.attach(NULL, mbed::SerialBase::TxIrq);
|
||||
}
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
/*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
|
||||
{
|
||||
DBG("Trying to read at most %d chars", maxLength);
|
||||
int ret = waitAvailable(timeout);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Error %d while waiting for incoming data", ret);
|
||||
return ret;
|
||||
}
|
||||
int readLen = MIN( available(), maxLength );
|
||||
*pLength = readLen;
|
||||
setupReadableISR(false);
|
||||
while(readLen--)
|
||||
{
|
||||
m_inBuf.dequeue(buf);
|
||||
buf++;
|
||||
}
|
||||
setupReadableISR(true);
|
||||
DBG("Read %d chars successfully", *pLength);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ size_t IOSerialStream::available()
|
||||
{
|
||||
setupReadableISR(false); //m_inBuf.available() is not reentrant
|
||||
size_t len = m_inBuf.available();
|
||||
setupReadableISR(true);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*virtual*/ int IOSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
|
||||
{
|
||||
int ret;
|
||||
if(available()) //Is data already available?
|
||||
{
|
||||
m_availableSphre.wait(0); //Clear the queue as data is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
|
||||
ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
|
||||
if(ret <= 0)
|
||||
{
|
||||
DBG("Timeout");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
if(!available()) //Even if abort has been called, return that data is available
|
||||
{
|
||||
DBG("Aborted");
|
||||
return NET_INTERRUPTED;
|
||||
}
|
||||
DBG("Finished waiting");
|
||||
m_availableSphre.wait(0); //Clear the queue as data is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int IOSerialStream::abortRead() //Abort current reading (or waiting) operation
|
||||
{
|
||||
if( !available() ) //If there is data pending, no need to abort
|
||||
{
|
||||
m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Serial is readable"); ;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void IOSerialStream::setupReadableISR(bool en)
|
||||
{
|
||||
if(en)
|
||||
{
|
||||
UART_X->IER |= 1 << 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UART_X->IER &= ~(1 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
void IOSerialStream::readable() //Callback from m_serial when new data is available
|
||||
{
|
||||
do
|
||||
{
|
||||
m_inBuf.queue(m_serial.getc());
|
||||
} while(m_serial.readable());
|
||||
m_availableSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
/*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/)
|
||||
{
|
||||
DBG("Trying to write %d chars", length);
|
||||
int ret = waitSpace(timeout);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Error %d while waiting for space", ret);
|
||||
return ret;
|
||||
}
|
||||
DBG("Writing %d chars", length);
|
||||
setupWriteableISR(false);
|
||||
while(length)
|
||||
{
|
||||
m_outBuf.queue(*buf);
|
||||
buf++;
|
||||
length--;
|
||||
if(length && !space())
|
||||
{
|
||||
DBG("Waiting to write remaining %d chars", length);
|
||||
setupWriteableISR(true);
|
||||
ret = waitSpace(timeout);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Error %d while waiting for space", ret);
|
||||
return ret;
|
||||
}
|
||||
setupWriteableISR(false);
|
||||
}
|
||||
}
|
||||
//If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt
|
||||
if( m_outBuf.available() && m_serialTxFifoEmpty )
|
||||
{
|
||||
m_serialTxFifoEmpty = false;
|
||||
uint8_t c;
|
||||
m_outBuf.dequeue(&c);
|
||||
m_serial.putc((char)c);
|
||||
}
|
||||
setupWriteableISR(true);
|
||||
DBG("Write successful");
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ size_t IOSerialStream::space()
|
||||
{
|
||||
setupWriteableISR(false); //m_outBuf.available() is not reentrant
|
||||
size_t len = CIRCBUF_SIZE - m_outBuf.available();
|
||||
setupWriteableISR(true);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available
|
||||
{
|
||||
int ret;
|
||||
if(space()) //Is still space already left?
|
||||
{
|
||||
m_spaceSphre.wait(0); //Clear the queue as space is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
|
||||
ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
|
||||
if(ret <= 0)
|
||||
{
|
||||
DBG("Timeout");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
if(!space()) //Even if abort has been called, return that space is available
|
||||
{
|
||||
DBG("Aborted");
|
||||
return NET_INTERRUPTED;
|
||||
}
|
||||
m_spaceSphre.wait(0); //Clear the queue as space is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation
|
||||
{
|
||||
if( !space() ) //If there is space left, no need to abort
|
||||
{
|
||||
m_spaceSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void IOSerialStream::setupWriteableISR(bool en)
|
||||
{
|
||||
if(en)
|
||||
{
|
||||
UART_X->IER |= 1 << 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UART_X->IER &= ~(1 << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void IOSerialStream::writeable() //Callback from m_serial when new space is available
|
||||
{
|
||||
if(m_outBuf.isEmpty())
|
||||
{
|
||||
m_serialTxFifoEmpty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(m_serial.writeable() && !m_outBuf.isEmpty())
|
||||
{
|
||||
uint8_t c;
|
||||
m_outBuf.dequeue(&c);
|
||||
m_serial.putc((char)c);
|
||||
}
|
||||
}
|
||||
m_spaceSphre.release(); //Force exiting the waiting state
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/* IOSerialStream.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef IOSERIALSTREAM_H_
|
||||
#define IOSERIALSTREAM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "RawSerial.h"
|
||||
|
||||
#include "rtos.h"
|
||||
#include "core/MtxCircBuffer.h"
|
||||
|
||||
/** Input Serial Stream for physical serial interfaces (UART...)
|
||||
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
|
||||
*/
|
||||
class IOSerialStream : public IOStream
|
||||
{
|
||||
public:
|
||||
enum { CIRCBUF_SIZE = 255 };
|
||||
IOSerialStream(mbed::RawSerial& serial);
|
||||
/*virtual*/ ~IOSerialStream();
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
|
||||
virtual size_t available();
|
||||
virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
|
||||
virtual int abortRead(); //Abort current reading (or waiting) operation
|
||||
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
|
||||
virtual size_t space();
|
||||
virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
|
||||
virtual int abortWrite(); //Abort current writing (or waiting) operation
|
||||
|
||||
private:
|
||||
|
||||
mbed::RawSerial& m_serial;
|
||||
volatile bool m_serialTxFifoEmpty;
|
||||
|
||||
void setupReadableISR(bool en);
|
||||
void readable(); //Callback from m_serial when new data is available
|
||||
|
||||
Semaphore m_availableSphre; //Used for signalling
|
||||
|
||||
void setupWriteableISR(bool en);
|
||||
void writeable(); //Callback from m_serial when new space is available
|
||||
|
||||
Semaphore m_spaceSphre; //Used for signalling
|
||||
|
||||
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
|
||||
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
|
||||
|
||||
};
|
||||
|
||||
#endif /* IOSERIALSTREAM_H_ */
|
|
@ -1,236 +0,0 @@
|
|||
/* USBSerialStream.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "USBSerialStream.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "USBSerialStream.h"
|
||||
|
||||
|
||||
USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
|
||||
m_availableSphre(1), m_spaceSphre(1), m_inBuf()
|
||||
{
|
||||
m_availableSphre.wait();
|
||||
m_spaceSphre.wait();
|
||||
//Attach interrupts
|
||||
m_serial.attach(this);
|
||||
}
|
||||
|
||||
/*virtual*/ USBSerialStream::~USBSerialStream()
|
||||
{
|
||||
m_serial.attach(NULL);
|
||||
}
|
||||
|
||||
//0 for non-blocking (returns immediately), -1 for infinite blocking
|
||||
/*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
|
||||
{
|
||||
DBG("Trying to read at most %d chars", maxLength);
|
||||
int ret = waitAvailable(timeout);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Error %d while waiting for incoming data", ret);
|
||||
return ret;
|
||||
}
|
||||
int a = available(); //Prevent macro issues
|
||||
int readLen = MIN( a, maxLength );
|
||||
*pLength = readLen;
|
||||
|
||||
setupReadableISR(false);
|
||||
while(readLen--)
|
||||
{
|
||||
m_inBuf.dequeue(buf);
|
||||
buf++;
|
||||
}
|
||||
setupReadableISR(true);
|
||||
DBG("Read %d chars successfully", *pLength);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ size_t USBSerialStream::available()
|
||||
{
|
||||
setupReadableISR(false); //m_inBuf.available() is not reentrant
|
||||
size_t len = m_inBuf.available();
|
||||
setupReadableISR(true);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
|
||||
{
|
||||
int ret;
|
||||
if(available()) //Is data already available?
|
||||
{
|
||||
while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
|
||||
ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
|
||||
if(ret <= 0)
|
||||
{
|
||||
DBG("Timeout");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
if(!m_inBuf.available()) //Even if abort has been called, return that data is available
|
||||
{
|
||||
DBG("Aborted");
|
||||
return NET_INTERRUPTED;
|
||||
}
|
||||
DBG("Finished waiting");
|
||||
while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
|
||||
{
|
||||
if( /*!available()*/true ) //If there is data pending, no need to abort
|
||||
{
|
||||
m_availableSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Serial is readable"); ;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void USBSerialStream::setupReadableISR(bool en)
|
||||
{
|
||||
m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
|
||||
}
|
||||
|
||||
void USBSerialStream::readable() //Callback from m_serial when new data is available
|
||||
{
|
||||
while(m_serial.readable())
|
||||
{
|
||||
m_inBuf.queue(m_serial.getc());
|
||||
}
|
||||
m_serial.readPacket(); //Start read of next packet
|
||||
m_availableSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
|
||||
//0 for non-blocking (returns immediately), -1 for infinite blocking
|
||||
/*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
|
||||
{
|
||||
DBG("Trying to write %d chars", length);
|
||||
do
|
||||
{
|
||||
int ret = waitSpace(timeout);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Error %d while waiting for space", ret);
|
||||
return ret;
|
||||
}
|
||||
int s = space(); //Prevent macro issues
|
||||
int writeLen = MIN( s, length );
|
||||
DBG("Writing %d chars", writeLen);
|
||||
setupWriteableISR(false);
|
||||
while(writeLen)
|
||||
{
|
||||
m_outBuf.queue(*buf);
|
||||
buf++;
|
||||
length--;
|
||||
writeLen--;
|
||||
}
|
||||
//If m_serial tx fifo is empty we need to start the packet write
|
||||
if( m_outBuf.available() && m_serialTxFifoEmpty )
|
||||
{
|
||||
writeable();
|
||||
}
|
||||
setupWriteableISR(true);
|
||||
} while(length);
|
||||
|
||||
DBG("Write successful");
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ size_t USBSerialStream::space()
|
||||
{
|
||||
setupWriteableISR(false); //m_outBuf.available() is not reentrant
|
||||
size_t len = CIRCBUF_SIZE - m_outBuf.available();
|
||||
setupWriteableISR(true);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
|
||||
{
|
||||
int ret;
|
||||
if(space()) //Is still space already left?
|
||||
{
|
||||
while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
|
||||
ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
|
||||
if(ret <= 0)
|
||||
{
|
||||
DBG("Timeout");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
if(!space()) //Even if abort has been called, return that space is available
|
||||
{
|
||||
DBG("Aborted");
|
||||
return NET_INTERRUPTED;
|
||||
}
|
||||
while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation
|
||||
{
|
||||
if( !space() ) //If there is space left, no need to abort
|
||||
{
|
||||
m_spaceSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void USBSerialStream::setupWriteableISR(bool en)
|
||||
{
|
||||
m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
|
||||
}
|
||||
|
||||
void USBSerialStream::writeable() //Callback from m_serial when new space is available
|
||||
{
|
||||
if(m_outBuf.isEmpty())
|
||||
{
|
||||
m_serialTxFifoEmpty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_serialTxFifoEmpty = false;
|
||||
while(m_serial.writeable() && !m_outBuf.isEmpty())
|
||||
{
|
||||
uint8_t c;
|
||||
m_outBuf.dequeue(&c);
|
||||
m_serial.putc((char)c);
|
||||
}
|
||||
m_serial.writePacket(); //Start packet write
|
||||
}
|
||||
if(!m_outBuf.isFull())
|
||||
{
|
||||
m_spaceSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/* USBSerialStream.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef USBSERIALSTREAM_H_
|
||||
#define USBSERIALSTREAM_H_
|
||||
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "USBHost3GModule/IUSBHostSerial.h"
|
||||
#include "USBHost3GModule/IUSBHostSerialListener.h"
|
||||
|
||||
#include "rtos.h"
|
||||
#include "core/MtxCircBuffer.h"
|
||||
|
||||
/* Input Serial Stream for USB virtual serial ports interfaces
|
||||
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
|
||||
*/
|
||||
|
||||
class USBSerialStream : public IOStream, IUSBHostSerialListener
|
||||
{
|
||||
public:
|
||||
enum { CIRCBUF_SIZE = 127 };
|
||||
USBSerialStream(IUSBHostSerial& serial);
|
||||
/*virtual*/ ~USBSerialStream();
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
|
||||
virtual size_t available();
|
||||
virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
|
||||
virtual int abortRead(); //Abort current reading (or waiting) operation
|
||||
|
||||
|
||||
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||
virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
|
||||
virtual size_t space();
|
||||
virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
|
||||
virtual int abortWrite(); //Abort current writing (or waiting) operation
|
||||
|
||||
private:
|
||||
IUSBHostSerial& m_serial;
|
||||
volatile bool m_serialTxFifoEmpty;
|
||||
|
||||
void setupReadableISR(bool en);
|
||||
virtual void readable(); //Callback from m_serial when new data is available
|
||||
|
||||
Semaphore m_availableSphre; //Used for signalling
|
||||
|
||||
void setupWriteableISR(bool en);
|
||||
virtual void writeable(); //Callback from m_serial when new space is available
|
||||
|
||||
Semaphore m_spaceSphre; //Used for signalling
|
||||
|
||||
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
|
||||
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
|
||||
};
|
||||
|
||||
#endif /* USBSERIALSTREAM_H_ */
|
|
@ -1,114 +0,0 @@
|
|||
/* Copyright (c) 2010-2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 4
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxCDMAModemInitializer.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "UbloxCDMAModemInitializer.h"
|
||||
|
||||
UbloxCDMAModemInitializer::UbloxCDMAModemInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t UbloxCDMAModemInitializer::getMSDVid()
|
||||
{
|
||||
return 0x05C6;
|
||||
}
|
||||
uint16_t UbloxCDMAModemInitializer::getMSDPid()
|
||||
{
|
||||
return 0x0000; //No MSD mode (presumably)
|
||||
}
|
||||
|
||||
uint16_t UbloxCDMAModemInitializer::getSerialVid()
|
||||
{
|
||||
return 0x05C6;
|
||||
}
|
||||
uint16_t UbloxCDMAModemInitializer::getSerialPid()
|
||||
{
|
||||
return 0x9004;
|
||||
}
|
||||
|
||||
bool UbloxCDMAModemInitializer::switchMode(USBDeviceConnected* pDev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int UbloxCDMAModemInitializer::getSerialPortCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*virtual*/ void UbloxCDMAModemInitializer::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
m_currentSerialIntf = 0;
|
||||
m_currentEndpoint = 0;
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxCDMAModemInitializer::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
|
||||
{
|
||||
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
|
||||
|
||||
if( intf_class == 0xFF ) {
|
||||
if( m_currentSerialIntf == 0 || m_currentSerialIntf == 1) {
|
||||
m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
|
||||
return true;
|
||||
}
|
||||
m_currentSerialIntf++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxCDMAModemInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d Current %d", intf_nb, type, dir, m_currentEndpoint);
|
||||
if(type == BULK_ENDPOINT) {
|
||||
if( intf_nb == 1 || intf_nb == 0) {
|
||||
m_currentEndpoint++;
|
||||
return true;
|
||||
} else {
|
||||
m_currentEndpoint++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if(type == INTERRUPT_ENDPOINT) {
|
||||
if( intf_nb == 1) {
|
||||
m_currentEndpoint++;
|
||||
return true;
|
||||
} else {
|
||||
m_currentEndpoint++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ int UbloxCDMAModemInitializer::getType()
|
||||
{
|
||||
return WAN_DONGLE_TYPE_UBLOX_LISAC200;
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* Copyright (c) 2010-2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UBLOXCDMAMODEMINITIALIZER_H
|
||||
#define UBLOXCDMAMODEMINITIALIZER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "WANDongleInitializer.h"
|
||||
#include "USBHost.h"
|
||||
#include "IUSBEnumerator.h"
|
||||
|
||||
enum
|
||||
{
|
||||
WAN_DONGLE_TYPE_UBLOX_LISAC200 = 0xC200,
|
||||
};
|
||||
|
||||
class UbloxCDMAModemInitializer : public WANDongleInitializer
|
||||
{
|
||||
public:
|
||||
UbloxCDMAModemInitializer(USBHost* pHost);
|
||||
|
||||
virtual uint16_t getMSDVid();
|
||||
virtual uint16_t getMSDPid();
|
||||
|
||||
virtual uint16_t getSerialVid();
|
||||
virtual uint16_t getSerialPid();
|
||||
|
||||
virtual bool switchMode(USBDeviceConnected* pDev);
|
||||
|
||||
virtual int getSerialPortCount();
|
||||
|
||||
virtual void setVidPid(uint16_t vid, uint16_t pid);
|
||||
|
||||
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
|
||||
|
||||
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
|
||||
|
||||
virtual int getType();
|
||||
|
||||
private:
|
||||
|
||||
int m_currentSerialIntf;
|
||||
int m_currentEndpoint;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/* Copyright (c) 2010-2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "UbloxGSMModemInitializer.h"
|
||||
#include "core/dbg.h"
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxGSMModemInitializer.cpp"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// mamm, u-blox Modem
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
UbloxGSMModemInitializer::UbloxGSMModemInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t UbloxGSMModemInitializer::getMSDVid() { return 0x1546; }
|
||||
uint16_t UbloxGSMModemInitializer::getMSDPid() { return 0x0000; }
|
||||
|
||||
uint16_t UbloxGSMModemInitializer::getSerialVid() { return 0x1546; }
|
||||
uint16_t UbloxGSMModemInitializer::getSerialPid() { return 0x1102; }
|
||||
|
||||
bool UbloxGSMModemInitializer::switchMode(USBDeviceConnected* pDev)
|
||||
{
|
||||
for (int i = 0; i < pDev->getNbIntf(); i++)
|
||||
{
|
||||
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
|
||||
{
|
||||
USBEndpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
|
||||
if ( pEp != NULL )
|
||||
{
|
||||
ERR("MSD descriptor found on device %p, intf %d", (void *)pDev, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define UBX_SERIALCOUNT 7
|
||||
|
||||
int UbloxGSMModemInitializer::getSerialPortCount()
|
||||
{
|
||||
return UBX_SERIALCOUNT;
|
||||
}
|
||||
|
||||
/*virtual*/ void UbloxGSMModemInitializer::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
|
||||
{
|
||||
m_hasSwitched = true;
|
||||
m_currentSerialIntf = 0;
|
||||
m_endpointsToFetch = UBX_SERIALCOUNT*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hasSwitched = false;
|
||||
m_endpointsToFetch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxGSMModemInitializer::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
|
||||
{
|
||||
if( m_hasSwitched )
|
||||
{
|
||||
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
|
||||
if( intf_class == 0x0A )
|
||||
{
|
||||
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 1) )
|
||||
{
|
||||
m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
|
||||
return true;
|
||||
}
|
||||
m_currentSerialIntf++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxGSMModemInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
if( m_hasSwitched )
|
||||
{
|
||||
DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d", intf_nb, type, dir);
|
||||
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ int UbloxGSMModemInitializer::getType()
|
||||
{
|
||||
return WAN_DONGLE_TYPE_UBLOX_LISAU200;
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* Copyright (c) 2010-2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UBLOXGSMMODEMINITIALIZER_H
|
||||
#define UBLOXGSNMODEMINITIALIZER_H
|
||||
|
||||
#include "WANDongleInitializer.h"
|
||||
|
||||
enum
|
||||
{
|
||||
WAN_DONGLE_TYPE_UBLOX_LISAU200 = 0x0200
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// mamm, u-blox Modem
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class UbloxGSMModemInitializer : public WANDongleInitializer
|
||||
{
|
||||
public:
|
||||
UbloxGSMModemInitializer(USBHost* pHost);
|
||||
|
||||
virtual uint16_t getMSDVid();
|
||||
virtual uint16_t getMSDPid();
|
||||
|
||||
virtual uint16_t getSerialVid();
|
||||
virtual uint16_t getSerialPid();
|
||||
|
||||
virtual bool switchMode(USBDeviceConnected* pDev);
|
||||
|
||||
virtual int getSerialPortCount();
|
||||
|
||||
virtual void setVidPid(uint16_t vid, uint16_t pid);
|
||||
|
||||
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
|
||||
|
||||
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
|
||||
|
||||
virtual int getType();
|
||||
|
||||
private:
|
||||
|
||||
bool m_hasSwitched;
|
||||
int m_currentSerialIntf;
|
||||
int m_endpointsToFetch;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,559 +0,0 @@
|
|||
/* UbloxModem.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 3
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxModem.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
#include "sms/GSMSMSInterface.h"
|
||||
#include "sms/CDMASMSInterface.h"
|
||||
|
||||
#include "UbloxModem.h"
|
||||
|
||||
UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) :
|
||||
m_at(atStream), // Construct ATCommandsInterface with the AT serial channel
|
||||
m_CdmaSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
||||
m_GsmSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
||||
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
|
||||
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
|
||||
m_ppp(pppStream ? pppStream : atStream), // Construct PPPIPInterface with the PPP serial channel
|
||||
m_ipInit(false), // PPIPInterface connection is initially down
|
||||
m_smsInit(false), // SMSInterface starts un-initialised
|
||||
m_ussdInit(false), // USSDInterface starts un-initialised
|
||||
m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
|
||||
m_atOpen(false), // ATCommandsInterface starts in a closed state
|
||||
m_onePort(pppStream == NULL),
|
||||
m_type(UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
genericAtProcessor::genericAtProcessor()
|
||||
{
|
||||
i = 0;
|
||||
str[0] = '\0';
|
||||
}
|
||||
|
||||
const char* genericAtProcessor::getResponse(void)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
int genericAtProcessor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
int l = strlen(line);
|
||||
if (i + l + 2 > sizeof(str))
|
||||
return NET_OVERFLOW;
|
||||
if (i) str[i++] = ',';
|
||||
strcat(&str[i], line);
|
||||
i += l;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int genericAtProcessor::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
class CREGProcessor : public IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
CREGProcessor(bool gsm) : status(STATUS_REGISTERING)
|
||||
{
|
||||
m_gsm = gsm;
|
||||
}
|
||||
enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
|
||||
REGISTERING_STATUS getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
const char* getAtCommand()
|
||||
{
|
||||
return m_gsm ? "AT+CREG?" : "AT+CSS?";
|
||||
}
|
||||
private:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
int r;
|
||||
if (m_gsm)
|
||||
{
|
||||
if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
|
||||
{
|
||||
status = (r == 1 || r == 5) ? STATUS_OK :
|
||||
(r == 0 || r == 2) ? STATUS_REGISTERING :
|
||||
// (r == 3) ? STATUS_FAILED :
|
||||
STATUS_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char bc[3] = "";
|
||||
if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1)
|
||||
{
|
||||
status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
volatile REGISTERING_STATUS status;
|
||||
bool m_gsm;
|
||||
};
|
||||
|
||||
int UbloxModem::connect(const char* apn, const char* user, const char* password)
|
||||
{
|
||||
if( !m_ipInit )
|
||||
{
|
||||
m_ipInit = true;
|
||||
m_ppp.init();
|
||||
}
|
||||
m_ppp.setup(user, password, (m_type != LISA_C200) ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA);
|
||||
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (m_onePort)
|
||||
{
|
||||
m_smsInit = false; //SMS status reset
|
||||
m_ussdInit = false; //USSD status reset
|
||||
m_linkMonitorInit = false; //Link monitor status reset
|
||||
}
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
if(apn != NULL)
|
||||
{
|
||||
char cmd[48];
|
||||
int tries = 30;
|
||||
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
|
||||
do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
|
||||
{
|
||||
ret = m_at.executeSimple(cmd, &result);
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
if(ret)
|
||||
{
|
||||
Thread::wait(500);
|
||||
}
|
||||
} while(ret && --tries);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
DBG("APN set to %s", apn);
|
||||
}
|
||||
|
||||
//Connect
|
||||
DBG("Connecting");
|
||||
if (m_onePort)
|
||||
{
|
||||
m_at.close(); // Closing AT parser
|
||||
m_atOpen = false; //Will need to be reinitialized afterwards
|
||||
}
|
||||
|
||||
DBG("Connecting PPP");
|
||||
|
||||
ret = m_ppp.connect();
|
||||
DBG("Result of connect: Err code=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int UbloxModem::disconnect()
|
||||
{
|
||||
DBG("Disconnecting from PPP");
|
||||
int ret = m_ppp.disconnect();
|
||||
if(ret)
|
||||
{
|
||||
ERR("Disconnect returned %d, still trying to disconnect", ret);
|
||||
}
|
||||
|
||||
//Ugly but leave dongle time to recover
|
||||
Thread::wait(500);
|
||||
|
||||
if (m_onePort)
|
||||
{
|
||||
//ATCommandsInterface::ATResult result;
|
||||
DBG("Starting AT thread");
|
||||
ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("Trying to hangup");
|
||||
|
||||
if (m_onePort)
|
||||
{
|
||||
//Reinit AT parser
|
||||
ret = m_at.init(false);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
if(ret)
|
||||
{
|
||||
m_at.close(); // Closing AT parser
|
||||
DBG("AT Parser closed, could not complete disconnection");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::sendSM(const char* number, const char* message)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ISMSInterface* sms;
|
||||
if (m_type == LISA_C200) sms = &m_CdmaSms;
|
||||
else sms = &m_GsmSms;
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = sms->init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = sms->send(number, message);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::getSM(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ISMSInterface* sms;
|
||||
if (m_type == LISA_C200) sms = &m_CdmaSms;
|
||||
else sms = &m_GsmSms;
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = sms->init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = sms->get(number, message, maxLength);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::getSMCount(size_t* pCount)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ISMSInterface* sms;
|
||||
if (m_type == LISA_C200) sms = &m_CdmaSms;
|
||||
else sms = &m_GsmSms;
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = sms->init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = sms->getCount(pCount);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
ATCommandsInterface* UbloxModem::getATCommandsInterface()
|
||||
{
|
||||
return &m_at;
|
||||
}
|
||||
|
||||
int UbloxModem::init()
|
||||
{
|
||||
if(m_atOpen)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Starting AT thread if needed");
|
||||
int ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBG("Sending initialisation commands");
|
||||
ret = m_at.init(false);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
genericAtProcessor atiProcessor;
|
||||
ret = m_at.execute("ATI", &atiProcessor, &result);
|
||||
if (OK != ret)
|
||||
return ret;
|
||||
const char* info = atiProcessor.getResponse();
|
||||
INFO("Modem Identification [%s]", info);
|
||||
if (strstr(info, "LISA-C200")) {
|
||||
m_type = LISA_C200;
|
||||
m_onePort = true; // force use of only one port
|
||||
}
|
||||
else if (strstr(info, "LISA-U200")) {
|
||||
m_type = LISA_U200;
|
||||
}
|
||||
else if (strstr(info, "SARA-G350")) {
|
||||
m_type = SARA_G350;
|
||||
}
|
||||
|
||||
// enable the network indicator
|
||||
if (m_type == SARA_G350) {
|
||||
m_at.executeSimple("AT+UGPIOC=16,2", &result);
|
||||
}
|
||||
else if (m_type == LISA_U200) {
|
||||
m_at.executeSimple("AT+UGPIOC=20,2", &result);
|
||||
}
|
||||
else if (m_type == LISA_C200) {
|
||||
// LISA-C200 02S/22S : GPIO1 do not support network status indication
|
||||
// m_at.executeSimple("AT+UGPIOC=20,2", &result);
|
||||
}
|
||||
INFO("Modem Identification [%s]", info);
|
||||
|
||||
CREGProcessor cregProcessor(m_type != LISA_C200);
|
||||
//Wait for network registration
|
||||
do
|
||||
{
|
||||
DBG("Waiting for network registration");
|
||||
ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
|
||||
{
|
||||
Thread::wait(3000);
|
||||
}
|
||||
} while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
|
||||
if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
|
||||
{
|
||||
ERR("Registration denied");
|
||||
return NET_AUTH;
|
||||
}
|
||||
|
||||
m_atOpen = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::cleanup()
|
||||
{
|
||||
if(m_ppp.isConnected())
|
||||
{
|
||||
WARN("Data connection is still open"); //Try to encourage good behaviour from the user
|
||||
m_ppp.disconnect();
|
||||
}
|
||||
|
||||
m_smsInit = false;
|
||||
m_ussdInit = false;
|
||||
m_linkMonitorInit = false;
|
||||
//We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
|
||||
|
||||
if(m_atOpen)
|
||||
{
|
||||
m_at.close();
|
||||
m_atOpen = false;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_ussdInit)
|
||||
{
|
||||
ret = m_ussd.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_ussdInit = true;
|
||||
}
|
||||
|
||||
ret = m_ussd.send(command, result, maxLength);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_linkMonitorInit)
|
||||
{
|
||||
ret = m_linkMonitor.init(m_type != LISA_C200);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_linkMonitorInit = true;
|
||||
}
|
||||
|
||||
ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxModem::getPhoneNumber(char* phoneNumber)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_linkMonitorInit)
|
||||
{
|
||||
ret = m_linkMonitor.init(m_type != LISA_C200);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_linkMonitorInit = true;
|
||||
}
|
||||
|
||||
ret = m_linkMonitor.getPhoneNumber(phoneNumber);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#include "USBHost.h"
|
||||
#include "UbloxGSMModemInitializer.h"
|
||||
#include "UbloxCDMAModemInitializer.h"
|
||||
|
||||
UbloxUSBModem::UbloxUSBModem() :
|
||||
UbloxModem(&m_atStream, &m_pppStream),
|
||||
m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
|
||||
m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
|
||||
m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
|
||||
m_dongleConnected(false) // Dongle is initially not ready for anything
|
||||
{
|
||||
USBHost* host = USBHost::getHostInst();
|
||||
m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
|
||||
m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
|
||||
}
|
||||
|
||||
int UbloxUSBModem::init()
|
||||
{
|
||||
if( !m_dongleConnected )
|
||||
{
|
||||
m_dongleConnected = true;
|
||||
while( !m_dongle.connected() )
|
||||
{
|
||||
m_dongle.tryConnect();
|
||||
Thread::wait(10);
|
||||
}
|
||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
|
||||
{
|
||||
INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
|
||||
m_type = LISA_U200;
|
||||
}
|
||||
else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
|
||||
{
|
||||
INFO("Using a u-blox LISA-C200 CDMA Modem");
|
||||
m_type = LISA_C200;
|
||||
m_onePort = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("Using an Unknown Dongle");
|
||||
}
|
||||
}
|
||||
return UbloxModem::init();
|
||||
}
|
||||
|
||||
int UbloxUSBModem::cleanup()
|
||||
{
|
||||
UbloxModem::cleanup();
|
||||
m_dongle.disconnect();
|
||||
m_dongleConnected = false;
|
||||
return OK;
|
||||
}
|
||||
|
||||
UbloxSerModem::UbloxSerModem() :
|
||||
UbloxModem(&m_atStream, NULL),
|
||||
m_Serial(P0_15/*MDMTXD*/,P0_16/*MDMRXD*/),
|
||||
m_atStream(m_Serial)
|
||||
{
|
||||
m_Serial.baud(115200/*MDMBAUD*/);
|
||||
m_Serial.set_flow_control(SerialBase::RTSCTS, P0_22/*MDMRTS*/, P0_17/*MDMCTS*/);
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
/* VodafoneUSBModem.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UBLOXMODEM_H_
|
||||
#define UBLOXMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "at/ATCommandsInterface.h"
|
||||
#include "ip/PPPIPInterface.h"
|
||||
#include "sms/GSMSMSInterface.h"
|
||||
#include "sms/CDMASMSInterface.h"
|
||||
#include "ussd/USSDInterface.h"
|
||||
#include "link/LinkMonitor.h"
|
||||
#include "CellularModem.h"
|
||||
|
||||
class genericAtProcessor : public IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
genericAtProcessor();
|
||||
const char* getResponse(void);
|
||||
private:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
|
||||
protected:
|
||||
char str[256];
|
||||
int i;
|
||||
};
|
||||
|
||||
/** u-blox WCDMA modem (LISA-U200)
|
||||
*/
|
||||
class UbloxModem: public CellularModem
|
||||
{
|
||||
public:
|
||||
/** Create u-blox API instance
|
||||
@param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
|
||||
@param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
|
||||
*/
|
||||
UbloxModem(IOStream* atStream, IOStream* pppStream);
|
||||
|
||||
//Internet-related functions
|
||||
|
||||
/** Open a 3G internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
|
||||
|
||||
/** Close the internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int sendSM(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSM(char* number, char* message, size_t maxLength);
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSMCount(size_t* pCount);
|
||||
|
||||
/** Send a USSD command & wait for its result
|
||||
@param command The command to send
|
||||
@param result Buffer in which to store the result
|
||||
@param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int sendUSSD(const char* command, char* result, size_t maxLength);
|
||||
|
||||
/** Get link state
|
||||
@param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
|
||||
@param pRegistrationState pointer to store the current registration state
|
||||
@param pBearer pointer to store the current bearer
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer);
|
||||
|
||||
int getPhoneNumber(char* phoneNumber);
|
||||
|
||||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
virtual ATCommandsInterface* getATCommandsInterface();
|
||||
|
||||
protected:
|
||||
/** Initialise dongle.
|
||||
* The following actions are performed:
|
||||
* 1) Start AT interface thread
|
||||
* 2) Wait for network registration
|
||||
*/
|
||||
virtual int init();
|
||||
|
||||
/** De-initialise dongle.
|
||||
* The following actions are performed:
|
||||
* 1) Tear down PPP session
|
||||
* 2) Set SMS,USSD, and LinkMonitor subsystems to un-initialised
|
||||
* 3) Close the AT commands interface
|
||||
*/
|
||||
virtual int cleanup();
|
||||
|
||||
private:
|
||||
ATCommandsInterface m_at; //< Interface to AT commands processing
|
||||
|
||||
CDMASMSInterface m_CdmaSms; //< Interface to SMS manager (send/receive etc)
|
||||
GSMSMSInterface m_GsmSms; //< Interface to SMS manager (send/receive etc)
|
||||
USSDInterface m_ussd; //< Interface to USSD manager (send etc)
|
||||
LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
|
||||
|
||||
PPPIPInterface m_ppp; //< Interface to PPP conection manager (IP assignment etc)
|
||||
|
||||
bool m_ipInit; //< Has PPIPInterface object (m_ppp) been initialised? true/false
|
||||
bool m_smsInit; //< Has SMSInterface object (m_sms) been initialised? true/false
|
||||
bool m_ussdInit; //< Has USSDInterface object (m_ussd) been initialised? true/false
|
||||
bool m_linkMonitorInit; //< Has LinkMonitor object (m_linkMonitor) been initialised? true/false
|
||||
bool m_atOpen; //< Is the interface to the ATCommandsInterface open? true/false
|
||||
protected:
|
||||
bool m_onePort;
|
||||
enum { LISA_C200, LISA_U200, SARA_G350, UNKNOWN } m_type;
|
||||
};
|
||||
|
||||
#include "WANDongle.h"
|
||||
#include "serial/usb/USBSerialStream.h"
|
||||
|
||||
class UbloxUSBModem: public UbloxModem
|
||||
{
|
||||
public:
|
||||
UbloxUSBModem();
|
||||
virtual int init();
|
||||
virtual int cleanup();
|
||||
virtual int power(bool enable) { return 1; }
|
||||
|
||||
private:
|
||||
WANDongle m_dongle; //< Interface to USB connected WAN dongle
|
||||
|
||||
USBSerialStream m_atStream; //< Serial interface to AT channel on modem
|
||||
USBSerialStream m_pppStream; //< Serial interface to PPP channel on modem
|
||||
|
||||
bool m_dongleConnected; //< Is the dongle physically connected (does the USB stack respond)? true/false
|
||||
};
|
||||
|
||||
#include "serial/io/IOSerialStream.h"
|
||||
|
||||
class UbloxSerModem: public UbloxModem
|
||||
{
|
||||
public:
|
||||
UbloxSerModem();
|
||||
virtual int power(bool enable) { return 1; }
|
||||
private:
|
||||
RawSerial m_Serial;
|
||||
IOSerialStream m_atStream; //< Serial interface to AT channel on modem
|
||||
};
|
||||
|
||||
#endif /* UBLOXMODEM_H_ */
|
|
@ -1,398 +0,0 @@
|
|||
/* UbloxUSBCDMAModem.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 4
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxUSBCDMAModem.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "UbloxUSBCDMAModem.h"
|
||||
#include "UbloxCDMAModemInitializer.h"
|
||||
#include "USBHost.h"
|
||||
|
||||
#define USE_ONE_PORT 1
|
||||
|
||||
UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
|
||||
m_stream(m_dongle.getSerial(serial)),
|
||||
m_at(&m_stream),
|
||||
m_sms(&m_at), m_ppp(&m_stream),
|
||||
m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
|
||||
m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
|
||||
{
|
||||
USBHost* host = USBHost::getHostInst();
|
||||
m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
|
||||
if( m_powerGatingPin != NC )
|
||||
{
|
||||
power(false); //Dongle will have to be powered on manually
|
||||
}
|
||||
}
|
||||
|
||||
class CSSProcessor : public IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
CSSProcessor() : status(STATUS_REGISTERING)
|
||||
{
|
||||
|
||||
}
|
||||
enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
|
||||
REGISTERING_STATUS getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
private:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
char b;
|
||||
char bc[3] = "";
|
||||
int sid = 99999;
|
||||
|
||||
//if( sscanf(line, "%*d, %c", &r) == 1 )
|
||||
if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
|
||||
{
|
||||
if(strcmp("Z", bc) == 0)
|
||||
status = STATUS_REGISTERING;
|
||||
else
|
||||
status = STATUS_OK;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
volatile REGISTERING_STATUS status;
|
||||
};
|
||||
|
||||
int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* password)
|
||||
{
|
||||
if( !m_ipInit )
|
||||
{
|
||||
m_ipInit = true;
|
||||
m_ppp.init();
|
||||
}
|
||||
m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
|
||||
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if USE_ONE_PORT
|
||||
m_smsInit = false; //SMS status reset
|
||||
//m_ussdInit = false; //USSD status reset
|
||||
//m_linkMonitorInit = false; //Link monitor status reset
|
||||
#endif
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
if(apn != NULL)
|
||||
{
|
||||
char cmd[48];
|
||||
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
|
||||
ret = m_at.executeSimple(cmd, &result);
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
DBG("APN set to %s", apn);
|
||||
}
|
||||
|
||||
|
||||
//Connect
|
||||
DBG("Connecting");
|
||||
#if USE_ONE_PORT
|
||||
m_at.close(); // Closing AT parser
|
||||
m_atOpen = false; //Will need to be reinitialized afterwards
|
||||
#endif
|
||||
|
||||
DBG("Connecting PPP");
|
||||
|
||||
ret = m_ppp.connect();
|
||||
DBG("Result of connect: Err code=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int UbloxUSBCDMAModem::disconnect()
|
||||
{
|
||||
DBG("Disconnecting from PPP");
|
||||
int ret = m_ppp.disconnect();
|
||||
if(ret)
|
||||
{
|
||||
ERR("Disconnect returned %d, still trying to disconnect", ret);
|
||||
}
|
||||
|
||||
//Ugly but leave dongle time to recover
|
||||
Thread::wait(500);
|
||||
|
||||
#if USE_ONE_PORT
|
||||
ATCommandsInterface::ATResult result;
|
||||
DBG("Starting AT thread");
|
||||
ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
DBG("Trying to hangup");
|
||||
|
||||
#if 0 //Does not appear to work
|
||||
int tries = 10;
|
||||
do
|
||||
{
|
||||
ret = m_at.executeSimple("+++", &result, 1000);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
} while(tries-- && ret);
|
||||
if(!ret)
|
||||
{
|
||||
ret = m_at.executeSimple("ATH", &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_ONE_PORT
|
||||
//Reinit AT parser
|
||||
ret = m_at.init();
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
if(ret)
|
||||
{
|
||||
m_at.close(); // Closing AT parser
|
||||
DBG("AT Parser closed, could not complete disconnection");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
|
||||
#if 0
|
||||
m_at.close(); // Closing AT parser
|
||||
DBG("AT Parser closed");
|
||||
#endif
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::sendSM(const char* number, const char* message)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.send(number, message);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::getSM(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.get(number, message, maxLength);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::getSMCount(size_t* pCount)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.getCount(pCount);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
ATCommandsInterface* UbloxUSBCDMAModem::getATCommandsInterface()
|
||||
{
|
||||
return &m_at;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::power(bool enable)
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
return NET_INVALID; //A pin name has not been provided in the constructor
|
||||
}
|
||||
|
||||
if(!enable) //Will force components to re-init
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
DigitalOut powerGatingOut(m_powerGatingPin);
|
||||
powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool UbloxUSBCDMAModem::power()
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
return true; //Assume power is always on
|
||||
}
|
||||
|
||||
DigitalOut powerGatingOut(m_powerGatingPin);
|
||||
return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::init()
|
||||
{
|
||||
if( !m_dongleConnected )
|
||||
{
|
||||
if(!power())
|
||||
{
|
||||
//Obviously cannot initialize the dongle if it is disconnected...
|
||||
ERR("Power is off");
|
||||
return NET_INVALID;
|
||||
}
|
||||
m_dongleConnected = true;
|
||||
while( !m_dongle.connected() )
|
||||
{
|
||||
m_dongle.tryConnect();
|
||||
Thread::wait(100);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_atOpen)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Starting AT thread if needed");
|
||||
int ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBG("Sending initialisation commands");
|
||||
ret = m_at.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
|
||||
{
|
||||
INFO("Using a UBLOX C200 Dongle");
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("Using an Unknown Dongle");
|
||||
}
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
//Wait for network registration
|
||||
CSSProcessor cssProcessor;
|
||||
do
|
||||
{
|
||||
DBG("Waiting for network registration");
|
||||
ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
|
||||
{
|
||||
Thread::wait(3000);
|
||||
}
|
||||
} while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
|
||||
|
||||
m_atOpen = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::cleanup()
|
||||
{
|
||||
if(m_ppp.isConnected())
|
||||
{
|
||||
WARN("Data connection is still open"); //Try to encourage good behaviour from the user
|
||||
m_ppp.disconnect();
|
||||
}
|
||||
|
||||
m_smsInit = false;
|
||||
// m_linkMonitorInit = false;
|
||||
//We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
|
||||
|
||||
if(m_atOpen)
|
||||
{
|
||||
m_at.close();
|
||||
m_atOpen = false;
|
||||
}
|
||||
|
||||
m_dongle.disconnect();
|
||||
m_dongleConnected = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
/* UbloxUSBCDMAModem.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UBLOXUSBCDMAMODEM_H_
|
||||
#define UBLOXUSBCDMAMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "WANDongle.h"
|
||||
#include "at/ATCommandsInterface.h"
|
||||
#include "USBSerialStream.h"
|
||||
#include "ip/PPPIPInterface.h"
|
||||
#include "sms/CDMASMSInterface.h"
|
||||
#include "CellularModem.h"
|
||||
|
||||
/** u-blox LISA-C200 modem
|
||||
*/
|
||||
class UbloxUSBCDMAModem: public CellularModem
|
||||
{
|
||||
public:
|
||||
/** Create Sprint USB Modem (Sierra Wireless 598U) API instance
|
||||
@param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
|
||||
@param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
|
||||
*/
|
||||
UbloxUSBCDMAModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true, int serial = 0);
|
||||
|
||||
//Internet-related functions
|
||||
|
||||
/** Open a 3G internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
|
||||
|
||||
/** Close the internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int sendSM(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSM(char* number, char* message, size_t maxLength);
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSMCount(size_t* pCount);
|
||||
|
||||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
virtual ATCommandsInterface* getATCommandsInterface();
|
||||
|
||||
/** Switch power on or off
|
||||
In order to use this function, a pin name must have been entered in the constructor
|
||||
@param enable true to switch the dongle on, false to switch it off
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int power(bool enable);
|
||||
|
||||
protected:
|
||||
bool power();
|
||||
|
||||
int init();
|
||||
int cleanup();
|
||||
|
||||
private:
|
||||
WANDongle m_dongle;
|
||||
|
||||
USBSerialStream m_stream;
|
||||
|
||||
ATCommandsInterface m_at;
|
||||
|
||||
CDMASMSInterface m_sms;
|
||||
|
||||
PPPIPInterface m_ppp;
|
||||
|
||||
bool m_dongleConnected;
|
||||
bool m_ipInit;
|
||||
bool m_smsInit;
|
||||
bool m_atOpen;
|
||||
|
||||
PinName m_powerGatingPin;
|
||||
bool m_powerGatingOnWhenPinHigh;
|
||||
};
|
||||
|
||||
|
||||
#endif /* UBLOXUSBCDMAMODEM_H_ */
|
||||
|
|
@ -1,605 +0,0 @@
|
|||
/* UbloxUSBGSMModem.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define __DEBUG__ 3
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxUSBGSMModem.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "UbloxUSBGSMModem.h"
|
||||
#include "UbloxGSMModemInitializer.h"
|
||||
#include "USBHost.h"
|
||||
|
||||
UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/) :
|
||||
m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
|
||||
m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
|
||||
m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
|
||||
m_at(&m_atStream), // Construct ATCommandsInterface with the AT serial channel
|
||||
m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
||||
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
|
||||
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
|
||||
m_ppp(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel
|
||||
m_dongleConnected(false), // Dongle is initially not ready for anything
|
||||
m_ipInit(false), // PPIPInterface connection is initially down
|
||||
m_smsInit(false), // SMSInterface starts un-initialised
|
||||
m_ussdInit(false), // USSDInterface starts un-initialised
|
||||
m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
|
||||
m_atOpen(false), // ATCommandsInterface starts in a closed state
|
||||
m_powerGatingPin(powerGatingPin), // set power gating pin
|
||||
m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh) // set state semantics for power gating pin
|
||||
{
|
||||
USBHost* host = USBHost::getHostInst();
|
||||
m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
|
||||
if( m_powerGatingPin != NC )
|
||||
{
|
||||
power(false); //Dongle will have to be powered on manually
|
||||
}
|
||||
}
|
||||
|
||||
class CREGProcessor : public IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
CREGProcessor() : status(STATUS_REGISTERING)
|
||||
{
|
||||
|
||||
}
|
||||
enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
|
||||
REGISTERING_STATUS getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
private:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
int r;
|
||||
if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
|
||||
{
|
||||
switch(r)
|
||||
{
|
||||
case 1:
|
||||
case 5:
|
||||
status = STATUS_OK;
|
||||
break;
|
||||
case 0:
|
||||
case 2:
|
||||
status = STATUS_REGISTERING;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
status = STATUS_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
volatile REGISTERING_STATUS status;
|
||||
};
|
||||
|
||||
#if 0
|
||||
class COPSProcessor : public IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
COPSProcessor() : valid(false)
|
||||
{
|
||||
network[0] = '\0';
|
||||
apn[0] = '\0';
|
||||
bearer[0] = '\0';
|
||||
}
|
||||
char* getNetwork()
|
||||
{
|
||||
return network;
|
||||
}
|
||||
char* getAPN()
|
||||
{
|
||||
return apn;
|
||||
}
|
||||
char* getBearer()
|
||||
{
|
||||
return bearer;
|
||||
}
|
||||
bool isValid()
|
||||
{
|
||||
return valid;
|
||||
}
|
||||
private:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
int networkId;
|
||||
int bearerId;
|
||||
int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
|
||||
if( s == 2 )
|
||||
{
|
||||
switch(networkId)
|
||||
{
|
||||
case 23415:
|
||||
strcpy(network, "Vodafone UK");
|
||||
strcpy(apn, "pp.vodafone.co.uk");
|
||||
valid = true;
|
||||
break;
|
||||
case 20810:
|
||||
strcpy(network, "SFR FR");
|
||||
strcpy(apn, "websfr");
|
||||
valid = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
switch(bearerId)
|
||||
{
|
||||
case 0: strcpy(bearer, "GSM"); break;
|
||||
case 1: strcpy(bearer, "GSM Compact"); break;
|
||||
case 2: strcpy(bearer, "UTRAN"); break;
|
||||
case 3: strcpy(bearer, "GSM w/EGPRS"); break;
|
||||
case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
|
||||
case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
|
||||
case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
|
||||
case 7: strcpy(bearer, "E-UTRAN"); break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
char network[24];
|
||||
char bearer[24];
|
||||
char apn[24];
|
||||
volatile bool valid;
|
||||
};
|
||||
#endif
|
||||
|
||||
int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* password)
|
||||
{
|
||||
if( !m_ipInit )
|
||||
{
|
||||
m_ipInit = true;
|
||||
m_ppp.init();
|
||||
}
|
||||
m_ppp.setup(user, password, DEFAULT_MSISDN_GSM);
|
||||
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if USE_ONE_PORT
|
||||
m_smsInit = false; //SMS status reset
|
||||
m_ussdInit = false; //USSD status reset
|
||||
m_linkMonitorInit = false; //Link monitor status reset
|
||||
#endif
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
#if 0
|
||||
//Get network info & select corresponding APN
|
||||
COPSProcessor copsProcessor;
|
||||
DBG("Get network info & select APN from DB");
|
||||
ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
|
||||
if(!copsProcessor.isValid())
|
||||
{
|
||||
WARN("Connected to an unknown network, try to connect with default parameters");
|
||||
DBG("Connected with %s", copsProcessor.getBearer());
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer());
|
||||
char cmd[48];
|
||||
int tries = 3;
|
||||
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN());
|
||||
do //Try 3 times because for some reasons it can fail with the K3772-Z dongle
|
||||
{
|
||||
ret = m_at.executeSimple(cmd, &result);
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
} while(ret && --tries);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
DBG("APN set to %s", copsProcessor.getAPN());
|
||||
}
|
||||
#else
|
||||
if(apn != NULL)
|
||||
{
|
||||
char cmd[48];
|
||||
int tries = 30;
|
||||
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
|
||||
do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
|
||||
{
|
||||
ret = m_at.executeSimple(cmd, &result);
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
if(ret)
|
||||
{
|
||||
Thread::wait(500);
|
||||
}
|
||||
} while(ret && --tries);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
DBG("APN set to %s", apn);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//Connect
|
||||
DBG("Connecting");
|
||||
#if 0
|
||||
ret = m_at.executeSimple("ATDT *99#", &result);
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
#endif
|
||||
#if USE_ONE_PORT
|
||||
m_at.close(); // Closing AT parser
|
||||
m_atOpen = false; //Will need to be reinitialized afterwards
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
DBG("AT Parser closed");
|
||||
if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT))
|
||||
{
|
||||
ERR("Could not connect");
|
||||
return ret; //Could not connect
|
||||
}
|
||||
#endif
|
||||
DBG("Connecting PPP");
|
||||
|
||||
ret = m_ppp.connect();
|
||||
DBG("Result of connect: Err code=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int UbloxUSBGSMModem::disconnect()
|
||||
{
|
||||
DBG("Disconnecting from PPP");
|
||||
int ret = m_ppp.disconnect();
|
||||
if(ret)
|
||||
{
|
||||
ERR("Disconnect returned %d, still trying to disconnect", ret);
|
||||
}
|
||||
|
||||
//Ugly but leave dongle time to recover
|
||||
Thread::wait(500);
|
||||
|
||||
#if USE_ONE_PORT
|
||||
ATCommandsInterface::ATResult result;
|
||||
DBG("Starting AT thread");
|
||||
ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
DBG("Trying to hangup");
|
||||
|
||||
#if 0 //Does not appear to work
|
||||
int tries = 10;
|
||||
do
|
||||
{
|
||||
ret = m_at.executeSimple("+++", &result, 1000);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
} while(tries-- && ret);
|
||||
if(!ret)
|
||||
{
|
||||
ret = m_at.executeSimple("ATH", &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_ONE_PORT
|
||||
//Reinit AT parser
|
||||
ret = m_at.init();
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
if(ret)
|
||||
{
|
||||
m_at.close(); // Closing AT parser
|
||||
DBG("AT Parser closed, could not complete disconnection");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
|
||||
#if 0
|
||||
m_at.close(); // Closing AT parser
|
||||
DBG("AT Parser closed");
|
||||
#endif
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::sendSM(const char* number, const char* message)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.send(number, message);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::getSM(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.get(number, message, maxLength);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::getSMCount(size_t* pCount)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.getCount(pCount);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::sendUSSD(const char* command, char* result, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_ussdInit)
|
||||
{
|
||||
ret = m_ussd.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_ussdInit = true;
|
||||
}
|
||||
|
||||
ret = m_ussd.send(command, result, maxLength);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_linkMonitorInit)
|
||||
{
|
||||
ret = m_linkMonitor.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_linkMonitorInit = true;
|
||||
}
|
||||
|
||||
ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
ATCommandsInterface* UbloxUSBGSMModem::getATCommandsInterface()
|
||||
{
|
||||
return &m_at;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::power(bool enable)
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
return NET_INVALID; //A pin name has not been provided in the constructor
|
||||
}
|
||||
|
||||
if(!enable) //Will force components to re-init
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
DigitalOut powerGatingOut(m_powerGatingPin);
|
||||
powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool UbloxUSBGSMModem::power()
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
return true; //Assume power is always on
|
||||
}
|
||||
|
||||
DigitalOut powerGatingOut(m_powerGatingPin);
|
||||
return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::init()
|
||||
{
|
||||
if( !m_dongleConnected )
|
||||
{
|
||||
if(!power())
|
||||
{
|
||||
//Obviously cannot initialize the dongle if it is disconnected...
|
||||
ERR("Power is off");
|
||||
return NET_INVALID;
|
||||
}
|
||||
m_dongleConnected = true;
|
||||
while( !m_dongle.connected() )
|
||||
{
|
||||
m_dongle.tryConnect();
|
||||
Thread::wait(10);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_atOpen)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
DBG("Starting AT thread if needed");
|
||||
int ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBG("Sending initialisation commands");
|
||||
ret = m_at.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
|
||||
{
|
||||
INFO("Using a u-blox LISA-U");
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("Using an Unknown Dongle");
|
||||
}
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
//Wait for network registration
|
||||
CREGProcessor cregProcessor;
|
||||
do
|
||||
{
|
||||
DBG("Waiting for network registration");
|
||||
ret = m_at.execute("AT+CREG?", &cregProcessor, &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
|
||||
{
|
||||
Thread::wait(3000);
|
||||
}
|
||||
} while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
|
||||
if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
|
||||
{
|
||||
ERR("Registration denied");
|
||||
return NET_AUTH;
|
||||
}
|
||||
|
||||
m_atOpen = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBGSMModem::cleanup()
|
||||
{
|
||||
if(m_ppp.isConnected())
|
||||
{
|
||||
WARN("Data connection is still open"); //Try to encourage good behaviour from the user
|
||||
m_ppp.disconnect();
|
||||
}
|
||||
|
||||
m_smsInit = false;
|
||||
m_ussdInit = false;
|
||||
m_linkMonitorInit = false;
|
||||
//We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
|
||||
|
||||
if(m_atOpen)
|
||||
{
|
||||
m_at.close();
|
||||
m_atOpen = false;
|
||||
}
|
||||
|
||||
m_dongle.disconnect();
|
||||
m_dongleConnected = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/* VodafoneUSBModem.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UBLOXUSBGSMMODEM_H_
|
||||
#define UBLOXUSBGSMMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "WANDongle.h"
|
||||
#include "at/ATCommandsInterface.h"
|
||||
#include "serial/usb/USBSerialStream.h"
|
||||
#include "ip/PPPIPInterface.h"
|
||||
#include "sms/GSMSMSInterface.h"
|
||||
#include "ussd/USSDInterface.h"
|
||||
#include "link/LinkMonitor.h"
|
||||
#include "CellularModem.h"
|
||||
|
||||
/** u-blox WCDMA modem (LISA-U200)
|
||||
*/
|
||||
class UbloxUSBGSMModem: public CellularModem
|
||||
{
|
||||
public:
|
||||
/** Create u-blox API instance
|
||||
@param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
|
||||
@param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
|
||||
*/
|
||||
UbloxUSBGSMModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true);
|
||||
|
||||
//Internet-related functions
|
||||
|
||||
/** Open a 3G internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
|
||||
|
||||
/** Close the internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int sendSM(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
|
||||
@param message Pointer to a buffer to store the the incoming message
|
||||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSM(char* number, char* message, size_t maxLength);
|
||||
|
||||
/** Get the number of SMs in the incoming box
|
||||
@param pCount pointer to store the number of unprocessed SMs on
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int getSMCount(size_t* pCount);
|
||||
|
||||
/** Send a USSD command & wait for its result
|
||||
@param command The command to send
|
||||
@param result Buffer in which to store the result
|
||||
@param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int sendUSSD(const char* command, char* result, size_t maxLength);
|
||||
|
||||
/** Get link state
|
||||
@param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
|
||||
@param pRegistrationState pointer to store the current registration state
|
||||
@param pBearer pointer to store the current bearer
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer);
|
||||
|
||||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
virtual ATCommandsInterface* getATCommandsInterface();
|
||||
|
||||
/** Switch power on or off
|
||||
In order to use this function, a pin name must have been entered in the constructor
|
||||
@param enable true to switch the dongle on, false to switch it off
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int power(bool enable);
|
||||
|
||||
protected:
|
||||
bool power(); //< Turn power to USB dongle ON.
|
||||
|
||||
/** Initialise dongle.
|
||||
* The following actions are performed:
|
||||
* 1) Power up
|
||||
* 2) Establish USB connection to dongle
|
||||
* 3) Start AT interface thread
|
||||
* 4) Wait for network registration
|
||||
*/
|
||||
int init();
|
||||
|
||||
/** De-initialise dongle.
|
||||
* The following actions are performed:
|
||||
* 1) Tear down PPP session
|
||||
* 2) Set SMS,USSD, and LinkMonitor subsystems to un-initialised
|
||||
* 3) Close the AT commands interface
|
||||
* 4) Tear down the USB connection to dongle
|
||||
*/
|
||||
int cleanup();
|
||||
|
||||
private:
|
||||
WANDongle m_dongle; //< Interface to USB connected WAN dongle
|
||||
|
||||
USBSerialStream m_atStream; //< Serial interface to AT channel on modem
|
||||
USBSerialStream m_pppStream; //< Serial interface to PPP channel on modem
|
||||
|
||||
ATCommandsInterface m_at; //< Interface to AT commands processing
|
||||
|
||||
GSMSMSInterface m_sms; //< Interface to SMS manager (send/receive etc)
|
||||
USSDInterface m_ussd; //< Interface to USSD manager (send etc)
|
||||
LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
|
||||
|
||||
PPPIPInterface m_ppp; //< Interface to PPP conection manager (IP assignment etc)
|
||||
|
||||
bool m_dongleConnected; //< Is the dongle physically connected (does the USB stack respond)? true/false
|
||||
bool m_ipInit; //< Has PPIPInterface object (m_ppp) been initialised? true/false
|
||||
bool m_smsInit; //< Has SMSInterface object (m_sms) been initialised? true/false
|
||||
bool m_ussdInit; //< Has USSDInterface object (m_ussd) been initialised? true/false
|
||||
bool m_linkMonitorInit; //< Has LinkMonitor object (m_linkMonitor) been initialised? true/false
|
||||
bool m_atOpen; //< Is the interface to the ATCommandsInterface open? true/false
|
||||
|
||||
PinName m_powerGatingPin; //< Pin which toggles power gating
|
||||
bool m_powerGatingOnWhenPinHigh; //< Semantics of power gating (whether high or low toggles power gating)
|
||||
};
|
||||
|
||||
|
||||
#endif /* UBLOXMODEM_H_ */
|
|
@ -1,156 +0,0 @@
|
|||
/* EthernetInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "EthernetInterface.h"
|
||||
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#include "eth_arch.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
#include "mbed.h"
|
||||
|
||||
/* TCP/IP and Network Interface Initialisation */
|
||||
static struct netif netif;
|
||||
|
||||
static char mac_addr[19];
|
||||
static char ip_addr[17] = "\0";
|
||||
static char gateway[17] = "\0";
|
||||
static char networkmask[17] = "\0";
|
||||
static bool use_dhcp = false;
|
||||
|
||||
static Semaphore tcpip_inited(0);
|
||||
static Semaphore netif_linked(0);
|
||||
static Semaphore netif_up(0);
|
||||
|
||||
static void tcpip_init_done(void *arg) {
|
||||
tcpip_inited.release();
|
||||
}
|
||||
|
||||
static void netif_link_callback(struct netif *netif) {
|
||||
if (netif_is_link_up(netif)) {
|
||||
netif_linked.release();
|
||||
}
|
||||
}
|
||||
|
||||
static void netif_status_callback(struct netif *netif) {
|
||||
if (netif_is_up(netif)) {
|
||||
strcpy(ip_addr, inet_ntoa(netif->ip_addr));
|
||||
strcpy(gateway, inet_ntoa(netif->gw));
|
||||
strcpy(networkmask, inet_ntoa(netif->netmask));
|
||||
netif_up.release();
|
||||
}
|
||||
}
|
||||
|
||||
static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) {
|
||||
tcpip_init(tcpip_init_done, NULL);
|
||||
tcpip_inited.wait();
|
||||
|
||||
memset((void*) &netif, 0, sizeof(netif));
|
||||
netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
|
||||
netif_set_default(&netif);
|
||||
|
||||
netif_set_link_callback (&netif, netif_link_callback);
|
||||
netif_set_status_callback(&netif, netif_status_callback);
|
||||
}
|
||||
|
||||
static void set_mac_address(void) {
|
||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
|
||||
snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
|
||||
MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
|
||||
#else
|
||||
char mac[6];
|
||||
mbed_mac_address(mac);
|
||||
snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
#endif
|
||||
}
|
||||
|
||||
int EthernetInterface::init() {
|
||||
use_dhcp = true;
|
||||
set_mac_address();
|
||||
init_netif(NULL, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EthernetInterface::init(const char* ip, const char* mask, const char* gateway) {
|
||||
use_dhcp = false;
|
||||
|
||||
set_mac_address();
|
||||
strcpy(ip_addr, ip);
|
||||
|
||||
ip_addr_t ip_n, mask_n, gateway_n;
|
||||
inet_aton(ip, &ip_n);
|
||||
inet_aton(mask, &mask_n);
|
||||
inet_aton(gateway, &gateway_n);
|
||||
init_netif(&ip_n, &mask_n, &gateway_n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EthernetInterface::connect(unsigned int timeout_ms) {
|
||||
eth_arch_enable_interrupts();
|
||||
|
||||
int inited;
|
||||
if (use_dhcp) {
|
||||
dhcp_start(&netif);
|
||||
|
||||
// Wait for an IP Address
|
||||
// -1: error, 0: timeout
|
||||
inited = netif_up.wait(timeout_ms);
|
||||
} else {
|
||||
netif_set_up(&netif);
|
||||
|
||||
// Wait for the link up
|
||||
inited = netif_linked.wait(timeout_ms);
|
||||
}
|
||||
|
||||
return (inited > 0) ? (0) : (-1);
|
||||
}
|
||||
|
||||
int EthernetInterface::disconnect() {
|
||||
if (use_dhcp) {
|
||||
dhcp_release(&netif);
|
||||
dhcp_stop(&netif);
|
||||
} else {
|
||||
netif_set_down(&netif);
|
||||
}
|
||||
|
||||
eth_arch_disable_interrupts();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* EthernetInterface::getMACAddress() {
|
||||
return mac_addr;
|
||||
}
|
||||
|
||||
char* EthernetInterface::getIPAddress() {
|
||||
return ip_addr;
|
||||
}
|
||||
|
||||
char* EthernetInterface::getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
char* EthernetInterface::getNetworkMask() {
|
||||
return networkmask;
|
||||
}
|
||||
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/* EthernetInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ETHERNETINTERFACE_H_
|
||||
#define ETHERNETINTERFACE_H_
|
||||
|
||||
#if !defined(TARGET_LPC1768) && !defined(TARGET_LPC4088) && !defined(TARGET_LPC4088_DM) && !defined(TARGET_K64F) && !defined(TARGET_K66F) && !defined(TARGET_RZ_A1H) && !defined(TARGET_VK_RZ_A1H) && !defined(TARGET_STM32F4)
|
||||
#error The Ethernet Interface library is not supported on this target
|
||||
#endif
|
||||
|
||||
#include "rtos.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/** Interface using Ethernet to connect to an IP-based network
|
||||
*
|
||||
*/
|
||||
class EthernetInterface {
|
||||
public:
|
||||
/** Initialize the interface with DHCP.
|
||||
* Initialize the interface and configure it to use DHCP (no connection at this point).
|
||||
* \return 0 on success, a negative number on failure
|
||||
*/
|
||||
static int init(); //With DHCP
|
||||
|
||||
/** Initialize the interface with a static IP address.
|
||||
* Initialize the interface and configure it with the following static configuration (no connection at this point).
|
||||
* \param ip the IP address to use
|
||||
* \param mask the IP address mask
|
||||
* \param gateway the gateway to use
|
||||
* \return 0 on success, a negative number on failure
|
||||
*/
|
||||
static int init(const char* ip, const char* mask, const char* gateway);
|
||||
|
||||
/** Connect
|
||||
* Bring the interface up, start DHCP if needed.
|
||||
* \param timeout_ms timeout in ms (default: (15)s).
|
||||
* \return 0 on success, a negative number on failure
|
||||
*/
|
||||
static int connect(unsigned int timeout_ms=15000);
|
||||
|
||||
/** Disconnect
|
||||
* Bring the interface down
|
||||
* \return 0 on success, a negative number on failure
|
||||
*/
|
||||
static int disconnect();
|
||||
|
||||
/** Get the MAC address of your Ethernet interface
|
||||
* \return a pointer to a string containing the MAC address
|
||||
*/
|
||||
static char* getMACAddress();
|
||||
|
||||
/** Get the IP address of your Ethernet interface
|
||||
* \return a pointer to a string containing the IP address
|
||||
*/
|
||||
static char* getIPAddress();
|
||||
|
||||
/** Get the Gateway address of your Ethernet interface
|
||||
* \return a pointer to a string containing the Gateway address
|
||||
*/
|
||||
static char* getGateway();
|
||||
|
||||
/** Get the Network mask of your Ethernet interface
|
||||
* \return a pointer to a string containing the Network mask
|
||||
*/
|
||||
static char* getNetworkMask();
|
||||
};
|
||||
|
||||
#include "TCPSocketConnection.h"
|
||||
#include "TCPSocketServer.h"
|
||||
|
||||
#include "Endpoint.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#endif /* ETHERNETINTERFACE_H_ */
|
|
@ -1,45 +0,0 @@
|
|||
/* EthernetInterface.h */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Architecture specific Ethernet interface
|
||||
// Must be implemented by each target
|
||||
|
||||
#ifndef ETHARCH_H_
|
||||
#define ETHARCH_H_
|
||||
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if DEVICE_EMAC
|
||||
err_t emac_lwip_if_init(struct netif *netif);
|
||||
|
||||
#else /* DEVICE_EMAC */
|
||||
void eth_arch_enable_interrupts(void);
|
||||
void eth_arch_disable_interrupts(void);
|
||||
err_t eth_arch_enetif_init(struct netif *netif);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef ETHARCHINTERFACE_H_
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fsl_port.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
******************************************************************************/
|
||||
void k64f_init_eth_hardware(void)
|
||||
{
|
||||
port_pin_config_t configENET = {0};
|
||||
|
||||
/* Disable MPU. */
|
||||
MPU->CESR &= ~MPU_CESR_VLD_MASK;
|
||||
|
||||
CLOCK_EnableClock(kCLOCK_PortC);
|
||||
CLOCK_EnableClock(kCLOCK_PortB);
|
||||
/* Affects PORTC_PCR16 register */
|
||||
PORT_SetPinMux(PORTC, 16u, kPORT_MuxAlt4);
|
||||
/* Affects PORTC_PCR17 register */
|
||||
PORT_SetPinMux(PORTC, 17u, kPORT_MuxAlt4);
|
||||
/* Affects PORTC_PCR18 register */
|
||||
PORT_SetPinMux(PORTC, 18u, kPORT_MuxAlt4);
|
||||
/* Affects PORTC_PCR19 register */
|
||||
PORT_SetPinMux(PORTC, 19u, kPORT_MuxAlt4);
|
||||
/* Affects PORTB_PCR1 register */
|
||||
PORT_SetPinMux(PORTB, 1u, kPORT_MuxAlt4);
|
||||
|
||||
configENET.openDrainEnable = kPORT_OpenDrainEnable;
|
||||
configENET.mux = kPORT_MuxAlt4;
|
||||
configENET.pullSelect = kPORT_PullUp;
|
||||
/* Ungate the port clock */
|
||||
CLOCK_EnableClock(kCLOCK_PortA);
|
||||
/* Affects PORTB_PCR0 register */
|
||||
PORT_SetPinConfig(PORTB, 0u, &configENET);
|
||||
|
||||
/* Affects PORTA_PCR13 register */
|
||||
PORT_SetPinMux(PORTA, 13u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR12 register */
|
||||
PORT_SetPinMux(PORTA, 12u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR14 register */
|
||||
PORT_SetPinMux(PORTA, 14u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR5 register */
|
||||
PORT_SetPinMux(PORTA, 5u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR16 register */
|
||||
PORT_SetPinMux(PORTA, 16u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR17 register */
|
||||
PORT_SetPinMux(PORTA, 17u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR15 register */
|
||||
PORT_SetPinMux(PORTA, 15u, kPORT_MuxAlt4);
|
||||
/* Affects PORTA_PCR28 register */
|
||||
PORT_SetPinMux(PORTA, 28u, kPORT_MuxAlt4);
|
||||
|
||||
/* Select the Ethernet timestamp clock source */
|
||||
CLOCK_SetEnetTime0Clock(0x2);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* EOF
|
||||
******************************************************************************/
|
||||
|
||||
|
|
@ -1,643 +0,0 @@
|
|||
#include "lwip/opt.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
#include "eth_arch.h"
|
||||
#include "sys_arch.h"
|
||||
|
||||
#include "fsl_phy.h"
|
||||
#include "k64f_emac_config.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mbed_interface.h"
|
||||
|
||||
enet_handle_t g_handle;
|
||||
// TX Buffer descriptors
|
||||
uint8_t *tx_desc_start_addr;
|
||||
// RX Buffer descriptors
|
||||
uint8_t *rx_desc_start_addr;
|
||||
// RX packet buffer pointers
|
||||
struct pbuf *rx_buff[ENET_RX_RING_LEN];
|
||||
// TX packet buffer pointers
|
||||
struct pbuf *tx_buff[ENET_RX_RING_LEN];
|
||||
// RX packet payload pointers
|
||||
uint32_t *rx_ptr[ENET_RX_RING_LEN];
|
||||
|
||||
/********************************************************************************
|
||||
* Internal data
|
||||
********************************************************************************/
|
||||
#define ENET_BuffSizeAlign(n) ENET_ALIGN(n, ENET_BUFF_ALIGNMENT)
|
||||
#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1)))
|
||||
extern void k64f_init_eth_hardware(void);
|
||||
|
||||
/* K64F EMAC driver data structure */
|
||||
struct k64f_enetdata {
|
||||
struct netif *netif; /**< Reference back to LWIP parent netif */
|
||||
sys_sem_t RxReadySem; /**< RX packet ready semaphore */
|
||||
sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
|
||||
sys_mutex_t TXLockMutex; /**< TX critical section mutex */
|
||||
sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
|
||||
uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */
|
||||
};
|
||||
|
||||
static struct k64f_enetdata k64f_enetdata;
|
||||
|
||||
/** \brief Driver transmit and receive thread priorities
|
||||
*
|
||||
* Thread priorities for receive thread and TX cleanup thread. Alter
|
||||
* to prioritize receive or transmit bandwidth. In a heavily loaded
|
||||
* system or with LEIP_DEBUG enabled, the priorities might be better
|
||||
* the same. */
|
||||
#define RX_PRIORITY (osPriorityNormal)
|
||||
#define TX_PRIORITY (osPriorityNormal)
|
||||
#define PHY_PRIORITY (osPriorityNormal)
|
||||
|
||||
/********************************************************************************
|
||||
* Buffer management
|
||||
********************************************************************************/
|
||||
/*
|
||||
* This function will queue a new receive buffer
|
||||
*/
|
||||
static void update_read_buffer(uint8_t *buf)
|
||||
{
|
||||
if (buf != NULL) {
|
||||
g_handle.rxBdCurrent->buffer = buf;
|
||||
}
|
||||
|
||||
/* Clears status. */
|
||||
g_handle.rxBdCurrent->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
|
||||
|
||||
/* Sets the receive buffer descriptor with the empty flag. */
|
||||
g_handle.rxBdCurrent->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
|
||||
|
||||
/* Increases the buffer descriptor to the next one. */
|
||||
if (g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) {
|
||||
g_handle.rxBdCurrent = g_handle.rxBdBase;
|
||||
g_handle.rxBdDirty = g_handle.rxBdBase;
|
||||
} else {
|
||||
g_handle.rxBdCurrent++;
|
||||
g_handle.rxBdDirty++;
|
||||
}
|
||||
|
||||
/* Actives the receive buffer descriptor. */
|
||||
ENET->RDAR = ENET_RDAR_RDAR_MASK;
|
||||
}
|
||||
|
||||
/** \brief Free TX buffers that are complete
|
||||
*
|
||||
* \param[in] k64f_enet Pointer to driver data structure
|
||||
*/
|
||||
static void k64f_tx_reclaim(struct k64f_enetdata *k64f_enet)
|
||||
{
|
||||
uint8_t i = 0 ;
|
||||
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&k64f_enet->TXLockMutex);
|
||||
|
||||
i = k64f_enet->tx_consume_index;
|
||||
// Traverse all descriptors, looking for the ones modified by the uDMA
|
||||
while((i != k64f_enet->tx_produce_index) && (!(g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))) {
|
||||
pbuf_free(tx_buff[i]);
|
||||
if (g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK)
|
||||
g_handle.txBdDirty = g_handle.txBdBase;
|
||||
else
|
||||
g_handle.txBdDirty++;
|
||||
|
||||
i = (i + 1) % ENET_TX_RING_LEN;
|
||||
}
|
||||
|
||||
k64f_enet->tx_consume_index = i;
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&k64f_enet->TXLockMutex);
|
||||
}
|
||||
|
||||
/** \brief Ethernet receive interrupt handler
|
||||
*
|
||||
* This function handles the receive interrupt of K64F.
|
||||
*/
|
||||
void enet_mac_rx_isr()
|
||||
{
|
||||
sys_sem_signal(&k64f_enetdata.RxReadySem);
|
||||
}
|
||||
|
||||
void enet_mac_tx_isr()
|
||||
{
|
||||
sys_sem_signal(&k64f_enetdata.TxCleanSem);
|
||||
}
|
||||
|
||||
void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case kENET_RxEvent:
|
||||
enet_mac_rx_isr();
|
||||
break;
|
||||
case kENET_TxEvent:
|
||||
enet_mac_tx_isr();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Low level init of the MAC and PHY.
|
||||
*
|
||||
* \param[in] netif Pointer to LWIP netif structure
|
||||
*/
|
||||
static err_t low_level_init(struct netif *netif)
|
||||
{
|
||||
struct k64f_enetdata *k64f_enet = netif->state;
|
||||
uint8_t i;
|
||||
uint32_t sysClock;
|
||||
phy_speed_t phy_speed;
|
||||
phy_duplex_t phy_duplex;
|
||||
uint32_t phyAddr = 0;
|
||||
bool link = false;
|
||||
enet_config_t config;
|
||||
|
||||
// Allocate RX descriptors
|
||||
rx_desc_start_addr = (uint8_t *)calloc(1, sizeof(enet_rx_bd_struct_t) * ENET_RX_RING_LEN + ENET_BUFF_ALIGNMENT);
|
||||
if(!rx_desc_start_addr)
|
||||
return ERR_MEM;
|
||||
|
||||
// Allocate TX descriptors
|
||||
tx_desc_start_addr = (uint8_t *)calloc(1, sizeof(enet_tx_bd_struct_t) * ENET_TX_RING_LEN + ENET_BUFF_ALIGNMENT);
|
||||
if(!tx_desc_start_addr)
|
||||
return ERR_MEM;
|
||||
|
||||
rx_desc_start_addr = (uint8_t *)ENET_ALIGN(rx_desc_start_addr, ENET_BUFF_ALIGNMENT);
|
||||
tx_desc_start_addr = (uint8_t *)ENET_ALIGN(tx_desc_start_addr, ENET_BUFF_ALIGNMENT);
|
||||
|
||||
/* Create buffers for each receive BD */
|
||||
for (i = 0; i < ENET_RX_RING_LEN; i++) {
|
||||
rx_buff[i] = pbuf_alloc(PBUF_RAW, ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT, PBUF_RAM);
|
||||
if (NULL == rx_buff[i])
|
||||
return ERR_MEM;
|
||||
|
||||
/* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F
|
||||
RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing
|
||||
a data structure which is internal to lwIP. This might not prove to be a good idea
|
||||
in the long run, but a better fix would probably involve modifying lwIP itself */
|
||||
rx_buff[i]->payload = (void*)ENET_ALIGN((uint32_t)rx_buff[i]->payload, ENET_BUFF_ALIGNMENT);
|
||||
rx_ptr[i] = rx_buff[i]->payload;
|
||||
}
|
||||
|
||||
k64f_enet->tx_consume_index = k64f_enet->tx_produce_index = 0;
|
||||
|
||||
/* prepare the buffer configuration. */
|
||||
enet_buffer_config_t buffCfg = {
|
||||
ENET_RX_RING_LEN,
|
||||
ENET_TX_RING_LEN,
|
||||
ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT),
|
||||
0,
|
||||
(volatile enet_rx_bd_struct_t *)rx_desc_start_addr,
|
||||
(volatile enet_tx_bd_struct_t *)tx_desc_start_addr,
|
||||
(uint8_t *)&rx_ptr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
k64f_init_eth_hardware();
|
||||
|
||||
sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk);
|
||||
|
||||
ENET_GetDefaultConfig(&config);
|
||||
|
||||
PHY_Init(ENET, 0, sysClock);
|
||||
PHY_GetLinkStatus(ENET, phyAddr, &link);
|
||||
if (link)
|
||||
{
|
||||
/* Get link information from PHY */
|
||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
|
||||
/* Change the MII speed and duplex for actual link status. */
|
||||
config.miiSpeed = (enet_mii_speed_t)phy_speed;
|
||||
config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
|
||||
config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
|
||||
}
|
||||
config.rxMaxFrameLen = ENET_ETH_MAX_FLEN;
|
||||
config.macSpecialConfig = kENET_ControlFlowControlEnable;
|
||||
config.txAccelerConfig = kENET_TxAccelIsShift16Enabled;
|
||||
config.rxAccelerConfig = kENET_RxAccelisShift16Enabled | kENET_RxAccelMacCheckEnabled;
|
||||
ENET_Init(ENET, &g_handle, &config, &buffCfg, netif->hwaddr, sysClock);
|
||||
ENET_SetCallback(&g_handle, ethernet_callback, netif);
|
||||
ENET_ActiveRead(ENET);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is the ethernet packet send function. It calls
|
||||
* etharp_output after checking link status.
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure for this enetif
|
||||
* \param[in] q Pointer to pbug to send
|
||||
* \param[in] ipaddr IP address
|
||||
* \return ERR_OK or error code
|
||||
*/
|
||||
err_t k64f_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
{
|
||||
/* Only send packet is link is up */
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP)
|
||||
return etharp_output(netif, q, ipaddr);
|
||||
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
/** \brief Allocates a pbuf and returns the data from the incoming packet.
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure
|
||||
* \param[in] idx index of packet to be read
|
||||
* \return a pbuf filled with the received packet (including MAC header)
|
||||
*/
|
||||
static struct pbuf *k64f_low_level_input(struct netif *netif, int idx)
|
||||
{
|
||||
volatile enet_rx_bd_struct_t *bdPtr = g_handle.rxBdCurrent;
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf *temp_rxbuf = NULL;
|
||||
u32_t length = 0;
|
||||
const u16_t err_mask = ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK | ENET_BUFFDESCRIPTOR_RX_CRC_MASK |
|
||||
ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK | ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK;
|
||||
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&k64f_enet->TXLockMutex);
|
||||
#endif
|
||||
|
||||
/* Determine if a frame has been received */
|
||||
if ((bdPtr->control & err_mask) != 0) {
|
||||
#if LINK_STATS
|
||||
if ((bdPtr->control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK) != 0)
|
||||
LINK_STATS_INC(link.lenerr);
|
||||
else
|
||||
LINK_STATS_INC(link.chkerr);
|
||||
#endif
|
||||
LINK_STATS_INC(link.drop);
|
||||
/* Re-use the same buffer in case of error */
|
||||
update_read_buffer(NULL);
|
||||
} else {
|
||||
/* A packet is waiting, get length */
|
||||
length = bdPtr->length;
|
||||
|
||||
/* Zero-copy */
|
||||
p = rx_buff[idx];
|
||||
p->len = length;
|
||||
|
||||
/* Attempt to queue new buffer */
|
||||
temp_rxbuf = pbuf_alloc(PBUF_RAW, ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT, PBUF_RAM);
|
||||
if (NULL == temp_rxbuf) {
|
||||
/* Drop frame (out of memory) */
|
||||
LINK_STATS_INC(link.drop);
|
||||
|
||||
/* Re-queue the same buffer */
|
||||
update_read_buffer(NULL);
|
||||
|
||||
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
|
||||
("k64f_low_level_input: Packet index %d dropped for OOM\n",
|
||||
idx));
|
||||
#ifdef LOCK_RX_THREAD
|
||||
sys_mutex_unlock(&k64f_enet->TXLockMutex);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rx_buff[idx] = temp_rxbuf;
|
||||
/* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F
|
||||
RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing
|
||||
a data structure which is internal to lwIP. This might not prove to be a good idea
|
||||
in the long run, but a better fix would probably involve modifying lwIP itself */
|
||||
rx_buff[idx]->payload = (void*)ENET_ALIGN((uint32_t)rx_buff[idx]->payload, ENET_BUFF_ALIGNMENT);
|
||||
rx_ptr[idx] = rx_buff[idx]->payload;
|
||||
|
||||
update_read_buffer(rx_buff[idx]->payload);
|
||||
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
|
||||
("k64f_low_level_input: Packet received: %p, size %d (index=%d)\n",
|
||||
p, length, idx));
|
||||
|
||||
/* Save size */
|
||||
p->tot_len = (u16_t) length;
|
||||
LINK_STATS_INC(link.recv);
|
||||
}
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
sys_mutex_unlock(&k64f_enet->TXLockMutex);
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/** \brief Attempt to read a packet from the EMAC interface.
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure
|
||||
* \param[in] idx index of packet to be read
|
||||
*/
|
||||
void k64f_enetif_input(struct netif *netif, int idx)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
struct pbuf *p;
|
||||
|
||||
/* move received packet into a new pbuf */
|
||||
p = k64f_low_level_input(netif, idx);
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = (struct eth_hdr*)p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
case ETHTYPE_IP:
|
||||
case ETHTYPE_ARP:
|
||||
#if PPPOE_SUPPORT
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("k64f_enetif_input: IP input error\n"));
|
||||
/* Free buffer */
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Return buffer */
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Packet reception task
|
||||
*
|
||||
* This task is called when a packet is received. It will
|
||||
* pass the packet to the LWIP core.
|
||||
*
|
||||
* \param[in] pvParameters pointer to the interface data
|
||||
*/
|
||||
static void packet_rx(void* pvParameters) {
|
||||
struct k64f_enetdata *k64f_enet = pvParameters;
|
||||
int idx = 0;
|
||||
|
||||
while (1) {
|
||||
/* Wait for receive task to wakeup */
|
||||
sys_arch_sem_wait(&k64f_enet->RxReadySem, 0);
|
||||
|
||||
while ((g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) == 0) {
|
||||
k64f_enetif_input(k64f_enet->netif, idx);
|
||||
idx = (idx + 1) % ENET_RX_RING_LEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Transmit cleanup task
|
||||
*
|
||||
* This task is called when a transmit interrupt occurs and
|
||||
* reclaims the pbuf and descriptor used for the packet once
|
||||
* the packet has been transferred.
|
||||
*
|
||||
* \param[in] pvParameters pointer to the interface data
|
||||
*/
|
||||
static void packet_tx(void* pvParameters) {
|
||||
struct k64f_enetdata *k64f_enet = pvParameters;
|
||||
|
||||
while (1) {
|
||||
/* Wait for transmit cleanup task to wakeup */
|
||||
sys_arch_sem_wait(&k64f_enet->TxCleanSem, 0);
|
||||
k64f_tx_reclaim(k64f_enet);
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Low level output of a packet. Never call this from an
|
||||
* interrupt context, as it may block until TX descriptors
|
||||
* become available.
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure for this netif
|
||||
* \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
||||
* \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
|
||||
*/
|
||||
static err_t k64f_low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct k64f_enetdata *k64f_enet = netif->state;
|
||||
struct pbuf *q;
|
||||
struct pbuf *temp_pbuf;
|
||||
uint8_t *psend = NULL, *dst;
|
||||
|
||||
|
||||
temp_pbuf = pbuf_alloc(PBUF_RAW, p->tot_len + ENET_BUFF_ALIGNMENT, PBUF_RAM);
|
||||
if (NULL == temp_pbuf)
|
||||
return ERR_MEM;
|
||||
|
||||
/* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F
|
||||
RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing
|
||||
a data structure which is internal to lwIP. This might not prove to be a good idea
|
||||
in the long run, but a better fix would probably involve modifying lwIP itself */
|
||||
psend = (uint8_t *)ENET_ALIGN((uint32_t)temp_pbuf->payload, ENET_BUFF_ALIGNMENT);
|
||||
|
||||
for (q = p, dst = psend; q != NULL; q = q->next) {
|
||||
MEMCPY(dst, q->payload, q->len);
|
||||
dst += q->len;
|
||||
}
|
||||
|
||||
/* Wait until a descriptor is available for the transfer. */
|
||||
/* THIS WILL BLOCK UNTIL THERE ARE A DESCRIPTOR AVAILABLE */
|
||||
while (g_handle.txBdCurrent->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)
|
||||
osSemaphoreWait(k64f_enet->xTXDCountSem.id, osWaitForever);
|
||||
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&k64f_enet->TXLockMutex);
|
||||
|
||||
/* Save the buffer so that it can be freed when transmit is done */
|
||||
tx_buff[k64f_enet->tx_produce_index] = temp_pbuf;
|
||||
k64f_enet->tx_produce_index = (k64f_enet->tx_produce_index + 1) % ENET_TX_RING_LEN;
|
||||
|
||||
/* Setup transfers */
|
||||
g_handle.txBdCurrent->buffer = psend;
|
||||
g_handle.txBdCurrent->length = p->tot_len;
|
||||
g_handle.txBdCurrent->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
|
||||
|
||||
/* Increase the buffer descriptor address. */
|
||||
if (g_handle.txBdCurrent->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK)
|
||||
g_handle.txBdCurrent = g_handle.txBdBase;
|
||||
else
|
||||
g_handle.txBdCurrent++;
|
||||
|
||||
/* Active the transmit buffer descriptor. */
|
||||
ENET->TDAR = ENET_TDAR_TDAR_MASK;
|
||||
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&k64f_enet->TXLockMutex);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PHY task: monitor link
|
||||
*******************************************************************************/
|
||||
|
||||
#define PHY_TASK_PERIOD_MS 200
|
||||
#define STATE_UNKNOWN (-1)
|
||||
|
||||
typedef struct {
|
||||
int connected;
|
||||
phy_speed_t speed;
|
||||
phy_duplex_t duplex;
|
||||
} PHY_STATE;
|
||||
|
||||
int phy_link_status() {
|
||||
bool connection_status;
|
||||
uint32_t phyAddr = 0;
|
||||
|
||||
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
|
||||
return (int)connection_status;
|
||||
}
|
||||
|
||||
static void k64f_phy_task(void *data) {
|
||||
struct netif *netif = (struct netif*)data;
|
||||
bool connection_status;
|
||||
PHY_STATE crt_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
|
||||
PHY_STATE prev_state;
|
||||
uint32_t phyAddr = 0;
|
||||
uint32_t rcr = 0;
|
||||
|
||||
prev_state = crt_state;
|
||||
while (true) {
|
||||
// Get current status
|
||||
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
|
||||
crt_state.connected = connection_status ? 1 : 0;
|
||||
// Get the actual PHY link speed
|
||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
|
||||
|
||||
// Compare with previous state
|
||||
if (crt_state.connected != prev_state.connected) {
|
||||
if (crt_state.connected)
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
|
||||
else
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
||||
}
|
||||
|
||||
if (crt_state.speed != prev_state.speed) {
|
||||
rcr = ENET->RCR;
|
||||
rcr &= ~ENET_RCR_RMII_10T_MASK;
|
||||
rcr |= ENET_RCR_RMII_10T(!crt_state.speed);
|
||||
ENET->RCR = rcr;
|
||||
}
|
||||
|
||||
prev_state = crt_state;
|
||||
osDelay(PHY_TASK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* network interface.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param[in] netif the lwip network interface structure for this netif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t eth_arch_enetif_init(struct netif *netif)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
k64f_enetdata.netif = netif;
|
||||
|
||||
/* set MAC hardware address */
|
||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
|
||||
netif->hwaddr[0] = MBED_MAC_ADDR_0;
|
||||
netif->hwaddr[1] = MBED_MAC_ADDR_1;
|
||||
netif->hwaddr[2] = MBED_MAC_ADDR_2;
|
||||
netif->hwaddr[3] = MBED_MAC_ADDR_3;
|
||||
netif->hwaddr[4] = MBED_MAC_ADDR_4;
|
||||
netif->hwaddr[5] = MBED_MAC_ADDR_5;
|
||||
#else
|
||||
mbed_mac_address((char *)netif->hwaddr);
|
||||
#endif
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
// TODOETH: check if the flags are correct below
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
|
||||
|
||||
/* Initialize the hardware */
|
||||
netif->state = &k64f_enetdata;
|
||||
err = low_level_init(netif);
|
||||
if (err != ERR_OK)
|
||||
return err;
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwipk64f";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->output = k64f_etharp_output;
|
||||
netif->linkoutput = k64f_low_level_output;
|
||||
|
||||
/* CMSIS-RTOS, start tasks */
|
||||
#ifdef CMSIS_OS_RTX
|
||||
memset(k64f_enetdata.xTXDCountSem.data, 0, sizeof(k64f_enetdata.xTXDCountSem.data));
|
||||
k64f_enetdata.xTXDCountSem.def.semaphore = k64f_enetdata.xTXDCountSem.data;
|
||||
#endif
|
||||
k64f_enetdata.xTXDCountSem.id = osSemaphoreCreate(&k64f_enetdata.xTXDCountSem.def, ENET_TX_RING_LEN);
|
||||
|
||||
LWIP_ASSERT("xTXDCountSem creation error", (k64f_enetdata.xTXDCountSem.id != NULL));
|
||||
|
||||
err = sys_mutex_new(&k64f_enetdata.TXLockMutex);
|
||||
LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
|
||||
|
||||
/* Packet receive task */
|
||||
err = sys_sem_new(&k64f_enetdata.RxReadySem, 0);
|
||||
LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK));
|
||||
sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
|
||||
|
||||
/* Transmit cleanup task */
|
||||
err = sys_sem_new(&k64f_enetdata.TxCleanSem, 0);
|
||||
LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
|
||||
sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
|
||||
|
||||
/* PHY monitoring task */
|
||||
sys_thread_new("phy_thread", k64f_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_PRIORITY);
|
||||
|
||||
/* Allow the PHY task to detect the initial link state and set up the proper flags */
|
||||
osDelay(10);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void eth_arch_enable_interrupts(void) {
|
||||
//NVIC_SetPriority(ENET_Receive_IRQn, 6U);
|
||||
//NVIC_SetPriority(ENET_Transmit_IRQn, 6U);
|
||||
}
|
||||
|
||||
void eth_arch_disable_interrupts(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef K64F_EMAC_CONFIG_H__
|
||||
#define K64F_EMAC_CONFIG_H__
|
||||
|
||||
#include "fsl_enet.h"
|
||||
|
||||
#define ENET_RX_RING_LEN (16)
|
||||
#define ENET_TX_RING_LEN (8)
|
||||
|
||||
#define ENET_ETH_MAX_FLEN (1522) // recommended size for a VLAN frame
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int phy_link_status(void);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #define K64F_EMAC_CONFIG_H__
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPOPTS_CONF_H
|
||||
#define LWIPOPTS_CONF_H
|
||||
|
||||
#include "k64f_emac_config.h"
|
||||
|
||||
#define LWIP_TRANSPORT_ETHERNET 1
|
||||
#define ETH_PAD_SIZE 2
|
||||
|
||||
#define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN)
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,661 +0,0 @@
|
|||
/**********************************************************************
|
||||
* $Id$ lpc17xx_emac.h 2010-05-21
|
||||
*//**
|
||||
* @file lpc17xx_emac.h
|
||||
* @brief Contains all macro definitions and function prototypes
|
||||
* support for Ethernet MAC firmware library on LPC17xx
|
||||
* @version 2.0
|
||||
* @date 21. May. 2010
|
||||
* @author NXP MCU SW Application Team
|
||||
*
|
||||
* Copyright(C) 2010, NXP Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
***********************************************************************
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* products. This software is supplied "AS IS" without any warranties.
|
||||
* NXP Semiconductors assumes no responsibility or liability for the
|
||||
* use of the software, conveys no license or title under any patent,
|
||||
* copyright, or mask work right to the product. NXP Semiconductors
|
||||
* reserves the right to make changes in the software without
|
||||
* notification. NXP Semiconductors also make no representation or
|
||||
* warranty that such application will be suitable for the specified
|
||||
* use without further testing or modification.
|
||||
**********************************************************************/
|
||||
|
||||
/* Peripheral group ----------------------------------------------------------- */
|
||||
/** @defgroup EMAC EMAC (Ethernet Media Access Controller)
|
||||
* @ingroup LPC1700CMSIS_FwLib_Drivers
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef LPC17XX_EMAC_H_
|
||||
#define LPC17XX_EMAC_H_
|
||||
|
||||
/* Includes ------------------------------------------------------------------- */
|
||||
#include "cmsis.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define MCB_LPC_1768
|
||||
//#define IAR_LPC_1768
|
||||
|
||||
/* Public Macros -------------------------------------------------------------- */
|
||||
/** @defgroup EMAC_Public_Macros EMAC Public Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/* EMAC PHY status type definitions */
|
||||
#define EMAC_PHY_STAT_LINK (0) /**< Link Status */
|
||||
#define EMAC_PHY_STAT_SPEED (1) /**< Speed Status */
|
||||
#define EMAC_PHY_STAT_DUP (2) /**< Duplex Status */
|
||||
|
||||
/* EMAC PHY device Speed definitions */
|
||||
#define EMAC_MODE_AUTO (0) /**< Auto-negotiation mode */
|
||||
#define EMAC_MODE_10M_FULL (1) /**< 10Mbps FullDuplex mode */
|
||||
#define EMAC_MODE_10M_HALF (2) /**< 10Mbps HalfDuplex mode */
|
||||
#define EMAC_MODE_100M_FULL (3) /**< 100Mbps FullDuplex mode */
|
||||
#define EMAC_MODE_100M_HALF (4) /**< 100Mbps HalfDuplex mode */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/* Private Macros ------------------------------------------------------------- */
|
||||
/** @defgroup EMAC_Private_Macros EMAC Private Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/* EMAC Memory Buffer configuration for 16K Ethernet RAM */
|
||||
#define EMAC_NUM_RX_FRAG 4 /**< Num.of RX Fragments 4*1536= 6.0kB */
|
||||
#define EMAC_NUM_TX_FRAG 3 /**< Num.of TX Fragments 3*1536= 4.6kB */
|
||||
#define EMAC_ETH_MAX_FLEN 1536 /**< Max. Ethernet Frame Size */
|
||||
#define EMAC_TX_FRAME_TOUT 0x00100000 /**< Frame Transmit timeout count */
|
||||
|
||||
/* --------------------- BIT DEFINITIONS -------------------------------------- */
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MAC Configuration Register 1
|
||||
**********************************************************************/
|
||||
#define EMAC_MAC1_REC_EN 0x00000001 /**< Receive Enable */
|
||||
#define EMAC_MAC1_PASS_ALL 0x00000002 /**< Pass All Receive Frames */
|
||||
#define EMAC_MAC1_RX_FLOWC 0x00000004 /**< RX Flow Control */
|
||||
#define EMAC_MAC1_TX_FLOWC 0x00000008 /**< TX Flow Control */
|
||||
#define EMAC_MAC1_LOOPB 0x00000010 /**< Loop Back Mode */
|
||||
#define EMAC_MAC1_RES_TX 0x00000100 /**< Reset TX Logic */
|
||||
#define EMAC_MAC1_RES_MCS_TX 0x00000200 /**< Reset MAC TX Control Sublayer */
|
||||
#define EMAC_MAC1_RES_RX 0x00000400 /**< Reset RX Logic */
|
||||
#define EMAC_MAC1_RES_MCS_RX 0x00000800 /**< Reset MAC RX Control Sublayer */
|
||||
#define EMAC_MAC1_SIM_RES 0x00004000 /**< Simulation Reset */
|
||||
#define EMAC_MAC1_SOFT_RES 0x00008000 /**< Soft Reset MAC */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MAC Configuration Register 2
|
||||
**********************************************************************/
|
||||
#define EMAC_MAC2_FULL_DUP 0x00000001 /**< Full-Duplex Mode */
|
||||
#define EMAC_MAC2_FRM_LEN_CHK 0x00000002 /**< Frame Length Checking */
|
||||
#define EMAC_MAC2_HUGE_FRM_EN 0x00000004 /**< Huge Frame Enable */
|
||||
#define EMAC_MAC2_DLY_CRC 0x00000008 /**< Delayed CRC Mode */
|
||||
#define EMAC_MAC2_CRC_EN 0x00000010 /**< Append CRC to every Frame */
|
||||
#define EMAC_MAC2_PAD_EN 0x00000020 /**< Pad all Short Frames */
|
||||
#define EMAC_MAC2_VLAN_PAD_EN 0x00000040 /**< VLAN Pad Enable */
|
||||
#define EMAC_MAC2_ADET_PAD_EN 0x00000080 /**< Auto Detect Pad Enable */
|
||||
#define EMAC_MAC2_PPREAM_ENF 0x00000100 /**< Pure Preamble Enforcement */
|
||||
#define EMAC_MAC2_LPREAM_ENF 0x00000200 /**< Long Preamble Enforcement */
|
||||
#define EMAC_MAC2_NO_BACKOFF 0x00001000 /**< No Backoff Algorithm */
|
||||
#define EMAC_MAC2_BACK_PRESSURE 0x00002000 /**< Backoff Presurre / No Backoff */
|
||||
#define EMAC_MAC2_EXCESS_DEF 0x00004000 /**< Excess Defer */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Back-to-Back Inter-Packet-Gap Register
|
||||
**********************************************************************/
|
||||
/** Programmable field representing the nibble time offset of the minimum possible period
|
||||
* between the end of any transmitted packet to the beginning of the next */
|
||||
#define EMAC_IPGT_BBIPG(n) (n&0x7F)
|
||||
/** Recommended value for Full Duplex of Programmable field representing the nibble time
|
||||
* offset of the minimum possible period between the end of any transmitted packet to the
|
||||
* beginning of the next */
|
||||
#define EMAC_IPGT_FULL_DUP (EMAC_IPGT_BBIPG(0x15))
|
||||
/** Recommended value for Half Duplex of Programmable field representing the nibble time
|
||||
* offset of the minimum possible period between the end of any transmitted packet to the
|
||||
* beginning of the next */
|
||||
#define EMAC_IPGT_HALF_DUP (EMAC_IPGT_BBIPG(0x12))
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Non Back-to-Back Inter-Packet-Gap Register
|
||||
**********************************************************************/
|
||||
/** Programmable field representing the Non-Back-to-Back Inter-Packet-Gap */
|
||||
#define EMAC_IPGR_NBBIPG_P2(n) (n&0x7F)
|
||||
/** Recommended value for Programmable field representing the Non-Back-to-Back Inter-Packet-Gap Part 1 */
|
||||
#define EMAC_IPGR_P2_DEF (EMAC_IPGR_NBBIPG_P2(0x12))
|
||||
/** Programmable field representing the optional carrierSense window referenced in
|
||||
* IEEE 802.3/4.2.3.2.1 'Carrier Deference' */
|
||||
#define EMAC_IPGR_NBBIPG_P1(n) ((n&0x7F)<<8)
|
||||
/** Recommended value for Programmable field representing the Non-Back-to-Back Inter-Packet-Gap Part 2 */
|
||||
#define EMAC_IPGR_P1_DEF EMAC_IPGR_NBBIPG_P1(0x0C)
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Collision Window/Retry Register
|
||||
**********************************************************************/
|
||||
/** Programmable field specifying the number of retransmission attempts following a collision before
|
||||
* aborting the packet due to excessive collisions */
|
||||
#define EMAC_CLRT_MAX_RETX(n) (n&0x0F)
|
||||
/** Programmable field representing the slot time or collision window during which collisions occur
|
||||
* in properly configured networks */
|
||||
#define EMAC_CLRT_COLL(n) ((n&0x3F)<<8)
|
||||
/** Default value for Collision Window / Retry register */
|
||||
#define EMAC_CLRT_DEF ((EMAC_CLRT_MAX_RETX(0x0F))|(EMAC_CLRT_COLL(0x37)))
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Maximum Frame Register
|
||||
**********************************************************************/
|
||||
/** Represents a maximum receive frame of 1536 octets */
|
||||
#define EMAC_MAXF_MAXFRMLEN(n) (n&0xFFFF)
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Support Register
|
||||
**********************************************************************/
|
||||
#define EMAC_SUPP_SPEED 0x00000100 /**< Reduced MII Logic Current Speed */
|
||||
#define EMAC_SUPP_RES_RMII 0x00000800 /**< Reset Reduced MII Logic */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Test Register
|
||||
**********************************************************************/
|
||||
#define EMAC_TEST_SHCUT_PQUANTA 0x00000001 /**< Shortcut Pause Quanta */
|
||||
#define EMAC_TEST_TST_PAUSE 0x00000002 /**< Test Pause */
|
||||
#define EMAC_TEST_TST_BACKP 0x00000004 /**< Test Back Pressure */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MII Management Configuration Register
|
||||
**********************************************************************/
|
||||
#define EMAC_MCFG_SCAN_INC 0x00000001 /**< Scan Increment PHY Address */
|
||||
#define EMAC_MCFG_SUPP_PREAM 0x00000002 /**< Suppress Preamble */
|
||||
#define EMAC_MCFG_CLK_SEL(n) ((n&0x0F)<<2) /**< Clock Select Field */
|
||||
#define EMAC_MCFG_RES_MII 0x00008000 /**< Reset MII Management Hardware */
|
||||
#define EMAC_MCFG_MII_MAXCLK 2500000UL /**< MII Clock max */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MII Management Command Register
|
||||
**********************************************************************/
|
||||
#define EMAC_MCMD_READ 0x00000001 /**< MII Read */
|
||||
#define EMAC_MCMD_SCAN 0x00000002 /**< MII Scan continuously */
|
||||
|
||||
#define EMAC_MII_WR_TOUT 0x00050000 /**< MII Write timeout count */
|
||||
#define EMAC_MII_RD_TOUT 0x00050000 /**< MII Read timeout count */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MII Management Address Register
|
||||
**********************************************************************/
|
||||
#define EMAC_MADR_REG_ADR(n) (n&0x1F) /**< MII Register Address field */
|
||||
#define EMAC_MADR_PHY_ADR(n) ((n&0x1F)<<8) /**< PHY Address Field */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MII Management Write Data Register
|
||||
**********************************************************************/
|
||||
#define EMAC_MWTD_DATA(n) (n&0xFFFF) /**< Data field for MMI Management Write Data register */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MII Management Read Data Register
|
||||
**********************************************************************/
|
||||
#define EMAC_MRDD_DATA(n) (n&0xFFFF) /**< Data field for MMI Management Read Data register */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for MII Management Indicators Register
|
||||
**********************************************************************/
|
||||
#define EMAC_MIND_BUSY 0x00000001 /**< MII is Busy */
|
||||
#define EMAC_MIND_SCAN 0x00000002 /**< MII Scanning in Progress */
|
||||
#define EMAC_MIND_NOT_VAL 0x00000004 /**< MII Read Data not valid */
|
||||
#define EMAC_MIND_MII_LINK_FAIL 0x00000008 /**< MII Link Failed */
|
||||
|
||||
/* Station Address 0 Register */
|
||||
/* Station Address 1 Register */
|
||||
/* Station Address 2 Register */
|
||||
|
||||
|
||||
/* Control register definitions --------------------------------------------------------------------------- */
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Command Register
|
||||
**********************************************************************/
|
||||
#define EMAC_CR_RX_EN 0x00000001 /**< Enable Receive */
|
||||
#define EMAC_CR_TX_EN 0x00000002 /**< Enable Transmit */
|
||||
#define EMAC_CR_REG_RES 0x00000008 /**< Reset Host Registers */
|
||||
#define EMAC_CR_TX_RES 0x00000010 /**< Reset Transmit Datapath */
|
||||
#define EMAC_CR_RX_RES 0x00000020 /**< Reset Receive Datapath */
|
||||
#define EMAC_CR_PASS_RUNT_FRM 0x00000040 /**< Pass Runt Frames */
|
||||
#define EMAC_CR_PASS_RX_FILT 0x00000080 /**< Pass RX Filter */
|
||||
#define EMAC_CR_TX_FLOW_CTRL 0x00000100 /**< TX Flow Control */
|
||||
#define EMAC_CR_RMII 0x00000200 /**< Reduced MII Interface */
|
||||
#define EMAC_CR_FULL_DUP 0x00000400 /**< Full Duplex */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Status Register
|
||||
**********************************************************************/
|
||||
#define EMAC_SR_RX_EN 0x00000001 /**< Enable Receive */
|
||||
#define EMAC_SR_TX_EN 0x00000002 /**< Enable Transmit */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Transmit Status Vector 0 Register
|
||||
**********************************************************************/
|
||||
#define EMAC_TSV0_CRC_ERR 0x00000001 /**< CRC error */
|
||||
#define EMAC_TSV0_LEN_CHKERR 0x00000002 /**< Length Check Error */
|
||||
#define EMAC_TSV0_LEN_OUTRNG 0x00000004 /**< Length Out of Range */
|
||||
#define EMAC_TSV0_DONE 0x00000008 /**< Tramsmission Completed */
|
||||
#define EMAC_TSV0_MCAST 0x00000010 /**< Multicast Destination */
|
||||
#define EMAC_TSV0_BCAST 0x00000020 /**< Broadcast Destination */
|
||||
#define EMAC_TSV0_PKT_DEFER 0x00000040 /**< Packet Deferred */
|
||||
#define EMAC_TSV0_EXC_DEFER 0x00000080 /**< Excessive Packet Deferral */
|
||||
#define EMAC_TSV0_EXC_COLL 0x00000100 /**< Excessive Collision */
|
||||
#define EMAC_TSV0_LATE_COLL 0x00000200 /**< Late Collision Occured */
|
||||
#define EMAC_TSV0_GIANT 0x00000400 /**< Giant Frame */
|
||||
#define EMAC_TSV0_UNDERRUN 0x00000800 /**< Buffer Underrun */
|
||||
#define EMAC_TSV0_BYTES 0x0FFFF000 /**< Total Bytes Transferred */
|
||||
#define EMAC_TSV0_CTRL_FRAME 0x10000000 /**< Control Frame */
|
||||
#define EMAC_TSV0_PAUSE 0x20000000 /**< Pause Frame */
|
||||
#define EMAC_TSV0_BACK_PRESS 0x40000000 /**< Backpressure Method Applied */
|
||||
#define EMAC_TSV0_VLAN 0x80000000 /**< VLAN Frame */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Transmit Status Vector 1 Register
|
||||
**********************************************************************/
|
||||
#define EMAC_TSV1_BYTE_CNT 0x0000FFFF /**< Transmit Byte Count */
|
||||
#define EMAC_TSV1_COLL_CNT 0x000F0000 /**< Transmit Collision Count */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Receive Status Vector Register
|
||||
**********************************************************************/
|
||||
#define EMAC_RSV_BYTE_CNT 0x0000FFFF /**< Receive Byte Count */
|
||||
#define EMAC_RSV_PKT_IGNORED 0x00010000 /**< Packet Previously Ignored */
|
||||
#define EMAC_RSV_RXDV_SEEN 0x00020000 /**< RXDV Event Previously Seen */
|
||||
#define EMAC_RSV_CARR_SEEN 0x00040000 /**< Carrier Event Previously Seen */
|
||||
#define EMAC_RSV_REC_CODEV 0x00080000 /**< Receive Code Violation */
|
||||
#define EMAC_RSV_CRC_ERR 0x00100000 /**< CRC Error */
|
||||
#define EMAC_RSV_LEN_CHKERR 0x00200000 /**< Length Check Error */
|
||||
#define EMAC_RSV_LEN_OUTRNG 0x00400000 /**< Length Out of Range */
|
||||
#define EMAC_RSV_REC_OK 0x00800000 /**< Frame Received OK */
|
||||
#define EMAC_RSV_MCAST 0x01000000 /**< Multicast Frame */
|
||||
#define EMAC_RSV_BCAST 0x02000000 /**< Broadcast Frame */
|
||||
#define EMAC_RSV_DRIB_NIBB 0x04000000 /**< Dribble Nibble */
|
||||
#define EMAC_RSV_CTRL_FRAME 0x08000000 /**< Control Frame */
|
||||
#define EMAC_RSV_PAUSE 0x10000000 /**< Pause Frame */
|
||||
#define EMAC_RSV_UNSUPP_OPC 0x20000000 /**< Unsupported Opcode */
|
||||
#define EMAC_RSV_VLAN 0x40000000 /**< VLAN Frame */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Flow Control Counter Register
|
||||
**********************************************************************/
|
||||
#define EMAC_FCC_MIRR_CNT(n) (n&0xFFFF) /**< Mirror Counter */
|
||||
#define EMAC_FCC_PAUSE_TIM(n) ((n&0xFFFF)<<16) /**< Pause Timer */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Flow Control Status Register
|
||||
**********************************************************************/
|
||||
#define EMAC_FCS_MIRR_CNT(n) (n&0xFFFF) /**< Mirror Counter Current */
|
||||
|
||||
|
||||
/* Receive filter register definitions -------------------------------------------------------- */
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Receive Filter Control Register
|
||||
**********************************************************************/
|
||||
#define EMAC_RFC_UCAST_EN 0x00000001 /**< Accept Unicast Frames Enable */
|
||||
#define EMAC_RFC_BCAST_EN 0x00000002 /**< Accept Broadcast Frames Enable */
|
||||
#define EMAC_RFC_MCAST_EN 0x00000004 /**< Accept Multicast Frames Enable */
|
||||
#define EMAC_RFC_UCAST_HASH_EN 0x00000008 /**< Accept Unicast Hash Filter Frames */
|
||||
#define EMAC_RFC_MCAST_HASH_EN 0x00000010 /**< Accept Multicast Hash Filter Fram.*/
|
||||
#define EMAC_RFC_PERFECT_EN 0x00000020 /**< Accept Perfect Match Enable */
|
||||
#define EMAC_RFC_MAGP_WOL_EN 0x00001000 /**< Magic Packet Filter WoL Enable */
|
||||
#define EMAC_RFC_PFILT_WOL_EN 0x00002000 /**< Perfect Filter WoL Enable */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Receive Filter WoL Status/Clear Registers
|
||||
**********************************************************************/
|
||||
#define EMAC_WOL_UCAST 0x00000001 /**< Unicast Frame caused WoL */
|
||||
#define EMAC_WOL_BCAST 0x00000002 /**< Broadcast Frame caused WoL */
|
||||
#define EMAC_WOL_MCAST 0x00000004 /**< Multicast Frame caused WoL */
|
||||
#define EMAC_WOL_UCAST_HASH 0x00000008 /**< Unicast Hash Filter Frame WoL */
|
||||
#define EMAC_WOL_MCAST_HASH 0x00000010 /**< Multicast Hash Filter Frame WoL */
|
||||
#define EMAC_WOL_PERFECT 0x00000020 /**< Perfect Filter WoL */
|
||||
#define EMAC_WOL_RX_FILTER 0x00000080 /**< RX Filter caused WoL */
|
||||
#define EMAC_WOL_MAG_PACKET 0x00000100 /**< Magic Packet Filter caused WoL */
|
||||
#define EMAC_WOL_BITMASK 0x01BF /**< Receive Filter WoL Status/Clear bitmasl value */
|
||||
|
||||
|
||||
/* Module control register definitions ---------------------------------------------------- */
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Interrupt Status/Enable/Clear/Set Registers
|
||||
**********************************************************************/
|
||||
#define EMAC_INT_RX_OVERRUN 0x00000001 /**< Overrun Error in RX Queue */
|
||||
#define EMAC_INT_RX_ERR 0x00000002 /**< Receive Error */
|
||||
#define EMAC_INT_RX_FIN 0x00000004 /**< RX Finished Process Descriptors */
|
||||
#define EMAC_INT_RX_DONE 0x00000008 /**< Receive Done */
|
||||
#define EMAC_INT_TX_UNDERRUN 0x00000010 /**< Transmit Underrun */
|
||||
#define EMAC_INT_TX_ERR 0x00000020 /**< Transmit Error */
|
||||
#define EMAC_INT_TX_FIN 0x00000040 /**< TX Finished Process Descriptors */
|
||||
#define EMAC_INT_TX_DONE 0x00000080 /**< Transmit Done */
|
||||
#define EMAC_INT_SOFT_INT 0x00001000 /**< Software Triggered Interrupt */
|
||||
#define EMAC_INT_WAKEUP 0x00002000 /**< Wakeup Event Interrupt */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Power Down Register
|
||||
**********************************************************************/
|
||||
#define EMAC_PD_POWER_DOWN 0x80000000 /**< Power Down MAC */
|
||||
|
||||
/* Descriptor and status formats ---------------------------------------------------- */
|
||||
/*********************************************************************//**
|
||||
* Macro defines for RX Descriptor Control Word
|
||||
**********************************************************************/
|
||||
#define EMAC_RCTRL_SIZE(n) (n&0x7FF) /**< Buffer size field */
|
||||
#define EMAC_RCTRL_INT 0x80000000 /**< Generate RxDone Interrupt */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for RX Status Hash CRC Word
|
||||
**********************************************************************/
|
||||
#define EMAC_RHASH_SA 0x000001FF /**< Hash CRC for Source Address */
|
||||
#define EMAC_RHASH_DA 0x001FF000 /**< Hash CRC for Destination Address */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for RX Status Information Word
|
||||
**********************************************************************/
|
||||
#define EMAC_RINFO_SIZE 0x000007FF /**< Data size in bytes */
|
||||
#define EMAC_RINFO_CTRL_FRAME 0x00040000 /**< Control Frame */
|
||||
#define EMAC_RINFO_VLAN 0x00080000 /**< VLAN Frame */
|
||||
#define EMAC_RINFO_FAIL_FILT 0x00100000 /**< RX Filter Failed */
|
||||
#define EMAC_RINFO_MCAST 0x00200000 /**< Multicast Frame */
|
||||
#define EMAC_RINFO_BCAST 0x00400000 /**< Broadcast Frame */
|
||||
#define EMAC_RINFO_CRC_ERR 0x00800000 /**< CRC Error in Frame */
|
||||
#define EMAC_RINFO_SYM_ERR 0x01000000 /**< Symbol Error from PHY */
|
||||
#define EMAC_RINFO_LEN_ERR 0x02000000 /**< Length Error */
|
||||
#define EMAC_RINFO_RANGE_ERR 0x04000000 /**< Range Error (exceeded max. size) */
|
||||
#define EMAC_RINFO_ALIGN_ERR 0x08000000 /**< Alignment Error */
|
||||
#define EMAC_RINFO_OVERRUN 0x10000000 /**< Receive overrun */
|
||||
#define EMAC_RINFO_NO_DESCR 0x20000000 /**< No new Descriptor available */
|
||||
#define EMAC_RINFO_LAST_FLAG 0x40000000 /**< Last Fragment in Frame */
|
||||
#define EMAC_RINFO_ERR 0x80000000 /**< Error Occured (OR of all errors) */
|
||||
#define EMAC_RINFO_ERR_MASK (EMAC_RINFO_FAIL_FILT | EMAC_RINFO_CRC_ERR | EMAC_RINFO_SYM_ERR | \
|
||||
EMAC_RINFO_LEN_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_OVERRUN)
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for TX Descriptor Control Word
|
||||
**********************************************************************/
|
||||
#define EMAC_TCTRL_SIZE 0x000007FF /**< Size of data buffer in bytes */
|
||||
#define EMAC_TCTRL_OVERRIDE 0x04000000 /**< Override Default MAC Registers */
|
||||
#define EMAC_TCTRL_HUGE 0x08000000 /**< Enable Huge Frame */
|
||||
#define EMAC_TCTRL_PAD 0x10000000 /**< Pad short Frames to 64 bytes */
|
||||
#define EMAC_TCTRL_CRC 0x20000000 /**< Append a hardware CRC to Frame */
|
||||
#define EMAC_TCTRL_LAST 0x40000000 /**< Last Descriptor for TX Frame */
|
||||
#define EMAC_TCTRL_INT 0x80000000 /**< Generate TxDone Interrupt */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for TX Status Information Word
|
||||
**********************************************************************/
|
||||
#define EMAC_TINFO_COL_CNT 0x01E00000 /**< Collision Count */
|
||||
#define EMAC_TINFO_DEFER 0x02000000 /**< Packet Deferred (not an error) */
|
||||
#define EMAC_TINFO_EXCESS_DEF 0x04000000 /**< Excessive Deferral */
|
||||
#define EMAC_TINFO_EXCESS_COL 0x08000000 /**< Excessive Collision */
|
||||
#define EMAC_TINFO_LATE_COL 0x10000000 /**< Late Collision Occured */
|
||||
#define EMAC_TINFO_UNDERRUN 0x20000000 /**< Transmit Underrun */
|
||||
#define EMAC_TINFO_NO_DESCR 0x40000000 /**< No new Descriptor available */
|
||||
#define EMAC_TINFO_ERR 0x80000000 /**< Error Occured (OR of all errors) */
|
||||
|
||||
#ifdef MCB_LPC_1768
|
||||
/* DP83848C PHY definition ------------------------------------------------------------ */
|
||||
|
||||
/** PHY device reset time out definition */
|
||||
#define EMAC_PHY_RESP_TOUT 0x100000UL
|
||||
|
||||
/* ENET Device Revision ID */
|
||||
#define EMAC_OLD_EMAC_MODULE_ID 0x39022000 /**< Rev. ID for first rev '-' */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for DP83848C PHY Registers
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_REG_BMCR 0x00 /**< Basic Mode Control Register */
|
||||
#define EMAC_PHY_REG_BMSR 0x01 /**< Basic Mode Status Register */
|
||||
#define EMAC_PHY_REG_IDR1 0x02 /**< PHY Identifier 1 */
|
||||
#define EMAC_PHY_REG_IDR2 0x03 /**< PHY Identifier 2 */
|
||||
#define EMAC_PHY_REG_ANAR 0x04 /**< Auto-Negotiation Advertisement */
|
||||
#define EMAC_PHY_REG_ANLPAR 0x05 /**< Auto-Neg. Link Partner Abitily */
|
||||
#define EMAC_PHY_REG_ANER 0x06 /**< Auto-Neg. Expansion Register */
|
||||
#define EMAC_PHY_REG_ANNPTR 0x07 /**< Auto-Neg. Next Page TX */
|
||||
#define EMAC_PHY_REG_LPNPA 0x08
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Extended Registers
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_REG_STS 0x10 /**< Status Register */
|
||||
#define EMAC_PHY_REG_MICR 0x11 /**< MII Interrupt Control Register */
|
||||
#define EMAC_PHY_REG_MISR 0x12 /**< MII Interrupt Status Register */
|
||||
#define EMAC_PHY_REG_FCSCR 0x14 /**< False Carrier Sense Counter */
|
||||
#define EMAC_PHY_REG_RECR 0x15 /**< Receive Error Counter */
|
||||
#define EMAC_PHY_REG_PCSR 0x16 /**< PCS Sublayer Config. and Status */
|
||||
#define EMAC_PHY_REG_RBR 0x17 /**< RMII and Bypass Register */
|
||||
#define EMAC_PHY_REG_LEDCR 0x18 /**< LED Direct Control Register */
|
||||
#define EMAC_PHY_REG_PHYCR 0x19 /**< PHY Control Register */
|
||||
#define EMAC_PHY_REG_10BTSCR 0x1A /**< 10Base-T Status/Control Register */
|
||||
#define EMAC_PHY_REG_CDCTRL1 0x1B /**< CD Test Control and BIST Extens. */
|
||||
#define EMAC_PHY_REG_EDCR 0x1D /**< Energy Detect Control Register */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Basic Mode Control Register
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_BMCR_RESET (1<<15) /**< Reset bit */
|
||||
#define EMAC_PHY_BMCR_LOOPBACK (1<<14) /**< Loop back */
|
||||
#define EMAC_PHY_BMCR_SPEED_SEL (1<<13) /**< Speed selection */
|
||||
#define EMAC_PHY_BMCR_AN (1<<12) /**< Auto Negotiation */
|
||||
#define EMAC_PHY_BMCR_POWERDOWN (1<<11) /**< Power down mode */
|
||||
#define EMAC_PHY_BMCR_ISOLATE (1<<10) /**< Isolate */
|
||||
#define EMAC_PHY_BMCR_RE_AN (1<<9) /**< Restart auto negotiation */
|
||||
#define EMAC_PHY_BMCR_DUPLEX (1<<8) /**< Duplex mode */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Basic Mode Status Status Register
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_BMSR_100BE_T4 (1<<15) /**< 100 base T4 */
|
||||
#define EMAC_PHY_BMSR_100TX_FULL (1<<14) /**< 100 base full duplex */
|
||||
#define EMAC_PHY_BMSR_100TX_HALF (1<<13) /**< 100 base half duplex */
|
||||
#define EMAC_PHY_BMSR_10BE_FULL (1<<12) /**< 10 base T full duplex */
|
||||
#define EMAC_PHY_BMSR_10BE_HALF (1<<11) /**< 10 base T half duplex */
|
||||
#define EMAC_PHY_BMSR_NOPREAM (1<<6) /**< MF Preamable Supress */
|
||||
#define EMAC_PHY_BMSR_AUTO_DONE (1<<5) /**< Auto negotiation complete */
|
||||
#define EMAC_PHY_BMSR_REMOTE_FAULT (1<<4) /**< Remote fault */
|
||||
#define EMAC_PHY_BMSR_NO_AUTO (1<<3) /**< Auto Negotiation ability */
|
||||
#define EMAC_PHY_BMSR_LINK_ESTABLISHED (1<<2) /**< Link status */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Status Register
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_SR_REMOTE_FAULT (1<<6) /**< Remote Fault */
|
||||
#define EMAC_PHY_SR_JABBER (1<<5) /**< Jabber detect */
|
||||
#define EMAC_PHY_SR_AUTO_DONE (1<<4) /**< Auto Negotiation complete */
|
||||
#define EMAC_PHY_SR_LOOPBACK (1<<3) /**< Loop back status */
|
||||
#define EMAC_PHY_SR_DUP (1<<2) /**< Duplex status */
|
||||
#define EMAC_PHY_SR_SPEED (1<<1) /**< Speed status */
|
||||
#define EMAC_PHY_SR_LINK (1<<0) /**< Link Status */
|
||||
|
||||
#define EMAC_PHY_FULLD_100M 0x2100 /**< Full Duplex 100Mbit */
|
||||
#define EMAC_PHY_HALFD_100M 0x2000 /**< Half Duplex 100Mbit */
|
||||
#define EMAC_PHY_FULLD_10M 0x0100 /**< Full Duplex 10Mbit */
|
||||
#define EMAC_PHY_HALFD_10M 0x0000 /**< Half Duplex 10MBit */
|
||||
#define EMAC_PHY_AUTO_NEG 0x3000 /**< Select Auto Negotiation */
|
||||
|
||||
#define EMAC_DEF_ADR 0x0100 /**< Default PHY device address */
|
||||
#define EMAC_DP83848C_ID 0x20005C90 /**< PHY Identifier */
|
||||
|
||||
#define EMAC_PHY_SR_100_SPEED ((1<<14)|(1<<13))
|
||||
#define EMAC_PHY_SR_FULL_DUP ((1<<14)|(1<<12))
|
||||
#define EMAC_PHY_BMSR_LINK_STATUS (1<<2) /**< Link status */
|
||||
|
||||
#elif defined(IAR_LPC_1768)
|
||||
/* KSZ8721BL PHY definition ------------------------------------------------------------ */
|
||||
/** PHY device reset time out definition */
|
||||
#define EMAC_PHY_RESP_TOUT 0x100000UL
|
||||
|
||||
/* ENET Device Revision ID */
|
||||
#define EMAC_OLD_EMAC_MODULE_ID 0x39022000 /**< Rev. ID for first rev '-' */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for KSZ8721BL PHY Registers
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_REG_BMCR 0x00 /**< Basic Mode Control Register */
|
||||
#define EMAC_PHY_REG_BMSR 0x01 /**< Basic Mode Status Register */
|
||||
#define EMAC_PHY_REG_IDR1 0x02 /**< PHY Identifier 1 */
|
||||
#define EMAC_PHY_REG_IDR2 0x03 /**< PHY Identifier 2 */
|
||||
#define EMAC_PHY_REG_ANAR 0x04 /**< Auto-Negotiation Advertisement */
|
||||
#define EMAC_PHY_REG_ANLPAR 0x05 /**< Auto-Neg. Link Partner Abitily */
|
||||
#define EMAC_PHY_REG_ANER 0x06 /**< Auto-Neg. Expansion Register */
|
||||
#define EMAC_PHY_REG_ANNPTR 0x07 /**< Auto-Neg. Next Page TX */
|
||||
#define EMAC_PHY_REG_LPNPA 0x08 /**< Link Partner Next Page Ability */
|
||||
#define EMAC_PHY_REG_REC 0x15 /**< RXError Counter Register */
|
||||
#define EMAC_PHY_REG_ISC 0x1b /**< Interrupt Control/Status Register */
|
||||
#define EMAC_PHY_REG_100BASE 0x1f /**< 100BASE-TX PHY Control Register */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Basic Mode Control Register
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_BMCR_RESET (1<<15) /**< Reset bit */
|
||||
#define EMAC_PHY_BMCR_LOOPBACK (1<<14) /**< Loop back */
|
||||
#define EMAC_PHY_BMCR_SPEED_SEL (1<<13) /**< Speed selection */
|
||||
#define EMAC_PHY_BMCR_AN (1<<12) /**< Auto Negotiation */
|
||||
#define EMAC_PHY_BMCR_POWERDOWN (1<<11) /**< Power down mode */
|
||||
#define EMAC_PHY_BMCR_ISOLATE (1<<10) /**< Isolate */
|
||||
#define EMAC_PHY_BMCR_RE_AN (1<<9) /**< Restart auto negotiation */
|
||||
#define EMAC_PHY_BMCR_DUPLEX (1<<8) /**< Duplex mode */
|
||||
#define EMAC_PHY_BMCR_COLLISION (1<<7) /**< Collision test */
|
||||
#define EMAC_PHY_BMCR_TXDIS (1<<0) /**< Disable transmit */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Basic Mode Status Register
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_BMSR_100BE_T4 (1<<15) /**< 100 base T4 */
|
||||
#define EMAC_PHY_BMSR_100TX_FULL (1<<14) /**< 100 base full duplex */
|
||||
#define EMAC_PHY_BMSR_100TX_HALF (1<<13) /**< 100 base half duplex */
|
||||
#define EMAC_PHY_BMSR_10BE_FULL (1<<12) /**< 10 base T full duplex */
|
||||
#define EMAC_PHY_BMSR_10BE_HALF (1<<11) /**< 10 base T half duplex */
|
||||
#define EMAC_PHY_BMSR_NOPREAM (1<<6) /**< MF Preamable Supress */
|
||||
#define EMAC_PHY_BMSR_AUTO_DONE (1<<5) /**< Auto negotiation complete */
|
||||
#define EMAC_PHY_BMSR_REMOTE_FAULT (1<<4) /**< Remote fault */
|
||||
#define EMAC_PHY_BMSR_NO_AUTO (1<<3) /**< Auto Negotiation ability */
|
||||
#define EMAC_PHY_BMSR_LINK_STATUS (1<<2) /**< Link status */
|
||||
#define EMAC_PHY_BMSR_JABBER_DETECT (1<<1) /**< Jabber detect */
|
||||
#define EMAC_PHY_BMSR_EXTEND (1<<0) /**< Extended support */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for PHY Identifier
|
||||
**********************************************************************/
|
||||
/* PHY Identifier 1 bitmap definitions */
|
||||
#define EMAC_PHY_IDR1(n) (n & 0xFFFF) /**< PHY ID1 Number */
|
||||
|
||||
/* PHY Identifier 2 bitmap definitions */
|
||||
#define EMAC_PHY_IDR2(n) (n & 0xFFFF) /**< PHY ID2 Number */
|
||||
|
||||
/*********************************************************************//**
|
||||
* Macro defines for Auto-Negotiation Advertisement
|
||||
**********************************************************************/
|
||||
#define EMAC_PHY_AN_NEXTPAGE (1<<15) /**< Next page capable */
|
||||
#define EMAC_PHY_AN_REMOTE_FAULT (1<<13) /**< Remote Fault support */
|
||||
#define EMAC_PHY_AN_PAUSE (1<<10) /**< Pause support */
|
||||
#define EMAC_PHY_AN_100BASE_T4 (1<<9) /**< T4 capable */
|
||||
#define EMAC_PHY_AN_100BASE_TX_FD (1<<8) /**< TX with Full-duplex capable */
|
||||
#define EMAC_PHY_AN_100BASE_TX (1<<7) /**< TX capable */
|
||||
#define EMAC_PHY_AN_10BASE_T_FD (1<<6) /**< 10Mbps with full-duplex capable */
|
||||
#define EMAC_PHY_AN_10BASE_T (1<<5) /**< 10Mbps capable */
|
||||
#define EMAC_PHY_AN_FIELD(n) (n & 0x1F) /**< Selector Field */
|
||||
|
||||
#define EMAC_PHY_FULLD_100M 0x2100 /**< Full Duplex 100Mbit */
|
||||
#define EMAC_PHY_HALFD_100M 0x2000 /**< Half Duplex 100Mbit */
|
||||
#define EMAC_PHY_FULLD_10M 0x0100 /**< Full Duplex 10Mbit */
|
||||
#define EMAC_PHY_HALFD_10M 0x0000 /**< Half Duplex 10MBit */
|
||||
#define EMAC_PHY_AUTO_NEG 0x3000 /**< Select Auto Negotiation */
|
||||
|
||||
#define EMAC_PHY_SR_100_SPEED ((1<<14)|(1<<13))
|
||||
#define EMAC_PHY_SR_FULL_DUP ((1<<14)|(1<<12))
|
||||
|
||||
#define EMAC_DEF_ADR (0x01<<8) /**< Default PHY device address */
|
||||
#define EMAC_KSZ8721BL_ID ((0x22 << 16) | 0x1619 ) /**< PHY Identifier */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/* Public Types --------------------------------------------------------------- */
|
||||
/** @defgroup EMAC_Public_Types EMAC Public Types
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Descriptor and status formats ---------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief RX Descriptor structure type definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t Packet; /**< Receive Packet Descriptor */
|
||||
uint32_t Ctrl; /**< Receive Control Descriptor */
|
||||
} RX_Desc;
|
||||
|
||||
/**
|
||||
* @brief RX Status structure type definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t Info; /**< Receive Information Status */
|
||||
uint32_t HashCRC; /**< Receive Hash CRC Status */
|
||||
} RX_Stat;
|
||||
|
||||
/**
|
||||
* @brief TX Descriptor structure type definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t Packet; /**< Transmit Packet Descriptor */
|
||||
uint32_t Ctrl; /**< Transmit Control Descriptor */
|
||||
} TX_Desc;
|
||||
|
||||
/**
|
||||
* @brief TX Status structure type definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t Info; /**< Transmit Information Status */
|
||||
} TX_Stat;
|
||||
|
||||
|
||||
/**
|
||||
* @brief TX Data Buffer structure definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t ulDataLen; /**< Data length */
|
||||
uint32_t *pbDataBuf; /**< A word-align data pointer to data buffer */
|
||||
} EMAC_PACKETBUF_Type;
|
||||
|
||||
/**
|
||||
* @brief EMAC configuration structure definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t Mode; /**< Supported EMAC PHY device speed, should be one of the following:
|
||||
- EMAC_MODE_AUTO
|
||||
- EMAC_MODE_10M_FULL
|
||||
- EMAC_MODE_10M_HALF
|
||||
- EMAC_MODE_100M_FULL
|
||||
- EMAC_MODE_100M_HALF
|
||||
*/
|
||||
uint8_t *pbEMAC_Addr; /**< Pointer to EMAC Station address that contains 6-bytes
|
||||
of MAC address, it must be sorted in order (bEMAC_Addr[0]..[5])
|
||||
*/
|
||||
} EMAC_CFG_Type;
|
||||
|
||||
/** Ethernet block power/clock control bit*/
|
||||
#define CLKPWR_PCONP_PCENET ((uint32_t)(1<<30))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LPC17XX_EMAC_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
|
@ -1,111 +0,0 @@
|
|||
/**********************************************************************
|
||||
* $Id$ lpc_emac_config.h 2011-11-20
|
||||
*//**
|
||||
* @file lpc_emac_config.h
|
||||
* @brief PHY and EMAC configuration file
|
||||
* @version 1.0
|
||||
* @date 20 Nov. 2011
|
||||
* @author NXP MCU SW Application Team
|
||||
*
|
||||
* Copyright(C) 2011, NXP Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
***********************************************************************
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* products. This software is supplied "AS IS" without any warranties.
|
||||
* NXP Semiconductors assumes no responsibility or liability for the
|
||||
* use of the software, conveys no license or title under any patent,
|
||||
* copyright, or mask work right to the product. NXP Semiconductors
|
||||
* reserves the right to make changes in the software without
|
||||
* notification. NXP Semiconductors also make no representation or
|
||||
* warranty that such application will be suitable for the specified
|
||||
* use without further testing or modification.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __LPC_EMAC_CONFIG_H
|
||||
#define __LPC_EMAC_CONFIG_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** @defgroup lwip_phy_config LWIP PHY configuration
|
||||
* @ingroup lwip_phy
|
||||
*
|
||||
* Configuration options for the PHY connected to the LPC EMAC.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \brief The PHY address connected the to MII/RMII
|
||||
*/
|
||||
#define LPC_PHYDEF_PHYADDR 1 /**< The PHY address on the PHY device. */
|
||||
|
||||
/** \brief Enable autonegotiation mode.
|
||||
* If this is enabled, the PHY will attempt to auto-negotiate the
|
||||
* best link mode if the PHY supports it. If this is not enabled,
|
||||
* the PHY_USE_FULL_DUPLEX and PHY_USE_100MBS defines will be
|
||||
* used to select the link mode. Note that auto-negotiation may
|
||||
* take a few seconds to complete.
|
||||
*/
|
||||
#define PHY_USE_AUTONEG 1 /**< Enables auto-negotiation mode. */
|
||||
|
||||
/** \brief Sets up the PHY interface to either full duplex operation or
|
||||
* half duplex operation if PHY_USE_AUTONEG is not enabled.
|
||||
*/
|
||||
#define PHY_USE_FULL_DUPLEX 1 /**< Sets duplex mode to full. */
|
||||
|
||||
/** \brief Sets up the PHY interface to either 100MBS operation or 10MBS
|
||||
* operation if PHY_USE_AUTONEG is not enabled.
|
||||
*/
|
||||
#define PHY_USE_100MBS 1 /**< Sets data rate to 100Mbps. */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup lwip_emac_config LWIP EMAC configuration
|
||||
* @ingroup lwip_emac
|
||||
*
|
||||
* Configuration options for the LPC EMAC.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \brief Selects RMII or MII connection type in the EMAC peripheral
|
||||
*/
|
||||
#define LPC_EMAC_RMII 1 /**< Use the RMII or MII driver variant .*/
|
||||
|
||||
/** \brief Defines the number of descriptors used for RX. This
|
||||
* must be a minimum value of 2.
|
||||
*/
|
||||
#define LPC_NUM_BUFF_RXDESCS 3
|
||||
|
||||
/** \brief Defines the number of descriptors used for TX. Must
|
||||
* be a minimum value of 2.
|
||||
*/
|
||||
#define LPC_NUM_BUFF_TXDESCS (TCP_SND_QUEUELEN + 1)
|
||||
|
||||
/** \brief Set this define to 1 to enable bounce buffers for transmit pbufs
|
||||
* that cannot be sent via the zero-copy method. Some chained pbufs
|
||||
* may have a payload address that links to an area of memory that
|
||||
* cannot be used for transmit DMA operations. If this define is
|
||||
* set to 1, an extra check will be made with the pbufs. If a buffer
|
||||
* is determined to be non-usable for zero-copy, a temporary bounce
|
||||
* buffer will be created and used instead.
|
||||
*/
|
||||
#define LPC_TX_PBUF_BOUNCE_EN 1
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LPC_EMAC_CONFIG_H */
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
|
@ -1,151 +0,0 @@
|
|||
/**********************************************************************
|
||||
* $Id$ lpc_phy.h 2011-11-20
|
||||
*//**
|
||||
* @file lpc_phy.h
|
||||
* @brief Common PHY definitions used with all PHYs
|
||||
* @version 1.0
|
||||
* @date 20 Nov. 2011
|
||||
* @author NXP MCU SW Application Team
|
||||
*
|
||||
* Copyright(C) 2011, NXP Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
***********************************************************************
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* products. This software is supplied "AS IS" without any warranties.
|
||||
* NXP Semiconductors assumes no responsibility or liability for the
|
||||
* use of the software, conveys no license or title under any patent,
|
||||
* copyright, or mask work right to the product. NXP Semiconductors
|
||||
* reserves the right to make changes in the software without
|
||||
* notification. NXP Semiconductors also make no representation or
|
||||
* warranty that such application will be suitable for the specified
|
||||
* use without further testing or modification.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __LPC_PHY_H_
|
||||
#define __LPC_PHY_H_
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* These PHY functions are usually part of the EMAC driver */
|
||||
|
||||
/** \brief Phy status update state machine
|
||||
*
|
||||
* This function provides a state machine for maintaining the PHY
|
||||
* status without blocking. It must be occasionally called for the
|
||||
* PHY status to be maintained.
|
||||
*
|
||||
* \param[in] netif NETIF structure
|
||||
*/
|
||||
s32_t lpc_phy_sts_sm(struct netif *netif);
|
||||
|
||||
/** \brief Initialize the PHY
|
||||
*
|
||||
* This function initializes the PHY. It will block until complete.
|
||||
* This function is called as part of the EMAC driver
|
||||
* initialization. Configuration of the PHY at startup is
|
||||
* controlled by setting up configuration defines in lpc_phy.h.
|
||||
*
|
||||
* \param[in] netif NETIF structure
|
||||
* \param[in] rmii If set, configures the PHY for RMII mode
|
||||
* \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
|
||||
*/
|
||||
err_t lpc_phy_init(struct netif *netif, int rmii);
|
||||
|
||||
/** \brief Write a value via the MII link (non-blocking)
|
||||
*
|
||||
* This function will write a value on the MII link interface to a PHY
|
||||
* or a connected device. The function will return immediately without
|
||||
* a status. Status needs to be polled later to determine if the write
|
||||
* was successful.
|
||||
*
|
||||
* \param[in] PhyReg PHY register to write to
|
||||
* \param[in] Value Value to write
|
||||
*/
|
||||
void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value);
|
||||
|
||||
/** \brief Write a value via the MII link (blocking)
|
||||
*
|
||||
* This function will write a value on the MII link interface to a PHY
|
||||
* or a connected device. The function will block until complete.
|
||||
*
|
||||
* \param[in] PhyReg PHY register to write to
|
||||
* \param[in] Value Value to write
|
||||
* \returns 0 if the write was successful, otherwise !0
|
||||
*/
|
||||
err_t lpc_mii_write(u32_t PhyReg, u32_t Value);
|
||||
|
||||
/** \brief Reads current MII link busy status
|
||||
*
|
||||
* This function will return the current MII link busy status and is meant to
|
||||
* be used with non-blocking functions for monitor PHY status such as
|
||||
* connection state.
|
||||
*
|
||||
* \returns !0 if the MII link is busy, otherwise 0
|
||||
*/
|
||||
u32_t lpc_mii_is_busy(void);
|
||||
|
||||
/** \brief Starts a read operation via the MII link (non-blocking)
|
||||
*
|
||||
* This function returns the current value in the MII data register. It is
|
||||
* meant to be used with the non-blocking oeprations. This value should
|
||||
* only be read after a non-block read command has been issued and the
|
||||
* MII status has been determined to be good.
|
||||
*
|
||||
* \returns The current value in the MII value register
|
||||
*/
|
||||
u32_t lpc_mii_read_data(void);
|
||||
|
||||
/** \brief Starts a read operation via the MII link (non-blocking)
|
||||
*
|
||||
* This function will start a read operation on the MII link interface
|
||||
* from a PHY or a connected device. The function will not block and
|
||||
* the status mist be polled until complete. Once complete, the data
|
||||
* can be read.
|
||||
*
|
||||
* \param[in] PhyReg PHY register to read from
|
||||
*/
|
||||
err_t lpc_mii_read(u32_t PhyReg, u32_t *data);
|
||||
|
||||
/** \brief Read a value via the MII link (blocking)
|
||||
*
|
||||
* This function will read a value on the MII link interface from a PHY
|
||||
* or a connected device. The function will block until complete.
|
||||
*
|
||||
* \param[in] PhyReg PHY register to read from
|
||||
* \param[in] data Pointer to where to save data read via MII
|
||||
* \returns 0 if the read was successful, otherwise !0
|
||||
*/
|
||||
void lpc_mii_read_noblock(u32_t PhyReg);
|
||||
|
||||
/**
|
||||
* This function provides a method for the PHY to setup the EMAC
|
||||
* for the PHY negotiated duplex mode.
|
||||
*
|
||||
* @param[in] full_duplex 0 = half duplex, 1 = full duplex
|
||||
*/
|
||||
void lpc_emac_set_duplex(int full_duplex);
|
||||
|
||||
/**
|
||||
* This function provides a method for the PHY to setup the EMAC
|
||||
* for the PHY negotiated bit rate.
|
||||
*
|
||||
* @param[in] mbs_100 0 = 10mbs mode, 1 = 100mbs mode
|
||||
*/
|
||||
void lpc_emac_set_speed(int mbs_100);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LPC_PHY_H_ */
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
|
@ -1,438 +0,0 @@
|
|||
/**********************************************************************
|
||||
* $Id$ lpc_phy_dp83848.c 2011-11-20
|
||||
*//**
|
||||
* @file lpc_phy_dp83848.c
|
||||
* @brief DP83848C PHY status and control.
|
||||
* @version 1.0
|
||||
* @date 20 Nov. 2011
|
||||
* @author NXP MCU SW Application Team
|
||||
*
|
||||
* Copyright(C) 2011, NXP Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
***********************************************************************
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* products. This software is supplied "AS IS" without any warranties.
|
||||
* NXP Semiconductors assumes no responsibility or liability for the
|
||||
* use of the software, conveys no license or title under any patent,
|
||||
* copyright, or mask work right to the product. NXP Semiconductors
|
||||
* reserves the right to make changes in the software without
|
||||
* notification. NXP Semiconductors also make no representation or
|
||||
* warranty that such application will be suitable for the specified
|
||||
* use without further testing or modification.
|
||||
**********************************************************************/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lpc_emac_config.h"
|
||||
#include "lpc_phy.h"
|
||||
#include "lpc17xx_emac.h"
|
||||
|
||||
/** @defgroup dp83848_phy PHY status and control for the DP83848.
|
||||
* @ingroup lwip_phy
|
||||
*
|
||||
* Various functions for controlling and monitoring the status of the
|
||||
* DP83848 PHY. In polled (standalone) systems, the PHY state must be
|
||||
* monitored as part of the application. In a threaded (RTOS) system,
|
||||
* the PHY state is monitored by the PHY handler thread. The MAC
|
||||
* driver will not transmit unless the PHY link is active.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \brief DP83848 PHY register offsets */
|
||||
#define DP8_BMCR_REG 0x0 /**< Basic Mode Control Register */
|
||||
#define DP8_BMSR_REG 0x1 /**< Basic Mode Status Reg */
|
||||
#define DP8_IDR1_REG 0x2 /**< Basic Mode Status Reg */
|
||||
#define DP8_IDR2_REG 0x3 /**< Basic Mode Status Reg */
|
||||
#define DP8_ANADV_REG 0x4 /**< Auto_Neg Advt Reg */
|
||||
#define DP8_ANLPA_REG 0x5 /**< Auto_neg Link Partner Ability Reg */
|
||||
#define DP8_ANEEXP_REG 0x6 /**< Auto-neg Expansion Reg */
|
||||
#define DP8_PHY_STAT_REG 0x10 /**< PHY Status Register */
|
||||
#define DP8_PHY_INT_CTL_REG 0x11 /**< PHY Interrupt Control Register */
|
||||
#define DP8_PHY_RBR_REG 0x17 /**< PHY RMII and Bypass Register */
|
||||
#define DP8_PHY_STS_REG 0x19 /**< PHY Status Register */
|
||||
|
||||
#define DP8_PHY_SCSR_REG 0x1f /**< PHY Special Control/Status Register (LAN8720) */
|
||||
|
||||
/** \brief DP83848 Control register definitions */
|
||||
#define DP8_RESET (1 << 15) /**< 1= S/W Reset */
|
||||
#define DP8_LOOPBACK (1 << 14) /**< 1=loopback Enabled */
|
||||
#define DP8_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */
|
||||
#define DP8_AUTONEG (1 << 12) /**< 1=Enable auto-negotiation */
|
||||
#define DP8_POWER_DOWN (1 << 11) /**< 1=Power down PHY */
|
||||
#define DP8_ISOLATE (1 << 10) /**< 1=Isolate PHY */
|
||||
#define DP8_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */
|
||||
#define DP8_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */
|
||||
#define DP8_COLLISION_TEST (1 << 7) /**< 1=Perform collsion test */
|
||||
|
||||
/** \brief DP83848 Status register definitions */
|
||||
#define DP8_100BASE_T4 (1 << 15) /**< T4 mode */
|
||||
#define DP8_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */
|
||||
#define DP8_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */
|
||||
#define DP8_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */
|
||||
#define DP8_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */
|
||||
#define DP8_MF_PREAMB_SUPPR (1 << 6) /**< Preamble suppress */
|
||||
#define DP8_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */
|
||||
#define DP8_RMT_FAULT (1 << 4) /**< Fault */
|
||||
#define DP8_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */
|
||||
#define DP8_LINK_STATUS (1 << 2) /**< 1=Link active */
|
||||
#define DP8_JABBER_DETECT (1 << 1) /**< Jabber detect */
|
||||
#define DP8_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */
|
||||
|
||||
/** \brief DP83848 PHY RBR MII dode definitions */
|
||||
#define DP8_RBR_RMII_MODE (1 << 5) /**< Use RMII mode */
|
||||
|
||||
/** \brief DP83848 PHY status definitions */
|
||||
#define DP8_REMOTEFAULT (1 << 6) /**< Remote fault */
|
||||
#define DP8_FULLDUPLEX (1 << 2) /**< 1=full duplex */
|
||||
#define DP8_SPEED10MBPS (1 << 1) /**< 1=10MBps speed */
|
||||
#define DP8_VALID_LINK (1 << 0) /**< 1=Link active */
|
||||
|
||||
/** \brief DP83848 PHY ID register definitions */
|
||||
#define DP8_PHYID1_OUI 0x2000 /**< Expected PHY ID1 */
|
||||
#define DP8_PHYID2_OUI 0x5c90 /**< Expected PHY ID2 */
|
||||
|
||||
/** \brief LAN8720 PHY Special Control/Status Register */
|
||||
#define PHY_SCSR_100MBIT 0x0008 /**< Speed: 1=100 MBit, 0=10Mbit */
|
||||
#define PHY_SCSR_DUPLEX 0x0010 /**< PHY Duplex Mask */
|
||||
|
||||
/** \brief Link status bits */
|
||||
#define LNK_STAT_VALID 0x01
|
||||
#define LNK_STAT_FULLDUPLEX 0x02
|
||||
#define LNK_STAT_SPEED10MPS 0x04
|
||||
|
||||
/** \brief PHY ID definitions */
|
||||
#define DP83848C_ID 0x20005C90 /**< PHY Identifier - DP83848C */
|
||||
#define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */
|
||||
|
||||
/** \brief PHY status structure used to indicate current status of PHY.
|
||||
*/
|
||||
typedef struct {
|
||||
u32_t phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */
|
||||
u32_t phy_full_duplex:1; /**< Half/full duplex connection speed flag. */
|
||||
u32_t phy_link_active:1; /**< Phy link active flag. */
|
||||
} PHY_STATUS_TYPE;
|
||||
|
||||
/** \brief PHY update flags */
|
||||
static PHY_STATUS_TYPE physts;
|
||||
|
||||
/** \brief Last PHY update flags, used for determing if something has changed */
|
||||
static PHY_STATUS_TYPE olddphysts;
|
||||
|
||||
/** \brief PHY update counter for state machine */
|
||||
static s32_t phyustate;
|
||||
|
||||
/** \brief Holds the PHY ID */
|
||||
static u32_t phy_id;
|
||||
|
||||
/** \brief Temporary holder of link status for LAN7420 */
|
||||
static u32_t phy_lan7420_sts_tmp;
|
||||
|
||||
/* Write a value via the MII link (non-blocking) */
|
||||
void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value)
|
||||
{
|
||||
/* Write value at PHY address and register */
|
||||
LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
|
||||
LPC_EMAC->MWTD = Value;
|
||||
}
|
||||
|
||||
/* Write a value via the MII link (blocking) */
|
||||
err_t lpc_mii_write(u32_t PhyReg, u32_t Value)
|
||||
{
|
||||
u32_t mst = 250;
|
||||
err_t sts = ERR_OK;
|
||||
|
||||
/* Write value at PHY address and register */
|
||||
lpc_mii_write_noblock(PhyReg, Value);
|
||||
|
||||
/* Wait for unbusy status */
|
||||
while (mst > 0) {
|
||||
sts = LPC_EMAC->MIND;
|
||||
if ((sts & EMAC_MIND_BUSY) == 0)
|
||||
mst = 0;
|
||||
else {
|
||||
mst--;
|
||||
osDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (sts != 0)
|
||||
sts = ERR_TIMEOUT;
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
/* Reads current MII link busy status */
|
||||
u32_t lpc_mii_is_busy(void)
|
||||
{
|
||||
return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY);
|
||||
}
|
||||
|
||||
/* Starts a read operation via the MII link (non-blocking) */
|
||||
u32_t lpc_mii_read_data(void)
|
||||
{
|
||||
u32_t data = LPC_EMAC->MRDD;
|
||||
LPC_EMAC->MCMD = 0;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Starts a read operation via the MII link (non-blocking) */
|
||||
void lpc_mii_read_noblock(u32_t PhyReg)
|
||||
{
|
||||
/* Read value at PHY address and register */
|
||||
LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
|
||||
LPC_EMAC->MCMD = EMAC_MCMD_READ;
|
||||
}
|
||||
|
||||
/* Read a value via the MII link (blocking) */
|
||||
err_t lpc_mii_read(u32_t PhyReg, u32_t *data)
|
||||
{
|
||||
u32_t mst = 250;
|
||||
err_t sts = ERR_OK;
|
||||
|
||||
/* Read value at PHY address and register */
|
||||
lpc_mii_read_noblock(PhyReg);
|
||||
|
||||
/* Wait for unbusy status */
|
||||
while (mst > 0) {
|
||||
sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL;
|
||||
if ((sts & EMAC_MIND_BUSY) == 0) {
|
||||
mst = 0;
|
||||
*data = LPC_EMAC->MRDD;
|
||||
} else {
|
||||
mst--;
|
||||
osDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
LPC_EMAC->MCMD = 0;
|
||||
|
||||
if (sts != 0)
|
||||
sts = ERR_TIMEOUT;
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** \brief Update PHY status from passed value
|
||||
*
|
||||
* This function updates the current PHY status based on the
|
||||
* passed PHY status word. The PHY status indicate if the link
|
||||
* is active, the connection speed, and duplex.
|
||||
*
|
||||
* \param[in] netif NETIF structure
|
||||
* \param[in] linksts Status word from PHY
|
||||
* \return 1 if the status has changed, otherwise 0
|
||||
*/
|
||||
static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts)
|
||||
{
|
||||
s32_t changed = 0;
|
||||
|
||||
/* Update link active status */
|
||||
if (linksts & LNK_STAT_VALID)
|
||||
physts.phy_link_active = 1;
|
||||
else
|
||||
physts.phy_link_active = 0;
|
||||
|
||||
/* Full or half duplex */
|
||||
if (linksts & LNK_STAT_FULLDUPLEX)
|
||||
physts.phy_full_duplex = 1;
|
||||
else
|
||||
physts.phy_full_duplex = 0;
|
||||
|
||||
/* Configure 100MBit/10MBit mode. */
|
||||
if (linksts & LNK_STAT_SPEED10MPS)
|
||||
physts.phy_speed_100mbs = 0;
|
||||
else
|
||||
physts.phy_speed_100mbs = 1;
|
||||
|
||||
if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
|
||||
changed = 1;
|
||||
if (physts.phy_speed_100mbs) {
|
||||
/* 100MBit mode. */
|
||||
lpc_emac_set_speed(1);
|
||||
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
|
||||
}
|
||||
else {
|
||||
/* 10MBit mode. */
|
||||
lpc_emac_set_speed(0);
|
||||
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
|
||||
}
|
||||
|
||||
olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
|
||||
}
|
||||
|
||||
if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
|
||||
changed = 1;
|
||||
if (physts.phy_full_duplex)
|
||||
lpc_emac_set_duplex(1);
|
||||
else
|
||||
lpc_emac_set_duplex(0);
|
||||
|
||||
olddphysts.phy_full_duplex = physts.phy_full_duplex;
|
||||
}
|
||||
|
||||
if (physts.phy_link_active != olddphysts.phy_link_active) {
|
||||
changed = 1;
|
||||
#if NO_SYS == 1
|
||||
if (physts.phy_link_active)
|
||||
netif_set_link_up(netif);
|
||||
else
|
||||
netif_set_link_down(netif);
|
||||
#else
|
||||
if (physts.phy_link_active)
|
||||
tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
|
||||
(void*) netif, 1);
|
||||
else
|
||||
tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
|
||||
(void*) netif, 1);
|
||||
#endif
|
||||
|
||||
olddphysts.phy_link_active = physts.phy_link_active;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/** \brief Initialize the DP83848 PHY.
|
||||
*
|
||||
* This function initializes the DP83848 PHY. It will block until
|
||||
* complete. This function is called as part of the EMAC driver
|
||||
* initialization. Configuration of the PHY at startup is
|
||||
* controlled by setting up configuration defines in lpc_phy.h.
|
||||
*
|
||||
* \param[in] netif NETIF structure
|
||||
* \param[in] rmii If set, configures the PHY for RMII mode
|
||||
* \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
|
||||
*/
|
||||
err_t lpc_phy_init(struct netif *netif, int rmii)
|
||||
{
|
||||
u32_t tmp;
|
||||
s32_t i;
|
||||
|
||||
physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 0;
|
||||
physts.phy_full_duplex = olddphysts.phy_full_duplex = 0;
|
||||
physts.phy_link_active = olddphysts.phy_link_active = 0;
|
||||
phyustate = 0;
|
||||
|
||||
/* Only first read and write are checked for failure */
|
||||
/* Put the DP83848C in reset mode and wait for completion */
|
||||
if (lpc_mii_write(DP8_BMCR_REG, DP8_RESET) != 0)
|
||||
return ERR_TIMEOUT;
|
||||
i = 400;
|
||||
while (i > 0) {
|
||||
osDelay(1); /* 1 ms */
|
||||
if (lpc_mii_read(DP8_BMCR_REG, &tmp) != 0)
|
||||
return ERR_TIMEOUT;
|
||||
|
||||
if (!(tmp & (DP8_RESET | DP8_POWER_DOWN)))
|
||||
i = -1;
|
||||
else
|
||||
i--;
|
||||
}
|
||||
/* Timeout? */
|
||||
if (i == 0)
|
||||
return ERR_TIMEOUT;
|
||||
|
||||
// read PHY ID
|
||||
lpc_mii_read(DP8_IDR1_REG, &tmp);
|
||||
phy_id = (tmp << 16);
|
||||
lpc_mii_read(DP8_IDR2_REG, &tmp);
|
||||
phy_id |= (tmp & 0XFFF0);
|
||||
|
||||
/* Setup link based on configuration options */
|
||||
#if PHY_USE_AUTONEG==1
|
||||
tmp = DP8_AUTONEG;
|
||||
#else
|
||||
tmp = 0;
|
||||
#endif
|
||||
#if PHY_USE_100MBS==1
|
||||
tmp |= DP8_SPEED_SELECT;
|
||||
#endif
|
||||
#if PHY_USE_FULL_DUPLEX==1
|
||||
tmp |= DP8_DUPLEX_MODE;
|
||||
#endif
|
||||
lpc_mii_write(DP8_BMCR_REG, tmp);
|
||||
|
||||
/* Enable RMII mode for PHY */
|
||||
if (rmii)
|
||||
lpc_mii_write(DP8_PHY_RBR_REG, DP8_RBR_RMII_MODE);
|
||||
|
||||
/* The link is not set active at this point, but will be detected
|
||||
later */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Phy status update state machine */
|
||||
s32_t lpc_phy_sts_sm(struct netif *netif)
|
||||
{
|
||||
s32_t changed = 0;
|
||||
u32_t data = 0;
|
||||
u32_t tmp;
|
||||
|
||||
switch (phyustate) {
|
||||
default:
|
||||
case 0:
|
||||
if (phy_id == DP83848C_ID) {
|
||||
lpc_mii_read_noblock(DP8_PHY_STAT_REG);
|
||||
phyustate = 2;
|
||||
}
|
||||
else if (phy_id == LAN8720_ID) {
|
||||
lpc_mii_read_noblock(DP8_PHY_SCSR_REG);
|
||||
phyustate = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (phy_id == LAN8720_ID) {
|
||||
tmp = lpc_mii_read_data();
|
||||
// we get speed and duplex here.
|
||||
phy_lan7420_sts_tmp = (tmp & PHY_SCSR_DUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
|
||||
phy_lan7420_sts_tmp |= (tmp & PHY_SCSR_100MBIT) ? 0 : LNK_STAT_SPEED10MPS;
|
||||
|
||||
//read the status register to get link status
|
||||
lpc_mii_read_noblock(DP8_BMSR_REG);
|
||||
phyustate = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Wait for read status state */
|
||||
if (!lpc_mii_is_busy()) {
|
||||
/* Update PHY status */
|
||||
tmp = lpc_mii_read_data();
|
||||
|
||||
if (phy_id == DP83848C_ID) {
|
||||
// STS register contains all needed status bits
|
||||
data = (tmp & DP8_VALID_LINK) ? LNK_STAT_VALID : 0;
|
||||
data |= (tmp & DP8_FULLDUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
|
||||
data |= (tmp & DP8_SPEED10MBPS) ? LNK_STAT_SPEED10MPS : 0;
|
||||
}
|
||||
else if (phy_id == LAN8720_ID) {
|
||||
// we only get the link status here.
|
||||
phy_lan7420_sts_tmp |= (tmp & DP8_LINK_STATUS) ? LNK_STAT_VALID : 0;
|
||||
data = phy_lan7420_sts_tmp;
|
||||
}
|
||||
|
||||
changed = lpc_update_phy_sts(netif, data);
|
||||
phyustate = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
|
@ -1,36 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPOPTS_CONF_H
|
||||
#define LWIPOPTS_CONF_H
|
||||
|
||||
#define LWIP_TRANSPORT_ETHERNET 1
|
||||
|
||||
#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
|
||||
#define MEM_SIZE 15360
|
||||
#elif defined(TARGET_LPC1768)
|
||||
#define MEM_SIZE 16362
|
||||
#endif
|
||||
|
||||
#if defined (TOOLCHAIN_GCC_CR)
|
||||
/* For LPCXpresso IDE above v8.0.0 to avoid clash with timeval struct */
|
||||
#include <sys/time.h>
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,26 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPOPTS_CONF_H
|
||||
#define LWIPOPTS_CONF_H
|
||||
|
||||
#define LWIP_TRANSPORT_ETHERNET 1
|
||||
|
||||
#define MEM_SIZE (1600 * 16)
|
||||
|
||||
#endif
|
|
@ -1,194 +0,0 @@
|
|||
#include "lwip/opt.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "mbed_interface.h"
|
||||
#include "ethernet_api.h"
|
||||
#include "ethernetext_api.h"
|
||||
|
||||
#define RECV_TASK_PRI (osPriorityNormal)
|
||||
#define PHY_TASK_PRI (osPriorityNormal)
|
||||
#define PHY_TASK_WAIT (200)
|
||||
|
||||
/* memory */
|
||||
static sys_sem_t recv_ready_sem; /* receive ready semaphore */
|
||||
|
||||
/* function */
|
||||
static void rza1_recv_task(void *arg);
|
||||
static void rza1_phy_task(void *arg);
|
||||
static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
|
||||
static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p);
|
||||
static void rza1_recv_callback(void);
|
||||
|
||||
static void rza1_recv_task(void *arg) {
|
||||
struct netif *netif = (struct netif*)arg;
|
||||
struct eth_hdr *ethhdr;
|
||||
u16_t recv_size;
|
||||
struct pbuf *p;
|
||||
int cnt;
|
||||
|
||||
while (1) {
|
||||
sys_arch_sem_wait(&recv_ready_sem, 0);
|
||||
for (cnt = 0; cnt < 16; cnt++) {
|
||||
recv_size = ethernet_receive();
|
||||
if (recv_size != 0) {
|
||||
p = pbuf_alloc(PBUF_RAW, recv_size, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
(void)ethernet_read((char *)p->payload, p->len);
|
||||
ethhdr = p->payload;
|
||||
switch (htons(ethhdr->type)) {
|
||||
case ETHTYPE_IP:
|
||||
case ETHTYPE_ARP:
|
||||
#if PPPOE_SUPPORT
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
/* Free buffer */
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Return buffer */
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rza1_phy_task(void *arg) {
|
||||
struct netif *netif = (struct netif*)arg;
|
||||
s32_t connect_sts = 0; /* 0: disconnect, 1:connect */
|
||||
s32_t link_sts;
|
||||
s32_t link_mode_new = NEGO_FAIL;
|
||||
s32_t link_mode_old = NEGO_FAIL;
|
||||
|
||||
while (1) {
|
||||
link_sts = ethernet_link();
|
||||
if (link_sts == 1) {
|
||||
link_mode_new = ethernetext_chk_link_mode();
|
||||
if (link_mode_new != link_mode_old) {
|
||||
if (connect_sts == 1) {
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
||||
}
|
||||
if (link_mode_new != NEGO_FAIL) {
|
||||
ethernetext_set_link_mode(link_mode_new);
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
|
||||
connect_sts = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (connect_sts != 0) {
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
||||
link_mode_new = NEGO_FAIL;
|
||||
connect_sts = 0;
|
||||
}
|
||||
}
|
||||
link_mode_old = link_mode_new;
|
||||
osDelay(PHY_TASK_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) {
|
||||
/* Only send packet is link is up */
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
return etharp_output(netif, q, ipaddr);
|
||||
}
|
||||
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p) {
|
||||
struct pbuf *q;
|
||||
s32_t cnt;
|
||||
err_t err = ERR_MEM;
|
||||
s32_t write_size = 0;
|
||||
|
||||
if ((p->payload != NULL) && (p->len != 0)) {
|
||||
/* If the first data can't be written, transmit descriptor is full. */
|
||||
for (cnt = 0; cnt < 100; cnt++) {
|
||||
write_size = ethernet_write((char *)p->payload, p->len);
|
||||
if (write_size != 0) {
|
||||
break;
|
||||
}
|
||||
osDelay(1);
|
||||
}
|
||||
if (write_size != 0) {
|
||||
for (q = p->next; q != NULL; q = q->next) {
|
||||
(void)ethernet_write((char *)q->payload, q->len);
|
||||
}
|
||||
if (ethernet_send() == 1) {
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rza1_recv_callback(void) {
|
||||
sys_sem_signal(&recv_ready_sem);
|
||||
}
|
||||
|
||||
err_t eth_arch_enetif_init(struct netif *netif)
|
||||
{
|
||||
ethernet_cfg_t ethcfg;
|
||||
|
||||
/* set MAC hardware address */
|
||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
|
||||
netif->hwaddr[0] = MBED_MAC_ADDR_0;
|
||||
netif->hwaddr[1] = MBED_MAC_ADDR_1;
|
||||
netif->hwaddr[2] = MBED_MAC_ADDR_2;
|
||||
netif->hwaddr[3] = MBED_MAC_ADDR_3;
|
||||
netif->hwaddr[4] = MBED_MAC_ADDR_4;
|
||||
netif->hwaddr[5] = MBED_MAC_ADDR_5;
|
||||
#else
|
||||
mbed_mac_address((char *)netif->hwaddr);
|
||||
#endif
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwiprza1";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->output = rza1_etharp_output;
|
||||
netif->linkoutput = rza1_low_level_output;
|
||||
|
||||
/* Initialize the hardware */
|
||||
ethcfg.int_priority = 6;
|
||||
ethcfg.recv_cb = &rza1_recv_callback;
|
||||
ethcfg.ether_mac = (char *)netif->hwaddr;
|
||||
ethernetext_init(ðcfg);
|
||||
|
||||
/* semaphore */
|
||||
sys_sem_new(&recv_ready_sem, 0);
|
||||
|
||||
/* task */
|
||||
sys_thread_new("rza1_recv_task", rza1_recv_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
|
||||
sys_thread_new("rza1_phy_task", rza1_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void eth_arch_enable_interrupts(void) {
|
||||
ethernetext_start_stop(1);
|
||||
}
|
||||
|
||||
void eth_arch_disable_interrupts(void) {
|
||||
ethernetext_start_stop(0);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/* Copyright (C) 2015 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPOPTS_CONF_H
|
||||
#define LWIPOPTS_CONF_H
|
||||
|
||||
#define LWIP_TRANSPORT_ETHERNET 1
|
||||
|
||||
#define MEM_SIZE (1600 * 16)
|
||||
|
||||
#endif
|
|
@ -1,560 +0,0 @@
|
|||
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/timers.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include <string.h>
|
||||
#include "cmsis_os.h"
|
||||
#include "mbed_interface.h"
|
||||
|
||||
/** @defgroup lwipstm32f4xx_emac_DRIVER stm32f4 EMAC driver for LWIP
|
||||
* @ingroup lwip_emac
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define RECV_TASK_PRI (osPriorityHigh)
|
||||
#define PHY_TASK_PRI (osPriorityLow)
|
||||
#define PHY_TASK_WAIT (200)
|
||||
|
||||
|
||||
#if defined (__ICCARM__) /*!< IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif
|
||||
__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END; /* Ethernet Rx MA Descriptor */
|
||||
|
||||
#if defined (__ICCARM__) /*!< IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif
|
||||
__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END; /* Ethernet Tx DMA Descriptor */
|
||||
|
||||
#if defined (__ICCARM__) /*!< IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif
|
||||
__ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */
|
||||
|
||||
#if defined (__ICCARM__) /*!< IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif
|
||||
__ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */
|
||||
|
||||
|
||||
ETH_HandleTypeDef heth;
|
||||
|
||||
static sys_sem_t rx_ready_sem; /* receive ready semaphore */
|
||||
static sys_mutex_t tx_lock_mutex;
|
||||
|
||||
/* function */
|
||||
static void stm32f4_rx_task(void *arg);
|
||||
static void stm32f4_phy_task(void *arg);
|
||||
static err_t stm32f4_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
|
||||
static err_t stm32f4_low_level_output(struct netif *netif, struct pbuf *p);
|
||||
|
||||
/**
|
||||
* Override HAL Eth Init function
|
||||
*/
|
||||
void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if (heth->Instance == ETH) {
|
||||
/* Peripheral clock enable */
|
||||
__ETH_CLK_ENABLE();
|
||||
|
||||
__GPIOA_CLK_ENABLE();
|
||||
__GPIOB_CLK_ENABLE();
|
||||
__GPIOC_CLK_ENABLE();
|
||||
|
||||
/**ETH GPIO Configuration
|
||||
PC1 ------> ETH_MDC
|
||||
PA1 ------> ETH_REF_CLK
|
||||
PA2 ------> ETH_MDIO
|
||||
PA7 ------> ETH_CRS_DV
|
||||
PC4 ------> ETH_RXD0
|
||||
PC5 ------> ETH_RXD1
|
||||
PB11 ------> ETH_TX_EN
|
||||
PB12 ------> ETH_TXD0
|
||||
PB13 ------> ETH_TXD1
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* Peripheral interrupt init*/
|
||||
/* Sets the priority grouping field */
|
||||
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
|
||||
HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(ETH_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override HAL Eth DeInit function
|
||||
*/
|
||||
void HAL_ETH_MspDeInit(ETH_HandleTypeDef* heth)
|
||||
{
|
||||
if (heth->Instance == ETH) {
|
||||
/* Peripheral clock disable */
|
||||
__ETH_CLK_DISABLE();
|
||||
|
||||
/**ETH GPIO Configuration
|
||||
PC1 ------> ETH_MDC
|
||||
PA1 ------> ETH_REF_CLK
|
||||
PA2 ------> ETH_MDIO
|
||||
PA7 ------> ETH_CRS_DV
|
||||
PC4 ------> ETH_RXD0
|
||||
PC5 ------> ETH_RXD1
|
||||
PB11 ------> ETH_TX_EN
|
||||
PB12 ------> ETH_TXD0
|
||||
PB13 ------> ETH_TXD1
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13);
|
||||
|
||||
/* Peripheral interrupt Deinit*/
|
||||
HAL_NVIC_DisableIRQ(ETH_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ethernet Rx Transfer completed callback
|
||||
*
|
||||
* @param heth: ETH handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
|
||||
{
|
||||
|
||||
sys_sem_signal(&rx_ready_sem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ethernet IRQ Handler
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void ETH_IRQHandler(void)
|
||||
{
|
||||
HAL_ETH_IRQHandler(&heth);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* In this function, the hardware should be initialized.
|
||||
* Called from eth_arch_enetif_init().
|
||||
*
|
||||
* @param netif the already initialized lwip network interface structure
|
||||
* for this ethernetif
|
||||
*/
|
||||
static void stm32f4_low_level_init(struct netif *netif)
|
||||
{
|
||||
uint32_t regvalue = 0;
|
||||
HAL_StatusTypeDef hal_eth_init_status;
|
||||
|
||||
/* Init ETH */
|
||||
uint8_t MACAddr[6];
|
||||
heth.Instance = ETH;
|
||||
heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
|
||||
heth.Init.Speed = ETH_SPEED_10M;
|
||||
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
|
||||
heth.Init.PhyAddress = 1;
|
||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
|
||||
MACAddr[0] = MBED_MAC_ADDR_0;
|
||||
MACAddr[1] = MBED_MAC_ADDR_1;
|
||||
MACAddr[2] = MBED_MAC_ADDR_2;
|
||||
MACAddr[3] = MBED_MAC_ADDR_3;
|
||||
MACAddr[4] = MBED_MAC_ADDR_4;
|
||||
MACAddr[5] = MBED_MAC_ADDR_5;
|
||||
#else
|
||||
mbed_mac_address((char *)MACAddr);
|
||||
#endif
|
||||
heth.Init.MACAddr = &MACAddr[0];
|
||||
heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
|
||||
heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
|
||||
heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
|
||||
hal_eth_init_status = HAL_ETH_Init(&heth);
|
||||
|
||||
if (hal_eth_init_status == HAL_OK) {
|
||||
/* Set netif link flag */
|
||||
netif->flags |= NETIF_FLAG_LINK_UP;
|
||||
}
|
||||
|
||||
/* Initialize Tx Descriptors list: Chain Mode */
|
||||
HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
|
||||
|
||||
/* Initialize Rx Descriptors list: Chain Mode */
|
||||
HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
|
||||
|
||||
#if LWIP_ARP || LWIP_ETHERNET
|
||||
/* set MAC hardware address length */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* set MAC hardware address */
|
||||
netif->hwaddr[0] = heth.Init.MACAddr[0];
|
||||
netif->hwaddr[1] = heth.Init.MACAddr[1];
|
||||
netif->hwaddr[2] = heth.Init.MACAddr[2];
|
||||
netif->hwaddr[3] = heth.Init.MACAddr[3];
|
||||
netif->hwaddr[4] = heth.Init.MACAddr[4];
|
||||
netif->hwaddr[5] = heth.Init.MACAddr[5];
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
|
||||
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
|
||||
|
||||
/* Enable MAC and DMA transmission and reception */
|
||||
HAL_ETH_Start(&heth);
|
||||
|
||||
/**** Configure PHY to generate an interrupt when Eth Link state changes ****/
|
||||
/* Read Register Configuration */
|
||||
HAL_ETH_ReadPHYRegister(&heth, PHY_MICR, ®value);
|
||||
|
||||
regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);
|
||||
|
||||
/* Enable Interrupts */
|
||||
HAL_ETH_WritePHYRegister(&heth, PHY_MICR, regvalue);
|
||||
|
||||
/* Read Register Configuration */
|
||||
HAL_ETH_ReadPHYRegister(&heth, PHY_MISR, ®value);
|
||||
|
||||
regvalue |= PHY_MISR_LINK_INT_EN;
|
||||
|
||||
/* Enable Interrupt on change of link status */
|
||||
HAL_ETH_WritePHYRegister(&heth, PHY_MISR, regvalue);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should do the actual transmission of the packet. The packet is
|
||||
* contained in the pbuf that is passed to the function. This pbuf
|
||||
* might be chained.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
||||
* @return ERR_OK if the packet could be sent
|
||||
* an err_t value if the packet couldn't be sent
|
||||
*
|
||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
||||
* strange results. You might consider waiting for space in the DMA queue
|
||||
* to become availale since the stack doesn't retry to send a packet
|
||||
* dropped because of memory failure (except for the TCP timers).
|
||||
*/
|
||||
|
||||
static err_t stm32f4_low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
err_t errval;
|
||||
struct pbuf *q;
|
||||
uint8_t *buffer = (uint8_t*)(heth.TxDesc->Buffer1Addr);
|
||||
__IO ETH_DMADescTypeDef *DmaTxDesc;
|
||||
uint32_t framelength = 0;
|
||||
uint32_t bufferoffset = 0;
|
||||
uint32_t byteslefttocopy = 0;
|
||||
uint32_t payloadoffset = 0;
|
||||
DmaTxDesc = heth.TxDesc;
|
||||
bufferoffset = 0;
|
||||
|
||||
|
||||
sys_mutex_lock(&tx_lock_mutex);
|
||||
|
||||
/* copy frame from pbufs to driver buffers */
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
/* Is this buffer available? If not, goto error */
|
||||
if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
|
||||
errval = ERR_USE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get bytes in current lwIP buffer */
|
||||
byteslefttocopy = q->len;
|
||||
payloadoffset = 0;
|
||||
|
||||
/* Check if the length of data to copy is bigger than Tx buffer size*/
|
||||
while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE) {
|
||||
/* Copy data to Tx buffer*/
|
||||
memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));
|
||||
|
||||
/* Point to next descriptor */
|
||||
DmaTxDesc = (ETH_DMADescTypeDef*)(DmaTxDesc->Buffer2NextDescAddr);
|
||||
|
||||
/* Check if the buffer is available */
|
||||
if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
|
||||
errval = ERR_USE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer = (uint8_t*)(DmaTxDesc->Buffer1Addr);
|
||||
|
||||
byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
|
||||
payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
|
||||
framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
|
||||
bufferoffset = 0;
|
||||
}
|
||||
|
||||
/* Copy the remaining bytes */
|
||||
memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy);
|
||||
bufferoffset = bufferoffset + byteslefttocopy;
|
||||
framelength = framelength + byteslefttocopy;
|
||||
}
|
||||
|
||||
/* Prepare transmit descriptors to give to DMA */
|
||||
HAL_ETH_TransmitFrame(&heth, framelength);
|
||||
|
||||
errval = ERR_OK;
|
||||
|
||||
error:
|
||||
|
||||
/* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
|
||||
if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) {
|
||||
/* Clear TUS ETHERNET DMA flag */
|
||||
heth.Instance->DMASR = ETH_DMASR_TUS;
|
||||
|
||||
/* Resume DMA transmission*/
|
||||
heth.Instance->DMATPDR = 0;
|
||||
}
|
||||
|
||||
sys_mutex_unlock(&tx_lock_mutex);
|
||||
|
||||
return errval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should allocate a pbuf and transfer the bytes of the incoming
|
||||
* packet from the interface into the pbuf.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return a pbuf filled with the received packet (including MAC header)
|
||||
* NULL on memory error
|
||||
*/
|
||||
static struct pbuf * stm32f4_low_level_input(struct netif *netif)
|
||||
{
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf *q;
|
||||
uint16_t len = 0;
|
||||
uint8_t *buffer;
|
||||
__IO ETH_DMADescTypeDef *dmarxdesc;
|
||||
uint32_t bufferoffset = 0;
|
||||
uint32_t payloadoffset = 0;
|
||||
uint32_t byteslefttocopy = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
|
||||
/* get received frame */
|
||||
if (HAL_ETH_GetReceivedFrame(&heth) != HAL_OK)
|
||||
return NULL;
|
||||
|
||||
/* Obtain the size of the packet and put it into the "len" variable. */
|
||||
len = heth.RxFrameInfos.length;
|
||||
buffer = (uint8_t*)heth.RxFrameInfos.buffer;
|
||||
|
||||
if (len > 0) {
|
||||
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
|
||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||
}
|
||||
|
||||
if (p != NULL) {
|
||||
dmarxdesc = heth.RxFrameInfos.FSRxDesc;
|
||||
bufferoffset = 0;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
byteslefttocopy = q->len;
|
||||
payloadoffset = 0;
|
||||
|
||||
/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
|
||||
while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE) {
|
||||
/* Copy data to pbuf */
|
||||
memcpy((uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
|
||||
|
||||
/* Point to next descriptor */
|
||||
dmarxdesc = (ETH_DMADescTypeDef*)(dmarxdesc->Buffer2NextDescAddr);
|
||||
buffer = (uint8_t*)(dmarxdesc->Buffer1Addr);
|
||||
|
||||
byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
|
||||
payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
|
||||
bufferoffset = 0;
|
||||
}
|
||||
/* Copy remaining data in pbuf */
|
||||
memcpy((uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);
|
||||
bufferoffset = bufferoffset + byteslefttocopy;
|
||||
}
|
||||
|
||||
/* Release descriptors to DMA */
|
||||
/* Point to first descriptor */
|
||||
dmarxdesc = heth.RxFrameInfos.FSRxDesc;
|
||||
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
|
||||
for (i = 0; i < heth.RxFrameInfos.SegCount; i++) {
|
||||
dmarxdesc->Status |= ETH_DMARXDESC_OWN;
|
||||
dmarxdesc = (ETH_DMADescTypeDef*)(dmarxdesc->Buffer2NextDescAddr);
|
||||
}
|
||||
|
||||
/* Clear Segment_Count */
|
||||
heth.RxFrameInfos.SegCount = 0;
|
||||
}
|
||||
|
||||
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
|
||||
if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
|
||||
/* Clear RBUS ETHERNET DMA flag */
|
||||
heth.Instance->DMASR = ETH_DMASR_RBUS;
|
||||
/* Resume DMA reception */
|
||||
heth.Instance->DMARPDR = 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* This task receives input data
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure
|
||||
*/
|
||||
static void stm32f4_rx_task(void *arg)
|
||||
{
|
||||
struct netif *netif = (struct netif*)arg;
|
||||
struct pbuf *p;
|
||||
|
||||
while (1) {
|
||||
sys_arch_sem_wait(&rx_ready_sem, 0);
|
||||
p = stm32f4_low_level_input(netif);
|
||||
if (p != NULL) {
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This task checks phy link status and updates net status
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure
|
||||
*/
|
||||
static void stm32f4_phy_task(void *arg)
|
||||
{
|
||||
struct netif *netif = (struct netif*)arg;
|
||||
uint32_t phy_status = 0;
|
||||
|
||||
while (1) {
|
||||
uint32_t status;
|
||||
if (HAL_ETH_ReadPHYRegister(&heth, PHY_SR, &status) == HAL_OK) {
|
||||
if ((status & PHY_LINK_STATUS) && !(phy_status & PHY_LINK_STATUS)) {
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
|
||||
} else if (!(status & PHY_LINK_STATUS) && (phy_status & PHY_LINK_STATUS)) {
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
||||
}
|
||||
|
||||
phy_status = status;
|
||||
}
|
||||
|
||||
osDelay(PHY_TASK_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is the ethernet packet send function. It calls
|
||||
* etharp_output after checking link status.
|
||||
*
|
||||
* \param[in] netif the lwip network interface structure for this lpc_enetif
|
||||
* \param[in] q Pointer to pbug to send
|
||||
* \param[in] ipaddr IP address
|
||||
* \return ERR_OK or error code
|
||||
*/
|
||||
static err_t stm32f4_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
|
||||
{
|
||||
/* Only send packet is link is up */
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
return etharp_output(netif, q, ipaddr);
|
||||
}
|
||||
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* network interface.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param[in] netif the lwip network interface structure for this lpc_enetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t eth_arch_enetif_init(struct netif *netif)
|
||||
{
|
||||
/* set MAC hardware address */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwipstm32f4";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->output = stm32f4_etharp_output;
|
||||
netif->linkoutput = stm32f4_low_level_output;
|
||||
|
||||
/* semaphore */
|
||||
sys_sem_new(&rx_ready_sem, 0);
|
||||
|
||||
sys_mutex_new(&tx_lock_mutex);
|
||||
|
||||
/* task */
|
||||
sys_thread_new("stm32f4_recv_task", stm32f4_rx_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
|
||||
sys_thread_new("stm32f4_phy_task", stm32f4_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
|
||||
|
||||
/* initialize the hardware */
|
||||
stm32f4_low_level_init(netif);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void eth_arch_enable_interrupts(void)
|
||||
{
|
||||
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
|
||||
HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(ETH_IRQn);
|
||||
}
|
||||
|
||||
void eth_arch_disable_interrupts(void)
|
||||
{
|
||||
NVIC_DisableIRQ(ETH_IRQn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
|
@ -1,26 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LWIPOPTS_CONF_H
|
||||
#define LWIPOPTS_CONF_H
|
||||
|
||||
#define LWIP_TRANSPORT_ETHERNET 1
|
||||
|
||||
#define MEM_SIZE (1600 * 16)
|
||||
|
||||
#endif
|
|
@ -1,194 +0,0 @@
|
|||
#include "lwip/opt.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "mbed_interface.h"
|
||||
#include "ethernet_api.h"
|
||||
#include "ethernetext_api.h"
|
||||
|
||||
#define RECV_TASK_PRI (osPriorityNormal)
|
||||
#define PHY_TASK_PRI (osPriorityNormal)
|
||||
#define PHY_TASK_WAIT (200)
|
||||
|
||||
/* memory */
|
||||
static sys_sem_t recv_ready_sem; /* receive ready semaphore */
|
||||
|
||||
/* function */
|
||||
static void rza1_recv_task(void *arg);
|
||||
static void rza1_phy_task(void *arg);
|
||||
static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
|
||||
static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p);
|
||||
static void rza1_recv_callback(void);
|
||||
|
||||
static void rza1_recv_task(void *arg) {
|
||||
struct netif *netif = (struct netif*)arg;
|
||||
struct eth_hdr *ethhdr;
|
||||
u16_t recv_size;
|
||||
struct pbuf *p;
|
||||
int cnt;
|
||||
|
||||
while (1) {
|
||||
sys_arch_sem_wait(&recv_ready_sem, 0);
|
||||
for (cnt = 0; cnt < 16; cnt++) {
|
||||
recv_size = ethernet_receive();
|
||||
if (recv_size != 0) {
|
||||
p = pbuf_alloc(PBUF_RAW, recv_size, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
(void)ethernet_read((char *)p->payload, p->len);
|
||||
ethhdr = p->payload;
|
||||
switch (htons(ethhdr->type)) {
|
||||
case ETHTYPE_IP:
|
||||
case ETHTYPE_ARP:
|
||||
#if PPPOE_SUPPORT
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
/* Free buffer */
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Return buffer */
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rza1_phy_task(void *arg) {
|
||||
struct netif *netif = (struct netif*)arg;
|
||||
s32_t connect_sts = 0; /* 0: disconnect, 1:connect */
|
||||
s32_t link_sts;
|
||||
s32_t link_mode_new = NEGO_FAIL;
|
||||
s32_t link_mode_old = NEGO_FAIL;
|
||||
|
||||
while (1) {
|
||||
link_sts = ethernet_link();
|
||||
if (link_sts == 1) {
|
||||
link_mode_new = ethernetext_chk_link_mode();
|
||||
if (link_mode_new != link_mode_old) {
|
||||
if (connect_sts == 1) {
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
||||
}
|
||||
if (link_mode_new != NEGO_FAIL) {
|
||||
ethernetext_set_link_mode(link_mode_new);
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
|
||||
connect_sts = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (connect_sts != 0) {
|
||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
||||
link_mode_new = NEGO_FAIL;
|
||||
connect_sts = 0;
|
||||
}
|
||||
}
|
||||
link_mode_old = link_mode_new;
|
||||
osDelay(PHY_TASK_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) {
|
||||
/* Only send packet is link is up */
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
return etharp_output(netif, q, ipaddr);
|
||||
}
|
||||
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p) {
|
||||
struct pbuf *q;
|
||||
s32_t cnt;
|
||||
err_t err = ERR_MEM;
|
||||
s32_t write_size = 0;
|
||||
|
||||
if ((p->payload != NULL) && (p->len != 0)) {
|
||||
/* If the first data can't be written, transmit descriptor is full. */
|
||||
for (cnt = 0; cnt < 100; cnt++) {
|
||||
write_size = ethernet_write((char *)p->payload, p->len);
|
||||
if (write_size != 0) {
|
||||
break;
|
||||
}
|
||||
osDelay(1);
|
||||
}
|
||||
if (write_size != 0) {
|
||||
for (q = p->next; q != NULL; q = q->next) {
|
||||
(void)ethernet_write((char *)q->payload, q->len);
|
||||
}
|
||||
if (ethernet_send() == 1) {
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rza1_recv_callback(void) {
|
||||
sys_sem_signal(&recv_ready_sem);
|
||||
}
|
||||
|
||||
err_t eth_arch_enetif_init(struct netif *netif)
|
||||
{
|
||||
ethernet_cfg_t ethcfg;
|
||||
|
||||
/* set MAC hardware address */
|
||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
|
||||
netif->hwaddr[0] = MBED_MAC_ADDR_0;
|
||||
netif->hwaddr[1] = MBED_MAC_ADDR_1;
|
||||
netif->hwaddr[2] = MBED_MAC_ADDR_2;
|
||||
netif->hwaddr[3] = MBED_MAC_ADDR_3;
|
||||
netif->hwaddr[4] = MBED_MAC_ADDR_4;
|
||||
netif->hwaddr[5] = MBED_MAC_ADDR_5;
|
||||
#else
|
||||
mbed_mac_address((char *)netif->hwaddr);
|
||||
#endif
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwiprza1";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->output = rza1_etharp_output;
|
||||
netif->linkoutput = rza1_low_level_output;
|
||||
|
||||
/* Initialize the hardware */
|
||||
ethcfg.int_priority = 6;
|
||||
ethcfg.recv_cb = &rza1_recv_callback;
|
||||
ethcfg.ether_mac = (char *)netif->hwaddr;
|
||||
ethernetext_init(ðcfg);
|
||||
|
||||
/* semaphore */
|
||||
sys_sem_new(&recv_ready_sem, 0);
|
||||
|
||||
/* task */
|
||||
sys_thread_new("rza1_recv_task", rza1_recv_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
|
||||
sys_thread_new("rza1_phy_task", rza1_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void eth_arch_enable_interrupts(void) {
|
||||
ethernetext_start_stop(1);
|
||||
}
|
||||
|
||||
void eth_arch_disable_interrupts(void) {
|
||||
ethernetext_start_stop(0);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#include "HTTPHeader.h"
|
||||
#include <stdlib.h>
|
||||
using std::map;
|
||||
using std::string;
|
||||
|
||||
HTTPHeader::HTTPHeader():
|
||||
_status(HTTP_ERROR),
|
||||
_fields()
|
||||
{
|
||||
}
|
||||
|
||||
std::string HTTPHeader::getField(const std::string& name)
|
||||
{
|
||||
map<string,string>::iterator itor = _fields.find(name);
|
||||
if(itor == _fields.end())
|
||||
return string();
|
||||
return itor->second;
|
||||
}
|
||||
|
||||
int HTTPHeader::getBodyLength()
|
||||
{
|
||||
return atoi(getField("Content-Length").c_str());
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef HTTPHEADER_H
|
||||
#define HTTPHEADER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
enum HTTPStatus { HTTP_OK, HTTP_ERROR };
|
||||
|
||||
class HTTPSClient;
|
||||
|
||||
class HTTPHeader
|
||||
{
|
||||
friend class HTTPSClient;
|
||||
|
||||
public :
|
||||
|
||||
HTTPHeader();
|
||||
|
||||
std::string getField(const std::string& name);
|
||||
int getBodyLength();
|
||||
|
||||
private :
|
||||
|
||||
HTTPStatus _status;
|
||||
std::map<std::string, std::string> _fields;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,163 +0,0 @@
|
|||
#include "HTTPSClient.h"
|
||||
#include "HTTPHeader.h"
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "mbed.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using std::memset;
|
||||
using std::memcpy;
|
||||
using std::string;
|
||||
|
||||
const static int HTTPS_PORT = 443;
|
||||
char buf[256];
|
||||
|
||||
HTTPSClient::HTTPSClient() :
|
||||
_is_connected(false),
|
||||
_ssl_ctx(),
|
||||
_ssl(),
|
||||
_host() {
|
||||
}
|
||||
|
||||
HTTPSClient::~HTTPSClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
int HTTPSClient::connect(const char* host) {
|
||||
if (init_socket(SOCK_STREAM) < 0)
|
||||
return -1;
|
||||
|
||||
if (set_address(host, HTTPS_PORT) != 0)
|
||||
return -1;
|
||||
|
||||
if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) {
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ssl_ctx_new(&_ssl_ctx, SSL_SERVER_VERIFY_LATER, SSL_DEFAULT_CLNT_SESS) != &_ssl_ctx)
|
||||
return -1;
|
||||
|
||||
_ssl.ssl_ctx = &_ssl_ctx;
|
||||
|
||||
if(ssl_client_new(&_ssl, _sock_fd, NULL, 0) == NULL)
|
||||
{
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
if(_ssl.hs_status != SSL_OK)
|
||||
{
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
_is_connected = true;
|
||||
_host = host;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HTTPSClient::is_connected(void) {
|
||||
return _is_connected;
|
||||
}
|
||||
|
||||
int HTTPSClient::send(char* data, int length) {
|
||||
if ((_sock_fd < 0) || !_is_connected)
|
||||
return -1;
|
||||
|
||||
return ssl_write(&_ssl, (uint8_t*)data, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HTTPHeader HTTPSClient::get(char *request)
|
||||
{
|
||||
if((_sock_fd < 0) || !_is_connected)
|
||||
return HTTPHeader();
|
||||
|
||||
sprintf(buf, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", request, _host.c_str());
|
||||
printf("buf=%s\n", buf);
|
||||
if(send(buf, strlen(buf)) != strlen(buf))
|
||||
return HTTPHeader();
|
||||
printf("Finished sending request\n");
|
||||
return read_header();
|
||||
}
|
||||
|
||||
|
||||
HTTPHeader HTTPSClient::read_header()
|
||||
{
|
||||
_ssl.bm_read_index = 0;
|
||||
_ssl.bm_index = 0;
|
||||
HTTPHeader hdr;
|
||||
if(read_line())
|
||||
return hdr;
|
||||
|
||||
int status;
|
||||
|
||||
if(sscanf(buf, "HTTP/%*d.%*d %d %*s", &status) == -1)
|
||||
return hdr;
|
||||
|
||||
if(status == 200)
|
||||
hdr._status = HTTP_OK;
|
||||
if(read_line())
|
||||
return hdr;
|
||||
do
|
||||
{
|
||||
string tmp(buf);
|
||||
std::size_t sep = tmp.find(':');
|
||||
string name = tmp.substr(0, sep);
|
||||
string value = tmp.substr(sep+2, tmp.size());
|
||||
hdr._fields[name] = value;
|
||||
if(read_line())
|
||||
return hdr;
|
||||
}while(strlen(buf));
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
uint8_t HTTPSClient::read_line()
|
||||
{
|
||||
int index = 0;
|
||||
do
|
||||
{
|
||||
if(ssl_read(&_ssl, (uint8_t*)(&buf[index]), 1) != 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
index++;
|
||||
}while(buf[index-1] != '\r' && index < 256);
|
||||
ssl_read(&_ssl, (uint8_t*)(&buf[index-1]), 1); // skip '\n'
|
||||
buf[index-1] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -1:error
|
||||
// otherwise return nb of characters read. Cannot be > than len
|
||||
int HTTPSClient::read(char *data, int len)
|
||||
{
|
||||
return ssl_read(&_ssl, (uint8_t*)data, len);
|
||||
}
|
||||
/*
|
||||
0 : must close connection
|
||||
-1 : error
|
||||
else : get data
|
||||
|
||||
int HTTPSClient::receive(char* data, int length) {
|
||||
if ((_sock_fd < 0) || !_is_connected)
|
||||
return -1;
|
||||
|
||||
if(read_record(&_ssl) < 0)
|
||||
return -1;
|
||||
return process_data(&_ssl, (uint8_t*)data, length);
|
||||
}
|
||||
*/
|
||||
void HTTPSClient::close()
|
||||
{
|
||||
if(!_is_connected)
|
||||
return;
|
||||
ssl_ctx_free(_ssl.ssl_ctx);
|
||||
Socket::close();
|
||||
_is_connected = false;
|
||||
_host.clear();
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
#ifndef HTTPSCLIENT_H
|
||||
#define HTTPSCLIENT_H
|
||||
|
||||
#include "Socket/Socket.h"
|
||||
#include "Socket/Endpoint.h"
|
||||
#include "axTLS/ssl/ssl.h"
|
||||
#include "HTTPHeader.h"
|
||||
|
||||
/**
|
||||
TCP socket connection
|
||||
*/
|
||||
class HTTPSClient : public Socket, public Endpoint {
|
||||
|
||||
public:
|
||||
/** TCP socket connection
|
||||
*/
|
||||
HTTPSClient();
|
||||
|
||||
|
||||
virtual ~HTTPSClient();
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
\param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS.
|
||||
\param port The host's port to connect to.
|
||||
\return 0 on success, -1 on failure.
|
||||
*/
|
||||
int connect(const char* host);
|
||||
|
||||
/** Check if the socket is connected
|
||||
\return true if connected, false otherwise.
|
||||
*/
|
||||
bool is_connected(void);
|
||||
|
||||
// Returns the size of the body
|
||||
HTTPHeader get(char *path);
|
||||
|
||||
int read(char *data, int len);
|
||||
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
int send(char* data, int length);
|
||||
|
||||
uint8_t read_line();
|
||||
HTTPHeader read_header();
|
||||
|
||||
bool _is_connected;
|
||||
SSL_CTX _ssl_ctx;
|
||||
SSL _ssl;
|
||||
std::string _host;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,460 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AES implementation - this is a small code version. There are much faster
|
||||
* versions around but they are much larger in size (i.e. they use large
|
||||
* submix tables).
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
//#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
#include <lwip/def.h>
|
||||
|
||||
/* all commented out in skeleton mode */
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
|
||||
#define rot1(x) (((x) << 24) | ((x) >> 8))
|
||||
#define rot2(x) (((x) << 16) | ((x) >> 16))
|
||||
#define rot3(x) (((x) << 8) | ((x) >> 24))
|
||||
|
||||
/*
|
||||
* This cute trick does 4 'mul by two' at once. Stolen from
|
||||
* Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
|
||||
* a standard graphics trick
|
||||
* The key to this is that we need to xor with 0x1b if the top bit is set.
|
||||
* a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
|
||||
* b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
|
||||
* c 0000 0001 0000 0000 we then subtract (c) from (b)
|
||||
* d 0111 1111 0000 0000 and now we and with our mask
|
||||
* e 0001 1011 0000 0000
|
||||
*/
|
||||
#define mt 0x80808080
|
||||
#define ml 0x7f7f7f7f
|
||||
#define mh 0xfefefefe
|
||||
#define mm 0x1b1b1b1b
|
||||
#define mul2(x,t) ((t)=((x)&mt), \
|
||||
((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
|
||||
|
||||
#define inv_mix_col(x,f2,f4,f8,f9) (\
|
||||
(f2)=mul2(x,f2), \
|
||||
(f4)=mul2(f2,f4), \
|
||||
(f8)=mul2(f4,f8), \
|
||||
(f9)=(x)^(f8), \
|
||||
(f8)=((f2)^(f4)^(f8)), \
|
||||
(f2)^=(f9), \
|
||||
(f4)^=(f9), \
|
||||
(f8)^=rot3(f2), \
|
||||
(f8)^=rot2(f4), \
|
||||
(f8)^rot1(f9))
|
||||
|
||||
/*
|
||||
* AES S-box
|
||||
*/
|
||||
static const uint8_t aes_sbox[256] =
|
||||
{
|
||||
0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
|
||||
0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
|
||||
0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
|
||||
0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
|
||||
0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
|
||||
0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
|
||||
0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
|
||||
0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
|
||||
0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
|
||||
0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
|
||||
0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
|
||||
0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
|
||||
0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
|
||||
0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
|
||||
0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
|
||||
0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
|
||||
0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
|
||||
0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
|
||||
0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
|
||||
0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
|
||||
0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
|
||||
0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
|
||||
0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
|
||||
0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
|
||||
0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
|
||||
0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
|
||||
0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
|
||||
0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
|
||||
0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
|
||||
0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
|
||||
0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
|
||||
0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
|
||||
};
|
||||
|
||||
/*
|
||||
* AES is-box
|
||||
*/
|
||||
static const uint8_t aes_isbox[256] =
|
||||
{
|
||||
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
|
||||
0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
|
||||
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
|
||||
0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
|
||||
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
|
||||
0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
|
||||
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
|
||||
0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
|
||||
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
|
||||
0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
|
||||
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
|
||||
0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
|
||||
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
|
||||
0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
|
||||
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
|
||||
0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
|
||||
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
|
||||
0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
|
||||
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
|
||||
0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
|
||||
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
|
||||
0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
|
||||
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
|
||||
0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
|
||||
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
|
||||
0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
|
||||
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
|
||||
0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
|
||||
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
|
||||
0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
|
||||
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
|
||||
0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
|
||||
};
|
||||
|
||||
static const unsigned char Rcon[30]=
|
||||
{
|
||||
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
|
||||
0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
|
||||
0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
|
||||
0xb3,0x7d,0xfa,0xef,0xc5,0x91,
|
||||
};
|
||||
|
||||
/* ----- static functions ----- */
|
||||
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
|
||||
/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
|
||||
x^8+x^4+x^3+x+1 */
|
||||
static unsigned char AES_xtime(uint32_t x)
|
||||
{
|
||||
return (x&0x80) ? (x<<1)^0x1b : x<<1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up AES with the key/iv and cipher size.
|
||||
*/
|
||||
void AES_set_key(AES_CTX *ctx, const uint8_t *key,
|
||||
const uint8_t *iv, AES_MODE mode)
|
||||
{
|
||||
int i, ii;
|
||||
uint32_t *W, tmp, tmp2;
|
||||
const unsigned char *ip;
|
||||
int words;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case AES_MODE_128:
|
||||
i = 10;
|
||||
words = 4;
|
||||
break;
|
||||
|
||||
case AES_MODE_256:
|
||||
i = 14;
|
||||
words = 8;
|
||||
break;
|
||||
|
||||
default: /* fail silently */
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->rounds = i;
|
||||
ctx->key_size = words;
|
||||
W = ctx->ks;
|
||||
for (i = 0; i < words; i+=2)
|
||||
{
|
||||
W[i+0]= ((uint32_t)key[ 0]<<24)|
|
||||
((uint32_t)key[ 1]<<16)|
|
||||
((uint32_t)key[ 2]<< 8)|
|
||||
((uint32_t)key[ 3] );
|
||||
W[i+1]= ((uint32_t)key[ 4]<<24)|
|
||||
((uint32_t)key[ 5]<<16)|
|
||||
((uint32_t)key[ 6]<< 8)|
|
||||
((uint32_t)key[ 7] );
|
||||
key += 8;
|
||||
}
|
||||
|
||||
ip = Rcon;
|
||||
ii = 4 * (ctx->rounds+1);
|
||||
for (i = words; i<ii; i++)
|
||||
{
|
||||
tmp = W[i-1];
|
||||
|
||||
if ((i % words) == 0)
|
||||
{
|
||||
tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
|
||||
tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
|
||||
tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
|
||||
tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
|
||||
tmp=tmp2^(((unsigned int)*ip)<<24);
|
||||
ip++;
|
||||
}
|
||||
|
||||
if ((words == 8) && ((i % words) == 4))
|
||||
{
|
||||
tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
|
||||
tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
|
||||
tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
|
||||
tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
|
||||
tmp=tmp2;
|
||||
}
|
||||
|
||||
W[i]=W[i-words]^tmp;
|
||||
}
|
||||
|
||||
/* copy the iv across */
|
||||
memcpy(ctx->iv, iv, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a key for decryption.
|
||||
*/
|
||||
void AES_convert_key(AES_CTX *ctx)
|
||||
{
|
||||
int i;
|
||||
uint32_t *k,w,t1,t2,t3,t4;
|
||||
|
||||
k = ctx->ks;
|
||||
k += 4;
|
||||
|
||||
for (i= ctx->rounds*4; i > 4; i--)
|
||||
{
|
||||
w= *k;
|
||||
w = inv_mix_col(w,t1,t2,t3,t4);
|
||||
*k++ =w;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a byte sequence (with a block size 16) using the AES cipher.
|
||||
*/
|
||||
void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
|
||||
{
|
||||
int i;
|
||||
uint32_t tin[4], tout[4], iv[4];
|
||||
|
||||
memcpy(iv, ctx->iv, AES_IV_SIZE);
|
||||
for (i = 0; i < 4; i++)
|
||||
tout[i] = ntohl(iv[i]);
|
||||
|
||||
for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
|
||||
{
|
||||
uint32_t msg_32[4];
|
||||
uint32_t out_32[4];
|
||||
memcpy(msg_32, msg, AES_BLOCKSIZE);
|
||||
msg += AES_BLOCKSIZE;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
tin[i] = ntohl(msg_32[i])^tout[i];
|
||||
|
||||
AES_encrypt(ctx, tin);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tout[i] = tin[i];
|
||||
out_32[i] = htonl(tout[i]);
|
||||
}
|
||||
|
||||
memcpy(out, out_32, AES_BLOCKSIZE);
|
||||
out += AES_BLOCKSIZE;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
iv[i] = htonl(tout[i]);
|
||||
memcpy(ctx->iv, iv, AES_IV_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a byte sequence (with a block size 16) using the AES cipher.
|
||||
*/
|
||||
void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
|
||||
{
|
||||
int i;
|
||||
uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
|
||||
|
||||
memcpy(iv, ctx->iv, AES_IV_SIZE);
|
||||
for (i = 0; i < 4; i++)
|
||||
xor[i] = ntohl(iv[i]);
|
||||
for (length -= 16; length >= 0; length -= 16)
|
||||
{
|
||||
uint32_t msg_32[4];
|
||||
uint32_t out_32[4];
|
||||
memcpy(msg_32, msg, AES_BLOCKSIZE);
|
||||
msg += AES_BLOCKSIZE;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tin[i] = ntohl(msg_32[i]);
|
||||
data[i] = tin[i];
|
||||
}
|
||||
|
||||
AES_decrypt(ctx, data);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tout[i] = data[i]^xor[i];
|
||||
xor[i] = tin[i];
|
||||
out_32[i] = htonl(tout[i]);
|
||||
}
|
||||
|
||||
memcpy(out, out_32, AES_BLOCKSIZE);
|
||||
out += AES_BLOCKSIZE;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
iv[i] = htonl(xor[i]);
|
||||
memcpy(ctx->iv, iv, AES_IV_SIZE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a single block (16 bytes) of data
|
||||
*/
|
||||
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
{
|
||||
/* To make this code smaller, generate the sbox entries on the fly.
|
||||
* This will have a really heavy effect upon performance.
|
||||
*/
|
||||
uint32_t tmp[4];
|
||||
uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
|
||||
int curr_rnd;
|
||||
int rounds = ctx->rounds;
|
||||
const uint32_t *k = ctx->ks;
|
||||
|
||||
/* Pre-round key addition */
|
||||
for (row = 0; row < 4; row++)
|
||||
data[row] ^= *(k++);
|
||||
|
||||
/* Encrypt one block. */
|
||||
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
|
||||
{
|
||||
/* Perform ByteSub and ShiftRow operations together */
|
||||
for (row = 0; row < 4; row++)
|
||||
{
|
||||
a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
|
||||
a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
|
||||
a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
|
||||
a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
|
||||
|
||||
/* Perform MixColumn iff not last round */
|
||||
if (curr_rnd < (rounds - 1))
|
||||
{
|
||||
tmp1 = a0 ^ a1 ^ a2 ^ a3;
|
||||
old_a0 = a0;
|
||||
a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
|
||||
a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
|
||||
a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
|
||||
a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
|
||||
}
|
||||
|
||||
tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
|
||||
}
|
||||
|
||||
/* KeyAddition - note that it is vital that this loop is separate from
|
||||
the MixColumn operation, which must be atomic...*/
|
||||
for (row = 0; row < 4; row++)
|
||||
data[row] = tmp[row] ^ *(k++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a single block (16 bytes) of data
|
||||
*/
|
||||
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
{
|
||||
uint32_t tmp[4];
|
||||
uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
|
||||
uint32_t a0, a1, a2, a3, row;
|
||||
int curr_rnd;
|
||||
int rounds = ctx->rounds;
|
||||
const uint32_t *k = ctx->ks + ((rounds+1)*4);
|
||||
/* pre-round key addition */
|
||||
for (row=4; row > 0;row--)
|
||||
data[row-1] ^= *(--k);
|
||||
|
||||
/* Decrypt one block */
|
||||
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
|
||||
{
|
||||
|
||||
/* Perform ByteSub and ShiftRow operations together */
|
||||
for (row = 4; row > 0; row--)
|
||||
{
|
||||
|
||||
a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
|
||||
a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
|
||||
a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
|
||||
a3 = aes_isbox[(data[row%4])&0xFF];
|
||||
|
||||
/* Perform MixColumn iff not last round */
|
||||
if (curr_rnd<(rounds-1))
|
||||
{
|
||||
/* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
|
||||
are quite large compared to encryption; this
|
||||
operation slows decryption down noticeably. */
|
||||
xt0 = AES_xtime(a0^a1);
|
||||
xt1 = AES_xtime(a1^a2);
|
||||
xt2 = AES_xtime(a2^a3);
|
||||
xt3 = AES_xtime(a3^a0);
|
||||
xt4 = AES_xtime(xt0^xt1);
|
||||
xt5 = AES_xtime(xt1^xt2);
|
||||
xt6 = AES_xtime(xt4^xt5);
|
||||
|
||||
xt0 ^= a1^a2^a3^xt4^xt6;
|
||||
xt1 ^= a0^a2^a3^xt5^xt6;
|
||||
xt2 ^= a0^a1^a3^xt4^xt6;
|
||||
xt3 ^= a0^a1^a2^xt5^xt6;
|
||||
tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
|
||||
}
|
||||
else
|
||||
tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
|
||||
}
|
||||
|
||||
for (row = 4; row > 0; row--)
|
||||
data[row-1] = tmp[row-1] ^ *(--k);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BIGINT_HEADER
|
||||
#define BIGINT_HEADER
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
BI_CTX *bi_initialize(void);
|
||||
void bi_terminate(BI_CTX *ctx);
|
||||
void bi_permanent(bigint *bi);
|
||||
void bi_depermanent(bigint *bi);
|
||||
void bi_clear_cache(BI_CTX *ctx);
|
||||
void bi_free(BI_CTX *ctx, bigint *bi);
|
||||
bigint *bi_copy(bigint *bi);
|
||||
bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
|
||||
void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
|
||||
bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
|
||||
bigint *int_to_bi(BI_CTX *ctx, comp i);
|
||||
|
||||
/* the functions that actually do something interesting */
|
||||
bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
|
||||
bigint *bi_subtract(BI_CTX *ctx, bigint *bia,
|
||||
bigint *bib, int *is_negative);
|
||||
bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
|
||||
bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
|
||||
bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
|
||||
bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
|
||||
int bi_compare(bigint *bia, bigint *bib);
|
||||
void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
|
||||
void bi_free_mod(BI_CTX *ctx, int mod_offset);
|
||||
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
void bi_print(const char *label, bigint *bi);
|
||||
bigint *bi_str_import(BI_CTX *ctx, const char *data);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def bi_mod
|
||||
* Find the residue of B. bi_set_mod() must be called before hand.
|
||||
*/
|
||||
#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
|
||||
|
||||
/**
|
||||
* bi_residue() is technically the same as bi_mod(), but it uses the
|
||||
* appropriate reduction technique (which is bi_mod() when doing classical
|
||||
* reduction).
|
||||
*/
|
||||
#if defined(CONFIG_BIGINT_MONTGOMERY)
|
||||
#define bi_residue(A, B) bi_mont(A, B)
|
||||
bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
|
||||
#elif defined(CONFIG_BIGINT_BARRETT)
|
||||
#define bi_residue(A, B) bi_barrett(A, B)
|
||||
bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
|
||||
#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
|
||||
#define bi_residue(A, B) bi_mod(A, B)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BIGINT_SQUARE
|
||||
bigint *bi_square(BI_CTX *ctx, bigint *bi);
|
||||
#else
|
||||
#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
bigint *bi_crt(BI_CTX *ctx, bigint *bi,
|
||||
bigint *dP, bigint *dQ,
|
||||
bigint *p, bigint *q,
|
||||
bigint *qInv);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BIGINT_IMPL_HEADER
|
||||
#define BIGINT_IMPL_HEADER
|
||||
|
||||
/* Maintain a number of precomputed variables when doing reduction */
|
||||
#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
#define BIGINT_P_OFFSET 1 /**< p modulo offset. */
|
||||
#define BIGINT_Q_OFFSET 2 /**< q module offset. */
|
||||
#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */
|
||||
#else
|
||||
#define BIGINT_NUM_MODS 1
|
||||
#endif
|
||||
|
||||
|
||||
/* Architecture specific functions for big ints */
|
||||
#if defined(CONFIG_INTEGER_8BIT)
|
||||
#define COMP_RADIX 256U /**< Max component + 1 */
|
||||
#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */
|
||||
#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */
|
||||
#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */
|
||||
#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */
|
||||
typedef uint8_t comp; /**< A single precision component. */
|
||||
typedef uint16_t long_comp; /**< A double precision component. */
|
||||
typedef int16_t slong_comp; /**< A signed double precision component. */
|
||||
#elif defined(CONFIG_INTEGER_16BIT)
|
||||
#define COMP_RADIX 65536U /**< Max component + 1 */
|
||||
#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */
|
||||
#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */
|
||||
#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */
|
||||
#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */
|
||||
typedef uint16_t comp; /**< A single precision component. */
|
||||
typedef uint32_t long_comp; /**< A double precision component. */
|
||||
typedef int32_t slong_comp; /**< A signed double precision component. */
|
||||
#else /* regular 32 bit */
|
||||
#ifdef WIN32
|
||||
#define COMP_RADIX 4294967296i64
|
||||
#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
|
||||
#else
|
||||
#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
|
||||
#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
|
||||
#endif
|
||||
#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
|
||||
#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
|
||||
#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
|
||||
#include <stdint.h>
|
||||
typedef uint32_t comp; /**< A single precision component. */
|
||||
typedef uint64_t long_comp; /**< A double precision component. */
|
||||
typedef int64_t slong_comp; /**< A signed double precision component. */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @struct _bigint
|
||||
* @brief A big integer basic object
|
||||
*/
|
||||
struct _bigint
|
||||
{
|
||||
struct _bigint* next; /**< The next bigint in the cache. */
|
||||
short size; /**< The number of components in this bigint. */
|
||||
short max_comps; /**< The heapsize allocated for this bigint */
|
||||
int refs; /**< An internal reference count. */
|
||||
comp* comps; /**< A ptr to the actual component data */
|
||||
};
|
||||
|
||||
typedef struct _bigint bigint; /**< An alias for _bigint */
|
||||
|
||||
/**
|
||||
* Maintains the state of the cache, and a number of variables used in
|
||||
* reduction.
|
||||
*/
|
||||
typedef struct /**< A big integer "session" context. */
|
||||
{
|
||||
bigint *active_list; /**< Bigints currently used. */
|
||||
bigint *free_list; /**< Bigints not used. */
|
||||
bigint *bi_radix; /**< The radix used. */
|
||||
bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */
|
||||
|
||||
#if defined(CONFIG_BIGINT_MONTGOMERY)
|
||||
bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */
|
||||
bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */
|
||||
comp N0_dash[BIGINT_NUM_MODS];
|
||||
#elif defined(CONFIG_BIGINT_BARRETT)
|
||||
bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */
|
||||
#endif
|
||||
bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
|
||||
bigint **g; /**< Used by sliding-window. */
|
||||
int window; /**< The size of the sliding window */
|
||||
int active_count; /**< Number of active bigints. */
|
||||
int free_count; /**< Number of free bigints. */
|
||||
|
||||
#ifdef CONFIG_BIGINT_MONTGOMERY
|
||||
uint8_t use_classical; /**< Use classical reduction. */
|
||||
#endif
|
||||
uint8_t mod_offset; /**< The mod offset we are using */
|
||||
} BI_CTX;
|
||||
|
||||
#ifndef WIN32
|
||||
#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */
|
||||
#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */
|
||||
#endif
|
||||
|
||||
#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
|
||||
|
||||
#endif
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file crypto.h
|
||||
*/
|
||||
|
||||
#ifndef HEADER_CRYPTO_H
|
||||
#define HEADER_CRYPTO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "bigint_impl.h"
|
||||
#include "bigint.h"
|
||||
|
||||
#ifndef STDCALL
|
||||
#define STDCALL
|
||||
#endif
|
||||
#ifndef EXP_FUNC
|
||||
#define EXP_FUNC
|
||||
#endif
|
||||
|
||||
|
||||
/* enable features based on a 'super-set' capbaility. */
|
||||
#if defined(CONFIG_SSL_FULL_MODE)
|
||||
#define CONFIG_SSL_ENABLE_CLIENT
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#elif defined(CONFIG_SSL_ENABLE_CLIENT)
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* AES declarations
|
||||
**************************************************************************/
|
||||
|
||||
#define AES_MAXROUNDS 14
|
||||
#define AES_BLOCKSIZE 16
|
||||
#define AES_IV_SIZE 16
|
||||
|
||||
typedef struct aes_key_st
|
||||
{
|
||||
uint16_t rounds;
|
||||
uint16_t key_size;
|
||||
uint32_t ks[(AES_MAXROUNDS+1)*8];
|
||||
uint8_t iv[AES_IV_SIZE];
|
||||
} AES_CTX;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AES_MODE_128,
|
||||
AES_MODE_256
|
||||
} AES_MODE;
|
||||
|
||||
void AES_set_key(AES_CTX *ctx, const uint8_t *key,
|
||||
const uint8_t *iv, AES_MODE mode);
|
||||
void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
|
||||
uint8_t *out, int length);
|
||||
void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
|
||||
void AES_convert_key(AES_CTX *ctx);
|
||||
|
||||
/**************************************************************************
|
||||
* RC4 declarations
|
||||
**************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t x, y, m[256];
|
||||
} RC4_CTX;
|
||||
|
||||
void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
|
||||
void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
|
||||
|
||||
/**************************************************************************
|
||||
* SHA1 declarations
|
||||
**************************************************************************/
|
||||
|
||||
#define SHA1_SIZE 20
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-1
|
||||
* hashing operation
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint16_t Message_Block_Index; /* Index into message block array */
|
||||
uint8_t Message_Block[64]; /* 512-bit message blocks */
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1_Init(SHA1_CTX *);
|
||||
void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
|
||||
void SHA1_Final(uint8_t *digest, SHA1_CTX *);
|
||||
|
||||
/**************************************************************************
|
||||
* MD2 declarations
|
||||
**************************************************************************/
|
||||
|
||||
#define MD2_SIZE 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char cksum[16]; /* checksum of the data block */
|
||||
unsigned char state[48]; /* intermediate digest state */
|
||||
unsigned char buffer[16]; /* data block being processed */
|
||||
int left; /* amount of data in buffer */
|
||||
} MD2_CTX;
|
||||
|
||||
EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
|
||||
EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
|
||||
EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
|
||||
|
||||
/**************************************************************************
|
||||
* MD5 declarations
|
||||
**************************************************************************/
|
||||
|
||||
#define MD5_SIZE 16
|
||||
#define MAX_KEYBLOCK_SIZE 136
|
||||
typedef struct
|
||||
{
|
||||
uint32_t state[4]; /* state (ABCD) */
|
||||
uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
uint8_t buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
|
||||
EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
|
||||
EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
|
||||
|
||||
/**************************************************************************
|
||||
* HMAC declarations
|
||||
**************************************************************************/
|
||||
void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest);
|
||||
void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest);
|
||||
|
||||
/**************************************************************************
|
||||
* RSA declarations
|
||||
**************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bigint *m; /* modulus */
|
||||
bigint *e; /* public exponent */
|
||||
bigint *d; /* private exponent */
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
bigint *p; /* p as in m = pq */
|
||||
bigint *q; /* q as in m = pq */
|
||||
bigint *dP; /* d mod (p-1) */
|
||||
bigint *dQ; /* d mod (q-1) */
|
||||
bigint *qInv; /* q^-1 mod p */
|
||||
#endif
|
||||
int num_octets;
|
||||
BI_CTX *bi_ctx;
|
||||
} RSA_CTX;
|
||||
|
||||
void RSA_priv_key_new(RSA_CTX **rsa_ctx,
|
||||
const uint8_t *modulus, int mod_len,
|
||||
const uint8_t *pub_exp, int pub_len,
|
||||
const uint8_t *priv_exp, int priv_len
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
, const uint8_t *p, int p_len,
|
||||
const uint8_t *q, int q_len,
|
||||
const uint8_t *dP, int dP_len,
|
||||
const uint8_t *dQ, int dQ_len,
|
||||
const uint8_t *qInv, int qInv_len
|
||||
#endif
|
||||
);
|
||||
void RSA_pub_key_new(RSA_CTX **rsa_ctx,
|
||||
const uint8_t *modulus, int mod_len,
|
||||
const uint8_t *pub_exp, int pub_len);
|
||||
void RSA_free(RSA_CTX *ctx);
|
||||
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
|
||||
int is_decryption);
|
||||
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
|
||||
#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
|
||||
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
|
||||
bigint *modulus, bigint *pub_exp);
|
||||
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
|
||||
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
|
||||
uint8_t *out_data, int is_signing);
|
||||
void RSA_print(const RSA_CTX *ctx);
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* RNG declarations
|
||||
**************************************************************************/
|
||||
EXP_FUNC void STDCALL RNG_initialize(void);
|
||||
EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size);
|
||||
EXP_FUNC void STDCALL RNG_terminate(void);
|
||||
EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
|
||||
void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,375 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Some misc. routines to help things out
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "os_port.h"
|
||||
#include <lwip/def.h>
|
||||
#include "sockets.h"
|
||||
#include "crypto_misc.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
#ifdef CONFIG_WIN32_USE_CRYPTO_LIB
|
||||
#include "wincrypt.h"
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
static int rng_fd = -1;
|
||||
#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
|
||||
static HCRYPTPROV gCryptProv;
|
||||
#endif
|
||||
|
||||
#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
|
||||
/* change to processor registers as appropriate */
|
||||
#define ENTROPY_POOL_SIZE 32
|
||||
#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
|
||||
#define ENTROPY_COUNTER2 rand()
|
||||
static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
|
||||
#endif
|
||||
|
||||
const char * const unsupported_str = "Error: Feature not supported\n";
|
||||
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
/**
|
||||
* Retrieve a file and put it into memory
|
||||
* @return The size of the file, or -1 on failure.
|
||||
*/
|
||||
int get_file(const char *filename, uint8_t **buf)
|
||||
{
|
||||
int total_bytes = 0;
|
||||
int bytes_read = 0;
|
||||
int filesize;
|
||||
FILE *stream = fopen(filename, "rb");
|
||||
|
||||
if (stream == NULL)
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("file '%s' does not exist\n", filename); TTY_FLUSH();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Win CE doesn't support stat() */
|
||||
fseek(stream, 0, SEEK_END);
|
||||
filesize = ftell(stream);
|
||||
*buf = (uint8_t *)malloc(filesize);
|
||||
fseek(stream, 0, SEEK_SET);
|
||||
|
||||
do
|
||||
{
|
||||
bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
|
||||
total_bytes += bytes_read;
|
||||
} while (total_bytes < filesize && bytes_read > 0);
|
||||
|
||||
fclose(stream);
|
||||
return filesize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialise the Random Number Generator engine.
|
||||
* - On Win32 use the platform SDK's crypto engine.
|
||||
* - On Linux use /dev/urandom
|
||||
* - If none of these work then use a custom RNG.
|
||||
*/
|
||||
EXP_FUNC void STDCALL RNG_initialize()
|
||||
{
|
||||
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
|
||||
rng_fd = ax_open("/dev/urandom", O_RDONLY);
|
||||
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
|
||||
if (!CryptAcquireContext(&gCryptProv,
|
||||
NULL, NULL, PROV_RSA_FULL, 0))
|
||||
{
|
||||
if (GetLastError() == NTE_BAD_KEYSET &&
|
||||
!CryptAcquireContext(&gCryptProv,
|
||||
NULL,
|
||||
NULL,
|
||||
PROV_RSA_FULL,
|
||||
CRYPT_NEWKEYSET))
|
||||
{
|
||||
printf("CryptoLib: %x\n", unsupported_str, GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* start of with a stack to copy across */
|
||||
int i;
|
||||
memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
|
||||
srand((unsigned int)&i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* If no /dev/urandom, then initialise the RNG with something interesting.
|
||||
*/
|
||||
EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size)
|
||||
{
|
||||
#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)
|
||||
entropy_pool[i] ^= seed_buf[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate the RNG engine.
|
||||
*/
|
||||
EXP_FUNC void STDCALL RNG_terminate(void)
|
||||
{
|
||||
#ifndef WIN32
|
||||
//close(rng_fd);
|
||||
#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
|
||||
CryptReleaseContext(gCryptProv, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a series of bytes with a random number. Individual bytes can be 0
|
||||
*/
|
||||
EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
|
||||
{
|
||||
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
|
||||
/* use the Linux default */
|
||||
read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */
|
||||
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
|
||||
/* use Microsoft Crypto Libraries */
|
||||
CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
|
||||
#else /* nothing else to use, so use a custom RNG */
|
||||
/* The method we use when we've got nothing better. Use RC4, time
|
||||
and a couple of random seeds to generate a random sequence */
|
||||
RC4_CTX rng_ctx;
|
||||
struct timeval tv;
|
||||
MD5_CTX rng_digest_ctx;
|
||||
uint8_t digest[MD5_SIZE];
|
||||
uint64_t *ep;
|
||||
int i;
|
||||
|
||||
/* A proper implementation would use counters etc for entropy */
|
||||
// XXX XXX XX X need to seed this properly
|
||||
gettimeofday(&tv, NULL);
|
||||
ep = (uint64_t *)entropy_pool;
|
||||
|
||||
ep[0] ^= ENTROPY_COUNTER1;
|
||||
ep[1] ^= ENTROPY_COUNTER2;
|
||||
|
||||
|
||||
/* use a digested version of the entropy pool as a key */
|
||||
MD5_Init(&rng_digest_ctx);
|
||||
MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);
|
||||
MD5_Final(digest, &rng_digest_ctx);
|
||||
|
||||
/* come up with the random sequence */
|
||||
RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */
|
||||
memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?
|
||||
num_rand_bytes : ENTROPY_POOL_SIZE);
|
||||
RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
|
||||
|
||||
/* move things along */
|
||||
for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)
|
||||
entropy_pool[i] = entropy_pool[i-MD5_SIZE];
|
||||
|
||||
/* insert the digest at the start of the entropy pool */
|
||||
memcpy(entropy_pool, digest, MD5_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a series of bytes with a random number. Individual bytes are not zero.
|
||||
*/
|
||||
void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
|
||||
{
|
||||
int i;
|
||||
get_random(num_rand_bytes, rand_data);
|
||||
|
||||
for (i = 0; i < num_rand_bytes; i++)
|
||||
{
|
||||
while (rand_data[i] == 0) /* can't be 0 */
|
||||
rand_data[i] = (uint8_t)(rand());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some useful diagnostic routines
|
||||
*/
|
||||
#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
|
||||
int hex_finish;
|
||||
int hex_index;
|
||||
|
||||
static void print_hex_init(int finish)
|
||||
{
|
||||
hex_finish = finish;
|
||||
hex_index = 0;
|
||||
}
|
||||
|
||||
static void print_hex(uint8_t hex)
|
||||
{
|
||||
static int column;
|
||||
|
||||
if (hex_index == 0)
|
||||
{
|
||||
column = 0;
|
||||
}
|
||||
|
||||
printf("%02x ", hex);
|
||||
if (++column == 8)
|
||||
{
|
||||
printf(": ");
|
||||
}
|
||||
else if (column >= 16)
|
||||
{
|
||||
printf("\r\n");
|
||||
column = 0;
|
||||
}
|
||||
|
||||
if (++hex_index >= hex_finish && column > 0)
|
||||
{
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spit out a blob of data for diagnostics. The data is is a nice column format
|
||||
* for easy reading.
|
||||
*
|
||||
* @param format [in] The string (with possible embedded format characters)
|
||||
* @param size [in] The number of numbers to print
|
||||
* @param data [in] The start of data to use
|
||||
* @param ... [in] Any additional arguments
|
||||
*/
|
||||
EXP_FUNC void STDCALL print_blob(const char *format,
|
||||
const uint8_t *data, int size, ...)
|
||||
{
|
||||
int i;
|
||||
char tmp[80];
|
||||
va_list(ap);
|
||||
|
||||
va_start(ap, size);
|
||||
sprintf(tmp, "%s\n", format);
|
||||
vprintf(tmp, ap);
|
||||
print_hex_init(size);
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
print_hex(data[i]);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
TTY_FLUSH();
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
/* VC6.0 doesn't handle variadic macros */
|
||||
EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
|
||||
int size, ...) {}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
|
||||
/* base64 to binary lookup table */
|
||||
static const uint8_t map[128] =
|
||||
{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
|
||||
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
|
||||
EXP_FUNC int STDCALL base64_decode(const char *in, int len,
|
||||
uint8_t *out, int *outlen)
|
||||
{
|
||||
int g, t, x, y, z;
|
||||
uint8_t c;
|
||||
int ret = -1;
|
||||
|
||||
g = 3;
|
||||
for (x = y = z = t = 0; x < len; x++)
|
||||
{
|
||||
if ((c = map[in[x]&0x7F]) == 0xff)
|
||||
continue;
|
||||
|
||||
if (c == 254) /* this is the end... */
|
||||
{
|
||||
c = 0;
|
||||
|
||||
if (--g < 0)
|
||||
goto error;
|
||||
}
|
||||
else if (g != 3) /* only allow = at end */
|
||||
goto error;
|
||||
|
||||
t = (t<<6) | c;
|
||||
|
||||
if (++y == 4)
|
||||
{
|
||||
out[z++] = (uint8_t)((t>>16)&255);
|
||||
|
||||
if (g > 1)
|
||||
out[z++] = (uint8_t)((t>>8)&255);
|
||||
|
||||
if (g > 2)
|
||||
out[z++] = (uint8_t)(t&255);
|
||||
|
||||
y = t = 0;
|
||||
}
|
||||
|
||||
/* check that we don't go past the output buffer */
|
||||
if (z > *outlen)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (y != 0)
|
||||
goto error;
|
||||
|
||||
*outlen = z;
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
if (ret < 0)
|
||||
printf("Error: Invalid base64\n"); TTY_FLUSH();
|
||||
#endif
|
||||
TTY_FLUSH();
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HMAC implementation - This code was originally taken from RFC2104
|
||||
* See http://www.ietf.org/rfc/rfc2104.txt and
|
||||
* http://www.faqs.org/rfcs/rfc2202.html
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/**
|
||||
* Perform HMAC-MD5
|
||||
* NOTE: does not handle keys larger than the block size.
|
||||
*/
|
||||
void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest)
|
||||
{
|
||||
MD5_CTX context;
|
||||
uint8_t k_ipad[64];
|
||||
uint8_t k_opad[64];
|
||||
int i;
|
||||
|
||||
memset(k_ipad, 0, sizeof k_ipad);
|
||||
memset(k_opad, 0, sizeof k_opad);
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
MD5_Init(&context);
|
||||
MD5_Update(&context, k_ipad, 64);
|
||||
MD5_Update(&context, msg, length);
|
||||
MD5_Final(digest, &context);
|
||||
MD5_Init(&context);
|
||||
MD5_Update(&context, k_opad, 64);
|
||||
MD5_Update(&context, digest, MD5_SIZE);
|
||||
MD5_Final(digest, &context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform HMAC-SHA1
|
||||
* NOTE: does not handle keys larger than the block size.
|
||||
*/
|
||||
void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest)
|
||||
{
|
||||
SHA1_CTX context;
|
||||
uint8_t k_ipad[64];
|
||||
uint8_t k_opad[64];
|
||||
int i;
|
||||
|
||||
memset(k_ipad, 0, sizeof k_ipad);
|
||||
memset(k_opad, 0, sizeof k_opad);
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, k_ipad, 64);
|
||||
SHA1_Update(&context, msg, length);
|
||||
SHA1_Final(digest, &context);
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, k_opad, 64);
|
||||
SHA1_Update(&context, digest, SHA1_SIZE);
|
||||
SHA1_Final(digest, &context);
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RFC 1115/1319 compliant MD2 implementation
|
||||
* The MD2 algorithm was designed by Ron Rivest in 1989.
|
||||
*
|
||||
* http://www.ietf.org/rfc/rfc1115.txt
|
||||
* http://www.ietf.org/rfc/rfc1319.txt
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* This code is only here to enable the verification of Verisign root
|
||||
* certificates. So only enable it for verification mode.
|
||||
*/
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
|
||||
static const uint8_t PI_SUBST[256] =
|
||||
{
|
||||
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
|
||||
0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,
|
||||
0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,
|
||||
0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
|
||||
0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,
|
||||
0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
|
||||
0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,
|
||||
0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
|
||||
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,
|
||||
0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,
|
||||
0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,
|
||||
0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
|
||||
0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,
|
||||
0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,
|
||||
0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,
|
||||
0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
|
||||
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,
|
||||
0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
|
||||
0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,
|
||||
0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
|
||||
0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,
|
||||
0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,
|
||||
0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,
|
||||
0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
|
||||
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,
|
||||
0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
|
||||
};
|
||||
|
||||
/*
|
||||
* MD2 context setup
|
||||
*/
|
||||
EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
}
|
||||
|
||||
static void md2_process(MD2_CTX *ctx)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t t = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
ctx->state[i + 16] = ctx->buffer[i];
|
||||
ctx->state[i + 32] = ctx->buffer[i] ^ ctx->state[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
for (j = 0; j < 48; j++)
|
||||
t = (ctx->state[j] ^= PI_SUBST[t]);
|
||||
|
||||
t = (t + i) & 0xFF;
|
||||
}
|
||||
|
||||
t = ctx->cksum[15];
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
t = (ctx->cksum[i] ^= PI_SUBST[ctx->buffer[i] ^ t]);
|
||||
}
|
||||
|
||||
/*
|
||||
* MD2 process buffer
|
||||
*/
|
||||
EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen)
|
||||
{
|
||||
int fill;
|
||||
|
||||
while (ilen > 0)
|
||||
{
|
||||
if (ctx->left + ilen > 16)
|
||||
fill = 16 - ctx->left;
|
||||
else
|
||||
fill = ilen;
|
||||
|
||||
memcpy(ctx->buffer + ctx->left, input, fill);
|
||||
|
||||
ctx->left += fill;
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
|
||||
if (ctx->left == 16)
|
||||
{
|
||||
ctx->left = 0;
|
||||
md2_process(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MD2 final digest
|
||||
*/
|
||||
EXP_FUNC void STDCALL MD2_Final(uint8_t *output, MD2_CTX *ctx)
|
||||
{
|
||||
int i;
|
||||
uint8_t x;
|
||||
|
||||
x = (uint8_t)(16 - ctx->left);
|
||||
|
||||
for (i = ctx->left; i < 16; i++)
|
||||
ctx->buffer[i] = x;
|
||||
|
||||
md2_process(ctx);
|
||||
|
||||
memcpy(ctx->buffer, ctx->cksum, 16);
|
||||
md2_process(ctx);
|
||||
|
||||
memcpy(output, ctx->state, 16);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,294 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file implements the MD5 algorithm as defined in RFC1321
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/* Constants for MD5Transform routine.
|
||||
*/
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
/* ----- static functions ----- */
|
||||
static void MD5Transform(uint32_t state[4], const uint8_t block[64]);
|
||||
static void Encode(uint8_t *output, uint32_t *input, uint32_t len);
|
||||
static void Decode(uint32_t *output, const uint8_t *input, uint32_t len);
|
||||
|
||||
static const uint8_t PADDING[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits. */
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation. */
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 initialization - begins an MD5 operation, writing a new ctx.
|
||||
*/
|
||||
EXP_FUNC void STDCALL MD5_Init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xefcdab89;
|
||||
ctx->state[2] = 0x98badcfe;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an array of octets as the next portion of the message.
|
||||
*/
|
||||
EXP_FUNC void STDCALL MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len)
|
||||
{
|
||||
uint32_t x;
|
||||
int i, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
x = (uint32_t)((ctx->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3))
|
||||
ctx->count[1]++;
|
||||
ctx->count[1] += ((uint32_t)len >> 29);
|
||||
|
||||
partLen = 64 - x;
|
||||
|
||||
/* Transform as many times as possible. */
|
||||
if (len >= partLen)
|
||||
{
|
||||
memcpy(&ctx->buffer[x], msg, partLen);
|
||||
MD5Transform(ctx->state, ctx->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < len; i += 64)
|
||||
MD5Transform(ctx->state, &msg[i]);
|
||||
|
||||
x = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
memcpy(&ctx->buffer[x], &msg[i], len-i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 128-bit message digest into the user's array
|
||||
*/
|
||||
EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *ctx)
|
||||
{
|
||||
uint8_t bits[8];
|
||||
uint32_t x, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode(bits, ctx->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.
|
||||
*/
|
||||
x = (uint32_t)((ctx->count[0] >> 3) & 0x3f);
|
||||
padLen = (x < 56) ? (56 - x) : (120 - x);
|
||||
MD5_Update(ctx, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5_Update(ctx, bits, 8);
|
||||
|
||||
/* Store state in digest */
|
||||
Encode(digest, ctx->state, MD5_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void MD5Transform(uint32_t state[4], const uint8_t block[64])
|
||||
{
|
||||
uint32_t a = state[0], b = state[1], c = state[2],
|
||||
d = state[3], x[MD5_SIZE];
|
||||
|
||||
Decode(x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes input (uint32_t) into output (uint8_t). Assumes len is
|
||||
* a multiple of 4.
|
||||
*/
|
||||
static void Encode(uint8_t *output, uint32_t *input, uint32_t len)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
{
|
||||
output[j] = (uint8_t)(input[i] & 0xff);
|
||||
output[j+1] = (uint8_t)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (uint8_t)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (uint8_t)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes input (uint8_t) into output (uint32_t). Assumes len is
|
||||
* a multiple of 4.
|
||||
*/
|
||||
static void Decode(uint32_t *output, const uint8_t *input, uint32_t len)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
|
||||
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file os_int.h
|
||||
*
|
||||
* Ensure a consistent bit size
|
||||
*/
|
||||
|
||||
#ifndef HEADER_OS_INT_H
|
||||
#define HEADER_OS_INT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef UINT8 uint8_t;
|
||||
typedef INT8 int8_t;
|
||||
typedef UINT16 uint16_t;
|
||||
typedef INT16 int16_t;
|
||||
typedef UINT32 uint32_t;
|
||||
typedef INT32 int32_t;
|
||||
typedef UINT64 uint64_t;
|
||||
typedef INT64 int64_t;
|
||||
#else /* Not Win32 */
|
||||
|
||||
#ifdef CONFIG_PLATFORM_SOLARIS
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif /* Not Solaris */
|
||||
|
||||
#endif /* Not Win32 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of the RC4/ARC4 algorithm.
|
||||
* Originally written by Christophe Devine.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/**
|
||||
* Get ready for an encrypt/decrypt operation
|
||||
*/
|
||||
void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length)
|
||||
{
|
||||
int i, j = 0, k = 0, a;
|
||||
uint8_t *m;
|
||||
|
||||
ctx->x = 0;
|
||||
ctx->y = 0;
|
||||
m = ctx->m;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
m[i] = i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
a = m[i];
|
||||
j = (uint8_t)(j + a + key[k]);
|
||||
m[i] = m[j];
|
||||
m[j] = a;
|
||||
|
||||
if (++k >= length)
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the encrypt/decrypt operation (can use it for either since
|
||||
* this is a stream cipher).
|
||||
* NOTE: *msg and *out must be the same pointer (performance tweak)
|
||||
*/
|
||||
void RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
|
||||
{
|
||||
int i;
|
||||
uint8_t *m, x, y, a, b;
|
||||
|
||||
x = ctx->x;
|
||||
y = ctx->y;
|
||||
m = ctx->m;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
a = m[++x];
|
||||
y += a;
|
||||
m[x] = b = m[y];
|
||||
m[y] = a;
|
||||
out[i] ^= m[(uint8_t)(a + b)];
|
||||
}
|
||||
|
||||
ctx->x = x;
|
||||
ctx->y = y;
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements the RSA public encryption algorithm. Uses the bigint library to
|
||||
* perform its calculations.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
|
||||
void RSA_priv_key_new(RSA_CTX **ctx,
|
||||
const uint8_t *modulus, int mod_len,
|
||||
const uint8_t *pub_exp, int pub_len,
|
||||
const uint8_t *priv_exp, int priv_len
|
||||
#if CONFIG_BIGINT_CRT
|
||||
, const uint8_t *p, int p_len,
|
||||
const uint8_t *q, int q_len,
|
||||
const uint8_t *dP, int dP_len,
|
||||
const uint8_t *dQ, int dQ_len,
|
||||
const uint8_t *qInv, int qInv_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
RSA_CTX *rsa_ctx;
|
||||
BI_CTX *bi_ctx;
|
||||
RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
|
||||
rsa_ctx = *ctx;
|
||||
bi_ctx = rsa_ctx->bi_ctx;
|
||||
rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
|
||||
bi_permanent(rsa_ctx->d);
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
rsa_ctx->p = bi_import(bi_ctx, p, p_len);
|
||||
rsa_ctx->q = bi_import(bi_ctx, q, q_len);
|
||||
rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
|
||||
rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
|
||||
rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
|
||||
bi_permanent(rsa_ctx->dP);
|
||||
bi_permanent(rsa_ctx->dQ);
|
||||
bi_permanent(rsa_ctx->qInv);
|
||||
bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
|
||||
bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RSA_pub_key_new(RSA_CTX **ctx,
|
||||
const uint8_t *modulus, int mod_len,
|
||||
const uint8_t *pub_exp, int pub_len)
|
||||
{
|
||||
RSA_CTX *rsa_ctx;
|
||||
BI_CTX *bi_ctx;
|
||||
|
||||
if (*ctx) /* if we load multiple certs, dump the old one */
|
||||
RSA_free(*ctx);
|
||||
|
||||
bi_ctx = bi_initialize();
|
||||
*ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
|
||||
rsa_ctx = *ctx;
|
||||
rsa_ctx->bi_ctx = bi_ctx;
|
||||
rsa_ctx->num_octets = mod_len;
|
||||
rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
|
||||
bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
|
||||
rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
|
||||
bi_permanent(rsa_ctx->e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free up any RSA context resources.
|
||||
*/
|
||||
void RSA_free(RSA_CTX *rsa_ctx)
|
||||
{
|
||||
BI_CTX *bi_ctx;
|
||||
if (rsa_ctx == NULL) /* deal with ptrs that are null */
|
||||
return;
|
||||
|
||||
bi_ctx = rsa_ctx->bi_ctx;
|
||||
|
||||
bi_depermanent(rsa_ctx->e);
|
||||
bi_free(bi_ctx, rsa_ctx->e);
|
||||
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
|
||||
|
||||
if (rsa_ctx->d)
|
||||
{
|
||||
bi_depermanent(rsa_ctx->d);
|
||||
bi_free(bi_ctx, rsa_ctx->d);
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
bi_depermanent(rsa_ctx->dP);
|
||||
bi_depermanent(rsa_ctx->dQ);
|
||||
bi_depermanent(rsa_ctx->qInv);
|
||||
bi_free(bi_ctx, rsa_ctx->dP);
|
||||
bi_free(bi_ctx, rsa_ctx->dQ);
|
||||
bi_free(bi_ctx, rsa_ctx->qInv);
|
||||
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
|
||||
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
|
||||
#endif
|
||||
}
|
||||
|
||||
bi_terminate(bi_ctx);
|
||||
free(rsa_ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Use PKCS1.5 for decryption/verification.
|
||||
* @param ctx [in] The context
|
||||
* @param in_data [in] The data to encrypt (must be < modulus size-11)
|
||||
* @param out_data [out] The encrypted data.
|
||||
* @param is_decryption [in] Decryption or verify operation.
|
||||
* @return The number of bytes that were originally encrypted. -1 on error.
|
||||
* @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
|
||||
*/
|
||||
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
|
||||
uint8_t *out_data, int is_decryption)
|
||||
{
|
||||
const int byte_size = ctx->num_octets;
|
||||
int i, size;
|
||||
bigint *decrypted_bi, *dat_bi;
|
||||
uint8_t *block = (uint8_t *)alloca(byte_size);
|
||||
|
||||
memset(out_data, 0, byte_size); /* initialise */
|
||||
|
||||
/* decrypt */
|
||||
dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
decrypted_bi = is_decryption ? /* decrypt or verify? */
|
||||
RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
|
||||
#else /* always a decryption */
|
||||
decrypted_bi = RSA_private(ctx, dat_bi);
|
||||
#endif
|
||||
|
||||
/* convert to a normal block */
|
||||
bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
|
||||
|
||||
i = 10; /* start at the first possible non-padded byte */
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
|
||||
{
|
||||
while (block[i++] == 0xff && i < byte_size);
|
||||
|
||||
if (block[i-2] != 0xff)
|
||||
i = byte_size; /*ensure size is 0 */
|
||||
}
|
||||
else /* PKCS1.5 encryption padding is random */
|
||||
#endif
|
||||
{
|
||||
while (block[i++] && i < byte_size);
|
||||
}
|
||||
size = byte_size - i;
|
||||
|
||||
/* get only the bit we want */
|
||||
if (size > 0)
|
||||
memcpy(out_data, &block[i], size);
|
||||
|
||||
return size ? size : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs m = c^d mod n
|
||||
*/
|
||||
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
|
||||
{
|
||||
printf("RSA private\n");
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv);
|
||||
#else
|
||||
BI_CTX *ctx = c->bi_ctx;
|
||||
ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
return bi_mod_power(ctx, bi_msg, c->d);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
/**
|
||||
* Used for diagnostics.
|
||||
*/
|
||||
void RSA_print(const RSA_CTX *rsa_ctx)
|
||||
{
|
||||
if (rsa_ctx == NULL)
|
||||
return;
|
||||
|
||||
printf("----------------- RSA DEBUG ----------------\n");
|
||||
printf("Size:\t%d\n", rsa_ctx->num_octets);
|
||||
bi_print("Modulus", rsa_ctx->m);
|
||||
bi_print("Public Key", rsa_ctx->e);
|
||||
bi_print("Private Key", rsa_ctx->d);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
|
||||
/**
|
||||
* Performs c = m^e mod n
|
||||
*/
|
||||
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
|
||||
{
|
||||
c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
return bi_mod_power(c->bi_ctx, bi_msg, c->e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use PKCS1.5 for encryption/signing.
|
||||
* see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
|
||||
*/
|
||||
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
|
||||
uint8_t *out_data, int is_signing)
|
||||
{
|
||||
int byte_size = ctx->num_octets;
|
||||
int num_pads_needed = byte_size-in_len-3;
|
||||
bigint *dat_bi, *encrypt_bi;
|
||||
/* note: in_len+11 must be > byte_size */
|
||||
out_data[0] = 0; /* ensure encryption block is < modulus */
|
||||
if (is_signing)
|
||||
{
|
||||
out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */
|
||||
memset(&out_data[2], 0xff, num_pads_needed);
|
||||
}
|
||||
else /* randomize the encryption padding with non-zero bytes */
|
||||
{
|
||||
out_data[1] = 2;
|
||||
get_random_NZ(num_pads_needed, &out_data[2]);
|
||||
}
|
||||
|
||||
out_data[2+num_pads_needed] = 0;
|
||||
memcpy(&out_data[3+num_pads_needed], in_data, in_len);
|
||||
|
||||
/* now encrypt it */
|
||||
dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
|
||||
|
||||
encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) :
|
||||
RSA_public(ctx, dat_bi);
|
||||
|
||||
bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
|
||||
/* save a few bytes of memory */
|
||||
bi_clear_cache(ctx->bi_ctx);
|
||||
|
||||
return byte_size;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
|
@ -1,249 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
|
||||
* This code was originally taken from RFC3174
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/*
|
||||
* Define the SHA1 circular left shift macro
|
||||
*/
|
||||
#define SHA1CircularShift(bits,word) \
|
||||
(((word) << (bits)) | ((word) >> (32-(bits))))
|
||||
|
||||
/* ----- static functions ----- */
|
||||
static void SHA1PadMessage(SHA1_CTX *ctx);
|
||||
static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Initialize the SHA1 context
|
||||
*/
|
||||
void SHA1_Init(SHA1_CTX *ctx)
|
||||
{
|
||||
ctx->Length_Low = 0;
|
||||
ctx->Length_High = 0;
|
||||
ctx->Message_Block_Index = 0;
|
||||
ctx->Intermediate_Hash[0] = 0x67452301;
|
||||
ctx->Intermediate_Hash[1] = 0xEFCDAB89;
|
||||
ctx->Intermediate_Hash[2] = 0x98BADCFE;
|
||||
ctx->Intermediate_Hash[3] = 0x10325476;
|
||||
ctx->Intermediate_Hash[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an array of octets as the next portion of the message.
|
||||
*/
|
||||
void SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
|
||||
ctx->Length_Low += 8;
|
||||
|
||||
if (ctx->Length_Low == 0)
|
||||
ctx->Length_High++;
|
||||
|
||||
if (ctx->Message_Block_Index == 64)
|
||||
SHA1ProcessMessageBlock(ctx);
|
||||
|
||||
msg++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 160-bit message digest into the user's array
|
||||
*/
|
||||
void SHA1_Final(uint8_t *digest, SHA1_CTX *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
SHA1PadMessage(ctx);
|
||||
memset(ctx->Message_Block, 0, 64);
|
||||
ctx->Length_Low = 0; /* and clear length */
|
||||
ctx->Length_High = 0;
|
||||
|
||||
for (i = 0; i < SHA1_SIZE; i++)
|
||||
{
|
||||
digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next 512 bits of the message stored in the array.
|
||||
*/
|
||||
static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
|
||||
{
|
||||
const uint32_t K[] = { /* Constants defined in SHA-1 */
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; /* Loop counter */
|
||||
uint32_t temp; /* Temporary word value */
|
||||
uint32_t W[80]; /* Word sequence */
|
||||
uint32_t A, B, C, D, E; /* Word buffers */
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for (t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = ctx->Message_Block[t * 4] << 24;
|
||||
W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
|
||||
W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
|
||||
W[t] |= ctx->Message_Block[t * 4 + 3];
|
||||
}
|
||||
|
||||
for (t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = ctx->Intermediate_Hash[0];
|
||||
B = ctx->Intermediate_Hash[1];
|
||||
C = ctx->Intermediate_Hash[2];
|
||||
D = ctx->Intermediate_Hash[3];
|
||||
E = ctx->Intermediate_Hash[4];
|
||||
|
||||
for (t = 0; t < 20; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 20; t < 40; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 40; t < 60; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 60; t < 80; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
ctx->Intermediate_Hash[0] += A;
|
||||
ctx->Intermediate_Hash[1] += B;
|
||||
ctx->Intermediate_Hash[2] += C;
|
||||
ctx->Intermediate_Hash[3] += D;
|
||||
ctx->Intermediate_Hash[4] += E;
|
||||
ctx->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64
|
||||
* bits represent the length of the original message. All bits in
|
||||
* between should be 0. This function will pad the message
|
||||
* according to those rules by filling the Message_Block array
|
||||
* accordingly. It will also call the ProcessMessageBlock function
|
||||
* provided appropriately. When it returns, it can be assumed that
|
||||
* the message digest has been computed.
|
||||
*
|
||||
* @param ctx [in, out] The SHA1 context
|
||||
*/
|
||||
static void SHA1PadMessage(SHA1_CTX *ctx)
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second
|
||||
* block.
|
||||
*/
|
||||
if (ctx->Message_Block_Index > 55)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
|
||||
while(ctx->Message_Block_Index < 64)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
SHA1ProcessMessageBlock(ctx);
|
||||
|
||||
while (ctx->Message_Block_Index < 56)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
|
||||
while(ctx->Message_Block_Index < 56)
|
||||
{
|
||||
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
ctx->Message_Block[56] = ctx->Length_High >> 24;
|
||||
ctx->Message_Block[57] = ctx->Length_High >> 16;
|
||||
ctx->Message_Block[58] = ctx->Length_High >> 8;
|
||||
ctx->Message_Block[59] = ctx->Length_High;
|
||||
ctx->Message_Block[60] = ctx->Length_Low >> 24;
|
||||
ctx->Message_Block[61] = ctx->Length_Low >> 16;
|
||||
ctx->Message_Block[62] = ctx->Length_Low >> 8;
|
||||
ctx->Message_Block[63] = ctx->Length_Low;
|
||||
SHA1ProcessMessageBlock(ctx);
|
||||
}
|
|
@ -1,565 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Some primitive asn methods for extraction ASN.1 data.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
#include "crypto_misc.h"
|
||||
#include "config.h"
|
||||
|
||||
#define SIG_OID_PREFIX_SIZE 8
|
||||
#define SIG_IIS6_OID_SIZE 5
|
||||
#define SIG_SUBJECT_ALT_NAME_SIZE 3
|
||||
|
||||
/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
|
||||
static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
|
||||
{
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
|
||||
};
|
||||
|
||||
static const uint8_t sig_sha1WithRSAEncrypt[SIG_IIS6_OID_SIZE] =
|
||||
{
|
||||
0x2b, 0x0e, 0x03, 0x02, 0x1d
|
||||
};
|
||||
|
||||
static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] =
|
||||
{
|
||||
0x55, 0x1d, 0x11
|
||||
};
|
||||
|
||||
/* CN, O, OU */
|
||||
static const uint8_t g_dn_types[] = { 3, 10, 11 };
|
||||
|
||||
int get_asn1_length(const uint8_t *buf, int *offset)
|
||||
{
|
||||
int len, i;
|
||||
|
||||
if (!(buf[*offset] & 0x80)) /* short form */
|
||||
{
|
||||
len = buf[(*offset)++];
|
||||
}
|
||||
else /* long form */
|
||||
{
|
||||
int length_bytes = buf[(*offset)++]&0x7f;
|
||||
len = 0;
|
||||
for (i = 0; i < length_bytes; i++)
|
||||
{
|
||||
len <<= 8;
|
||||
len += buf[(*offset)++];
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip the ASN1.1 object type and its length. Get ready to read the object's
|
||||
* data.
|
||||
*/
|
||||
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
|
||||
{
|
||||
if (buf[*offset] != obj_type)
|
||||
return X509_NOT_OK;
|
||||
(*offset)++;
|
||||
int tmp = get_asn1_length(buf, offset);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip over an ASN.1 object type completely. Get ready to read the next
|
||||
* object.
|
||||
*/
|
||||
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
|
||||
{
|
||||
int len;
|
||||
if (buf[*offset] != obj_type)
|
||||
return X509_NOT_OK;
|
||||
(*offset)++;
|
||||
len = get_asn1_length(buf, offset);
|
||||
*offset += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an integer value for ASN.1 data
|
||||
* Note: This function allocates memory which must be freed by the user.
|
||||
*/
|
||||
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
|
||||
{
|
||||
int len;
|
||||
|
||||
if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
|
||||
goto end_int_array;
|
||||
|
||||
if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */
|
||||
{
|
||||
len--;
|
||||
(*offset)++;
|
||||
}
|
||||
|
||||
*object = (uint8_t *)malloc(len);
|
||||
memcpy(*object, &buf[*offset], len);
|
||||
*offset += len;
|
||||
|
||||
end_int_array:
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the RSA private key specifics from an ASN.1 encoded file
|
||||
*/
|
||||
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
|
||||
{
|
||||
int offset = 7;
|
||||
uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL;
|
||||
int mod_len, priv_len, pub_len;
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL;
|
||||
int p_len, q_len, dP_len, dQ_len, qInv_len;
|
||||
#endif
|
||||
|
||||
/* not in der format */
|
||||
if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: This is not a valid ASN.1 file\n");
|
||||
#endif
|
||||
return X509_INVALID_PRIV_KEY;
|
||||
}
|
||||
|
||||
/* Use the private key to mix up the RNG if possible. */
|
||||
RNG_custom_init(buf, len);
|
||||
|
||||
mod_len = asn1_get_int(buf, &offset, &modulus);
|
||||
pub_len = asn1_get_int(buf, &offset, &pub_exp);
|
||||
priv_len = asn1_get_int(buf, &offset, &priv_exp);
|
||||
|
||||
if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
|
||||
return X509_INVALID_PRIV_KEY;
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
p_len = asn1_get_int(buf, &offset, &p);
|
||||
q_len = asn1_get_int(buf, &offset, &q);
|
||||
dP_len = asn1_get_int(buf, &offset, &dP);
|
||||
dQ_len = asn1_get_int(buf, &offset, &dQ);
|
||||
qInv_len = asn1_get_int(buf, &offset, &qInv);
|
||||
|
||||
if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
|
||||
return X509_INVALID_PRIV_KEY;
|
||||
|
||||
RSA_priv_key_new(rsa_ctx,
|
||||
modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
|
||||
p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
|
||||
|
||||
free(p);
|
||||
free(q);
|
||||
free(dP);
|
||||
free(dQ);
|
||||
free(qInv);
|
||||
#else
|
||||
RSA_priv_key_new(rsa_ctx,
|
||||
modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
|
||||
#endif
|
||||
|
||||
free(modulus);
|
||||
free(priv_exp);
|
||||
free(pub_exp);
|
||||
return X509_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time of a certificate. Ignore hours/minutes/seconds.
|
||||
*/
|
||||
static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
|
||||
{
|
||||
int ret = X509_NOT_OK, len, t_offset;
|
||||
struct tm tm;
|
||||
|
||||
if (buf[(*offset)++] != ASN1_UTC_TIME)
|
||||
goto end_utc_time;
|
||||
|
||||
len = get_asn1_length(buf, offset);
|
||||
t_offset = *offset;
|
||||
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
|
||||
|
||||
if (tm.tm_year <= 50) /* 1951-2050 thing */
|
||||
{
|
||||
tm.tm_year += 100;
|
||||
}
|
||||
|
||||
tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
|
||||
tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
|
||||
*t = mktime(&tm);
|
||||
*offset += len;
|
||||
ret = X509_OK;
|
||||
|
||||
end_utc_time:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version type of a certificate (which we don't actually care about)
|
||||
*/
|
||||
int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
|
||||
{
|
||||
int ret = X509_NOT_OK;
|
||||
|
||||
(*offset) += 2; /* get past explicit tag */
|
||||
if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
|
||||
goto end_version;
|
||||
|
||||
ret = X509_OK;
|
||||
end_version:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the notbefore and notafter certificate times.
|
||||
*/
|
||||
int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
|
||||
{
|
||||
return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
|
||||
asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the components of a distinguished name
|
||||
*/
|
||||
static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
|
||||
{
|
||||
int dn_type = 0;
|
||||
int len;
|
||||
|
||||
if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
|
||||
goto end_oid;
|
||||
|
||||
/* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
|
||||
components we are interested in. */
|
||||
if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
|
||||
dn_type = buf[(*offset)++];
|
||||
else
|
||||
{
|
||||
*offset += len; /* skip over it */
|
||||
}
|
||||
|
||||
end_oid:
|
||||
return dn_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain an ASN.1 printable string type.
|
||||
*/
|
||||
static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
|
||||
{
|
||||
int len = X509_NOT_OK;
|
||||
int asn1_type = buf[*offset];
|
||||
|
||||
/* some certs have this awful crud in them for some reason */
|
||||
if (asn1_type != ASN1_PRINTABLE_STR &&
|
||||
asn1_type != ASN1_PRINTABLE_STR2 &&
|
||||
asn1_type != ASN1_TELETEX_STR &&
|
||||
asn1_type != ASN1_IA5_STR &&
|
||||
asn1_type != ASN1_UNICODE_STR)
|
||||
goto end_pnt_str;
|
||||
|
||||
(*offset)++;
|
||||
len = get_asn1_length(buf, offset);
|
||||
|
||||
if (asn1_type == ASN1_UNICODE_STR)
|
||||
{
|
||||
int i;
|
||||
*str = (char *)malloc(len/2+1); /* allow for null */
|
||||
|
||||
for (i = 0; i < len; i += 2)
|
||||
(*str)[i/2] = buf[*offset + i + 1];
|
||||
|
||||
(*str)[len/2] = 0; /* null terminate */
|
||||
}
|
||||
else
|
||||
{
|
||||
*str = (char *)malloc(len+1); /* allow for null */
|
||||
memcpy(*str, &buf[*offset], len);
|
||||
(*str)[len] = 0; /* null terminate */
|
||||
}
|
||||
|
||||
*offset += len;
|
||||
|
||||
end_pnt_str:
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subject name (or the issuer) of a certificate.
|
||||
*/
|
||||
int asn1_name(const uint8_t *cert, int *offset, char *dn[])
|
||||
{
|
||||
int ret = X509_NOT_OK;
|
||||
int dn_type;
|
||||
char *tmp;
|
||||
|
||||
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
|
||||
goto end_name;
|
||||
|
||||
while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
|
||||
{
|
||||
int i, found = 0;
|
||||
|
||||
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
|
||||
(dn_type = asn1_get_oid_x520(cert, offset)) < 0)
|
||||
goto end_name;
|
||||
|
||||
tmp = NULL;
|
||||
|
||||
if (asn1_get_printable_str(cert, offset, &tmp) < 0)
|
||||
{
|
||||
free(tmp);
|
||||
goto end_name;
|
||||
}
|
||||
|
||||
/* find the distinguished named type */
|
||||
for (i = 0; i < X509_NUM_DN_TYPES; i++)
|
||||
{
|
||||
if (dn_type == g_dn_types[i])
|
||||
{
|
||||
if (dn[i] == NULL)
|
||||
{
|
||||
dn[i] = tmp;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) /* not found so get rid of it */
|
||||
{
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
ret = X509_OK;
|
||||
end_name:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the modulus and public exponent of a certificate.
|
||||
*/
|
||||
int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
|
||||
{
|
||||
int ret = X509_NOT_OK, mod_len, pub_len;
|
||||
uint8_t *modulus = NULL, *pub_exp = NULL;
|
||||
|
||||
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
|
||||
asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
|
||||
goto end_pub_key;
|
||||
|
||||
(*offset)++; /* ignore the padding bit field */
|
||||
|
||||
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
|
||||
goto end_pub_key;
|
||||
|
||||
mod_len = asn1_get_int(cert, offset, &modulus);
|
||||
pub_len = asn1_get_int(cert, offset, &pub_exp);
|
||||
RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
|
||||
free(modulus);
|
||||
free(pub_exp);
|
||||
ret = X509_OK;
|
||||
|
||||
end_pub_key:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
/**
|
||||
* Read the signature of the certificate.
|
||||
*/
|
||||
int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
|
||||
{
|
||||
int ret = X509_NOT_OK;
|
||||
|
||||
if (cert[(*offset)++] != ASN1_BIT_STRING)
|
||||
goto end_sig;
|
||||
|
||||
x509_ctx->sig_len = get_asn1_length(cert, offset)-1;
|
||||
(*offset)++; /* ignore bit string padding bits */
|
||||
x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
|
||||
memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
|
||||
*offset += x509_ctx->sig_len;
|
||||
ret = X509_OK;
|
||||
|
||||
end_sig:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare 2 distinguished name components for equality
|
||||
* @return 0 if a match
|
||||
*/
|
||||
static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (dn1 == NULL && dn2 == NULL)
|
||||
ret = 0;
|
||||
else
|
||||
ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up all of the CA certificates.
|
||||
*/
|
||||
void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (ca_cert_ctx == NULL)
|
||||
return;
|
||||
|
||||
while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
|
||||
{
|
||||
x509_free(ca_cert_ctx->cert[i]);
|
||||
ca_cert_ctx->cert[i++] = NULL;
|
||||
}
|
||||
|
||||
free(ca_cert_ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare 2 distinguished names for equality
|
||||
* @return 0 if a match
|
||||
*/
|
||||
int asn1_compare_dn(char * const dn1[], char * const dn2[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < X509_NUM_DN_TYPES; i++)
|
||||
{
|
||||
if (asn1_compare_dn_comp(dn1[i], dn2[i]))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0; /* all good */
|
||||
}
|
||||
|
||||
int asn1_find_oid(const uint8_t* cert, int* offset,
|
||||
const uint8_t* oid, int oid_length)
|
||||
{
|
||||
int seqlen;
|
||||
if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0)
|
||||
{
|
||||
int end = *offset + seqlen;
|
||||
|
||||
while (*offset < end)
|
||||
{
|
||||
int type = cert[(*offset)++];
|
||||
int length = get_asn1_length(cert, offset);
|
||||
int noffset = *offset + length;
|
||||
|
||||
if (type == ASN1_SEQUENCE)
|
||||
{
|
||||
type = cert[(*offset)++];
|
||||
length = get_asn1_length(cert, offset);
|
||||
|
||||
if (type == ASN1_OID && length == oid_length &&
|
||||
memcmp(cert + *offset, oid, oid_length) == 0)
|
||||
{
|
||||
*offset += oid_length;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
*offset = noffset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asn1_find_subjectaltname(const uint8_t* cert, int offset)
|
||||
{
|
||||
if (asn1_find_oid(cert, &offset, sig_subject_alt_name,
|
||||
SIG_SUBJECT_ALT_NAME_SIZE))
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
|
||||
/**
|
||||
* Read the signature type of the certificate. We only support RSA-MD5 and
|
||||
* RSA-SHA1 signature types.
|
||||
*/
|
||||
int asn1_signature_type(const uint8_t *cert,
|
||||
int *offset, X509_CTX *x509_ctx)
|
||||
{
|
||||
int ret = X509_NOT_OK, len;
|
||||
|
||||
if (cert[(*offset)++] != ASN1_OID)
|
||||
goto end_check_sig;
|
||||
|
||||
len = get_asn1_length(cert, offset);
|
||||
|
||||
if (len == 5 && memcmp(sig_sha1WithRSAEncrypt, &cert[*offset],
|
||||
SIG_IIS6_OID_SIZE) == 0)
|
||||
{
|
||||
x509_ctx->sig_type = SIG_TYPE_SHA1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
|
||||
goto end_check_sig; /* unrecognised cert type */
|
||||
|
||||
x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
|
||||
}
|
||||
|
||||
*offset += len;
|
||||
asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */
|
||||
ret = X509_OK;
|
||||
|
||||
end_check_sig:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
#ifndef CERT_H
|
||||
#define CERT_H
|
||||
|
||||
/*
|
||||
unsigned char default_certificate[] = {
|
||||
0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab,
|
||||
0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
|
||||
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34,
|
||||
0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61,
|
||||
0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
|
||||
0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32,
|
||||
0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32,
|
||||
0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a,
|
||||
0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
|
||||
0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
||||
0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81,
|
||||
0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
||||
0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
|
||||
0x81, 0x81, 0x00, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76,
|
||||
0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f,
|
||||
0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90,
|
||||
0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14,
|
||||
0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d,
|
||||
0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46,
|
||||
0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa,
|
||||
0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a,
|
||||
0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82,
|
||||
0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32,
|
||||
0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02,
|
||||
0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40,
|
||||
0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88,
|
||||
0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06,
|
||||
0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b,
|
||||
0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8,
|
||||
0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13,
|
||||
0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac,
|
||||
0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27,
|
||||
0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e,
|
||||
0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80,
|
||||
0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54,
|
||||
0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5
|
||||
};
|
||||
unsigned int default_certificate_len = 475;
|
||||
*/
|
||||
unsigned char default_certificate[] = {
|
||||
0x30, 0x82, 0x03, 0xb8, 0x30, 0x82, 0x03, 0x21, 0xa0, 0x03, 0x02, 0x01,
|
||||
0x02, 0x02, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55, 0x5d, 0xa4, 0x8f,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
||||
0x05, 0x05, 0x00, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12,
|
||||
0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73,
|
||||
0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
|
||||
0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41,
|
||||
0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
|
||||
0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72,
|
||||
0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
||||
0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c,
|
||||
0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79,
|
||||
0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x35,
|
||||
0x31, 0x33, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, 0x34,
|
||||
0x36, 0x30, 0x33, 0x32, 0x31, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a,
|
||||
0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
|
||||
0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04,
|
||||
0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06,
|
||||
0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73, 0x74, 0x76, 0x69,
|
||||
0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
||||
0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41, 0x74, 0x6f, 0x6d,
|
||||
0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72, 0x08, 0x08, 0x31,
|
||||
0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x41, 0x73,
|
||||
0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c, 0x73, 0x31, 0x25,
|
||||
0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
|
||||
0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x40, 0x61, 0x73,
|
||||
0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
|
||||
0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, 0xe0, 0x59, 0x6a, 0x19, 0x08,
|
||||
0x0d, 0x21, 0x98, 0x79, 0x96, 0x16, 0x2a, 0x5a, 0x5c, 0x20, 0xeb, 0x66,
|
||||
0x1e, 0x9e, 0x1e, 0xc4, 0xef, 0x83, 0x42, 0x15, 0xd8, 0x4b, 0x14, 0xd3,
|
||||
0xe7, 0xba, 0xc8, 0xf6, 0xb4, 0x52, 0xdf, 0x18, 0xa6, 0x6b, 0x8b, 0xca,
|
||||
0x84, 0xdc, 0x21, 0x26, 0xfd, 0x7c, 0xde, 0xbd, 0x2b, 0x64, 0x0d, 0xd3,
|
||||
0x20, 0x7c, 0xe7, 0x0c, 0xfc, 0x3c, 0xa9, 0x09, 0xc0, 0xa7, 0x78, 0x3d,
|
||||
0xe9, 0x48, 0x50, 0x90, 0xd7, 0x3e, 0x46, 0x78, 0x8f, 0xfc, 0xc8, 0xb6,
|
||||
0x89, 0x41, 0x49, 0x15, 0x47, 0x27, 0x4b, 0x46, 0xcb, 0x11, 0x82, 0xd8,
|
||||
0x7b, 0x68, 0xb7, 0xc5, 0x64, 0x70, 0xaf, 0xe6, 0x80, 0x63, 0xfe, 0x53,
|
||||
0x70, 0xee, 0xd2, 0xa9, 0x2c, 0x40, 0x96, 0x9c, 0xd4, 0xa1, 0xcf, 0xd4,
|
||||
0x51, 0x9d, 0xe1, 0xa7, 0xf0, 0xfb, 0xa6, 0x49, 0x4c, 0x00, 0x05, 0xff,
|
||||
0x8f, 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x02, 0x30,
|
||||
0x81, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
|
||||
0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f,
|
||||
0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0x30, 0x81, 0xcf,
|
||||
0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xc7, 0x30, 0x81, 0xc4, 0x80,
|
||||
0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f,
|
||||
0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0xa1, 0x81, 0xa0,
|
||||
0xa4, 0x81, 0x9d, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12,
|
||||
0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73,
|
||||
0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
|
||||
0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41,
|
||||
0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
|
||||
0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72,
|
||||
0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
||||
0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c,
|
||||
0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79,
|
||||
0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55,
|
||||
0x5d, 0xa4, 0x8f, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
|
||||
0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
||||
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
|
||||
0x89, 0x79, 0xf2, 0xa8, 0xd3, 0xc7, 0x02, 0x2d, 0x02, 0x68, 0x9a, 0xf1,
|
||||
0xa7, 0x10, 0xa2, 0x2c, 0x52, 0x12, 0xf2, 0x97, 0x39, 0x52, 0x83, 0x69,
|
||||
0xd7, 0xe7, 0x73, 0x1f, 0xf1, 0x02, 0x5e, 0xbe, 0x5f, 0xbe, 0x94, 0xa9,
|
||||
0x4d, 0x8f, 0xb7, 0x3c, 0x52, 0x35, 0x09, 0x0a, 0x69, 0xed, 0x5e, 0x12,
|
||||
0xc9, 0x4d, 0x59, 0xec, 0x47, 0xfa, 0x82, 0xe5, 0x79, 0xbc, 0x17, 0x9d,
|
||||
0xae, 0x02, 0x17, 0xb5, 0xfb, 0xca, 0xc7, 0x42, 0xf4, 0xb5, 0x48, 0x19,
|
||||
0x1c, 0xd4, 0xd6, 0xfb, 0x2a, 0x7b, 0x0e, 0x8b, 0x56, 0xcc, 0x8e, 0x7a,
|
||||
0xa8, 0xaf, 0x4e, 0x5a, 0xa1, 0xf1, 0x78, 0x37, 0x4d, 0x09, 0x03, 0x9a,
|
||||
0xde, 0x4c, 0x87, 0xbe, 0xb1, 0x93, 0x1a, 0x39, 0x9a, 0xbb, 0xa0, 0x5c,
|
||||
0xfe, 0x58, 0x71, 0x62, 0x20, 0x74, 0x04, 0xc5, 0x50, 0x6e, 0x7b, 0xad,
|
||||
0xbe, 0xb0, 0xaa, 0x64, 0xea, 0x48, 0xa7, 0x9f
|
||||
};
|
||||
unsigned int default_certificate_len = 956;
|
||||
|
||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
#define CONFIG_DEBUG
|
||||
#define CONFIG_STRIP_UNWANTED_SECTIONS 1
|
||||
|
||||
/*
|
||||
* BigInt Options
|
||||
*/
|
||||
#define CONFIG_BIGINT_BARRETT 1
|
||||
#define CONFIG_BIGINT_CRT 1
|
||||
#define CONFIG_INTEGER_32BIT 1
|
||||
|
||||
/*
|
||||
* SSL Library
|
||||
*/
|
||||
#define CONFIG_SSL_ENABLE_CLIENT 1
|
||||
//#define CONFIG_SSL_SKELETON_MODE
|
||||
#define CONFIG_SSL_PROT_LOW 1
|
||||
//#undef CONFIG_SSL_PROT_MEDIUM
|
||||
//#undef CONFIG_SSL_PROT_HIGH
|
||||
#define CONFIG_SSL_USE_DEFAULT_KEY 1
|
||||
#define CONFIG_SSL_PRIVATE_KEY_LOCATION ""
|
||||
#define CONFIG_SSL_PRIVATE_KEY_PASSWORD ""
|
||||
#define CONFIG_SSL_X509_CERT_LOCATION ""
|
||||
#undef CONFIG_SSL_GENERATE_X509_CERT
|
||||
#define CONFIG_SSL_X509_COMMON_NAME ""
|
||||
#define CONFIG_SSL_X509_ORGANIZATION_NAME ""
|
||||
#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME ""
|
||||
#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE
|
||||
#undef CONFIG_SSL_HAS_PEM
|
||||
#undef CONFIG_SSL_USE_PKCS12
|
||||
#define CONFIG_SSL_EXPIRY_TIME 24
|
||||
#define CONFIG_X509_MAX_CA_CERTS 1
|
||||
#define CONFIG_SSL_MAX_CERTS 1
|
||||
#undef CONFIG_SSL_CTX_MUTEXING
|
||||
#undef CONFIG_USE_DEV_URANDOM
|
||||
#undef CONFIG_WIN32_USE_CRYPTO_LIB
|
||||
#undef CONFIG_OPENSSL_COMPATIBLE
|
||||
#undef CONFIG_PERFORMANCE_TESTING
|
||||
#undef CONFIG_SSL_TEST
|
||||
#undef CONFIG_AXTLSWRAP
|
||||
#undef CONFIG_AXHTTPD
|
||||
#undef CONFIG_HTTP_STATIC_BUILD
|
||||
#undef CONFIG_HTTP_HAS_CGI
|
||||
#define CONFIG_HTTP_CGI_EXTENSIONS ""
|
||||
#undef CONFIG_HTTP_ENABLE_LUA
|
||||
#define CONFIG_HTTP_LUA_PREFIX ""
|
||||
#undef CONFIG_HTTP_BUILD_LUA
|
||||
#define CONFIG_HTTP_CGI_LAUNCHER ""
|
||||
#undef CONFIG_HTTP_DIRECTORIES
|
||||
#undef CONFIG_HTTP_HAS_AUTHORIZATION
|
||||
#undef CONFIG_HTTP_HAS_IPV6
|
||||
#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER
|
||||
#define CONFIG_HTTP_USER ""
|
||||
#undef CONFIG_HTTP_VERBOSE
|
||||
#undef CONFIG_HTTP_IS_DAEMON
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#define CONFIG_SSL_FULL_MODE
|
||||
|
||||
#define MBED
|
||||
|
||||
#endif
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file crypto_misc.h
|
||||
*/
|
||||
|
||||
#ifndef HEADER_CRYPTO_MISC_H
|
||||
#define HEADER_CRYPTO_MISC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "crypto.h"
|
||||
#include "bigint.h"
|
||||
#include "config.h"
|
||||
|
||||
/**************************************************************************
|
||||
* X509 declarations
|
||||
**************************************************************************/
|
||||
#define X509_OK 0
|
||||
#define X509_NOT_OK -1
|
||||
#define X509_VFY_ERROR_NO_TRUSTED_CERT -2
|
||||
#define X509_VFY_ERROR_BAD_SIGNATURE -3
|
||||
#define X509_VFY_ERROR_NOT_YET_VALID -4
|
||||
#define X509_VFY_ERROR_EXPIRED -5
|
||||
#define X509_VFY_ERROR_SELF_SIGNED -6
|
||||
#define X509_VFY_ERROR_INVALID_CHAIN -7
|
||||
#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
|
||||
#define X509_INVALID_PRIV_KEY -9
|
||||
|
||||
/*
|
||||
* The Distinguished Name
|
||||
*/
|
||||
#define X509_NUM_DN_TYPES 3
|
||||
#define X509_COMMON_NAME 0
|
||||
#define X509_ORGANIZATION 1
|
||||
#define X509_ORGANIZATIONAL_UNIT 2
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct _x509_ctx
|
||||
{
|
||||
char *ca_cert_dn[X509_NUM_DN_TYPES];
|
||||
char *cert_dn[X509_NUM_DN_TYPES];
|
||||
char **subject_alt_dnsnames;
|
||||
time_t not_before;
|
||||
time_t not_after;
|
||||
uint8_t *signature;
|
||||
uint16_t sig_len;
|
||||
uint8_t sig_type;
|
||||
RSA_CTX *rsa_ctx;
|
||||
bigint *digest;
|
||||
struct _x509_ctx *next;
|
||||
};
|
||||
|
||||
typedef struct _x509_ctx X509_CTX;
|
||||
typedef struct
|
||||
{
|
||||
X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
|
||||
} CA_CERT_CTX;
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
|
||||
#endif
|
||||
|
||||
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
|
||||
void x509_free(X509_CTX *x509_ctx);
|
||||
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
#endif
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);
|
||||
const char * x509_display_error(int error);
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* ASN1 declarations
|
||||
**************************************************************************/
|
||||
#define ASN1_INTEGER 0x02
|
||||
#define ASN1_BIT_STRING 0x03
|
||||
#define ASN1_OCTET_STRING 0x04
|
||||
#define ASN1_NULL 0x05
|
||||
#define ASN1_PRINTABLE_STR2 0x0C
|
||||
#define ASN1_OID 0x06
|
||||
#define ASN1_PRINTABLE_STR2 0x0C
|
||||
#define ASN1_PRINTABLE_STR 0x13
|
||||
#define ASN1_TELETEX_STR 0x14
|
||||
#define ASN1_IA5_STR 0x16
|
||||
#define ASN1_UTC_TIME 0x17
|
||||
#define ASN1_UNICODE_STR 0x1e
|
||||
#define ASN1_SEQUENCE 0x30
|
||||
#define ASN1_CONTEXT_DNSNAME 0x82
|
||||
#define ASN1_SET 0x31
|
||||
#define ASN1_V3_DATA 0xa3
|
||||
#define ASN1_IMPLICIT_TAG 0x80
|
||||
#define ASN1_CONTEXT_DNSNAME 0x82
|
||||
#define ASN1_EXPLICIT_TAG 0xa0
|
||||
#define ASN1_V3_DATA 0xa3
|
||||
|
||||
#define SIG_TYPE_MD2 0x02
|
||||
#define SIG_TYPE_MD5 0x04
|
||||
#define SIG_TYPE_SHA1 0x05
|
||||
|
||||
int get_asn1_length(const uint8_t *buf, int *offset);
|
||||
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
|
||||
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
|
||||
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
|
||||
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
|
||||
int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||
int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||
int asn1_name(const uint8_t *cert, int *offset, char *dn[]);
|
||||
int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||
int asn1_find_subjectaltname(const uint8_t* cert, int offset);
|
||||
int asn1_compare_dn(char * const dn1[], char * const dn2[]);
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
int asn1_signature_type(const uint8_t *cert,
|
||||
int *offset, X509_CTX *x509_ctx);
|
||||
|
||||
/**************************************************************************
|
||||
* MISC declarations
|
||||
**************************************************************************/
|
||||
#define SALT_SIZE 8
|
||||
|
||||
extern const char * const unsupported_str;
|
||||
|
||||
typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
|
||||
typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest);
|
||||
|
||||
int get_file(const char *filename, uint8_t **buf);
|
||||
|
||||
#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
|
||||
EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...);
|
||||
#else
|
||||
#define print_blob(...)
|
||||
#endif
|
||||
|
||||
EXP_FUNC int STDCALL base64_decode(const char *in, int len,
|
||||
uint8_t *out, int *outlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,364 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef CONFIG_SSL_GENERATE_X509_CERT
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "os_port.h"
|
||||
#include "ssl.h"
|
||||
|
||||
/**
|
||||
* Generate a basic X.509 certificate
|
||||
*/
|
||||
|
||||
static uint8_t set_gen_length(int len, uint8_t *buf, int *offset)
|
||||
{
|
||||
if (len < 0x80) /* short form */
|
||||
{
|
||||
buf[(*offset)++] = len;
|
||||
return 1;
|
||||
}
|
||||
else /* long form */
|
||||
{
|
||||
int i, length_bytes = 0;
|
||||
|
||||
if (len & 0x00FF0000)
|
||||
length_bytes = 3;
|
||||
else if (len & 0x0000FF00)
|
||||
length_bytes = 2;
|
||||
else if (len & 0x000000FF)
|
||||
length_bytes = 1;
|
||||
|
||||
buf[(*offset)++] = 0x80 + length_bytes;
|
||||
|
||||
for (i = length_bytes-1; i >= 0; i--)
|
||||
{
|
||||
buf[*offset+i] = len & 0xFF;
|
||||
len >>= 8;
|
||||
}
|
||||
|
||||
*offset += length_bytes;
|
||||
return length_bytes+1;
|
||||
}
|
||||
}
|
||||
|
||||
static int pre_adjust_with_size(uint8_t type,
|
||||
int *seq_offset, uint8_t *buf, int *offset)
|
||||
{
|
||||
buf[(*offset)++] = type;
|
||||
*seq_offset = *offset;
|
||||
*offset += 4; /* fill in later */
|
||||
return *offset;
|
||||
}
|
||||
|
||||
static void adjust_with_size(int seq_size, int seq_start,
|
||||
uint8_t *buf, int *offset)
|
||||
{
|
||||
uint8_t seq_byte_size;
|
||||
int orig_seq_size = seq_size;
|
||||
int orig_seq_start = seq_start;
|
||||
|
||||
seq_size = *offset-seq_size;
|
||||
seq_byte_size = set_gen_length(seq_size, buf, &seq_start);
|
||||
|
||||
if (seq_byte_size != 4)
|
||||
{
|
||||
memmove(&buf[orig_seq_start+seq_byte_size],
|
||||
&buf[orig_seq_size], seq_size);
|
||||
*offset -= 4-seq_byte_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_serial_number(uint8_t *buf, int *offset)
|
||||
{
|
||||
static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F };
|
||||
memcpy(&buf[*offset], ser_oid , sizeof(ser_oid));
|
||||
*offset += sizeof(ser_oid);
|
||||
}
|
||||
|
||||
static void gen_signature_alg(uint8_t *buf, int *offset)
|
||||
{
|
||||
/* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */
|
||||
static const uint8_t sig_oid[] =
|
||||
{
|
||||
ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
|
||||
ASN1_NULL, 0x00
|
||||
};
|
||||
|
||||
memcpy(&buf[*offset], sig_oid, sizeof(sig_oid));
|
||||
*offset += sizeof(sig_oid);
|
||||
}
|
||||
|
||||
static int gen_dn(const char *name, uint8_t dn_type,
|
||||
uint8_t *buf, int *offset)
|
||||
{
|
||||
int ret = X509_OK;
|
||||
int name_size = strlen(name);
|
||||
|
||||
if (name_size > 0x70) /* just too big */
|
||||
{
|
||||
ret = X509_NOT_OK;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buf[(*offset)++] = ASN1_SET;
|
||||
set_gen_length(9+name_size, buf, offset);
|
||||
buf[(*offset)++] = ASN1_SEQUENCE;
|
||||
set_gen_length(7+name_size, buf, offset);
|
||||
buf[(*offset)++] = ASN1_OID;
|
||||
buf[(*offset)++] = 3;
|
||||
buf[(*offset)++] = 0x55;
|
||||
buf[(*offset)++] = 0x04;
|
||||
buf[(*offset)++] = dn_type;
|
||||
buf[(*offset)++] = ASN1_PRINTABLE_STR;
|
||||
buf[(*offset)++] = name_size;
|
||||
strcpy(&buf[*offset], name);
|
||||
*offset += name_size;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gen_issuer(const char * dn[], uint8_t *buf, int *offset)
|
||||
{
|
||||
int ret = X509_OK;
|
||||
int seq_offset;
|
||||
int seq_size = pre_adjust_with_size(
|
||||
ASN1_SEQUENCE, &seq_offset, buf, offset);
|
||||
char fqdn[128];
|
||||
|
||||
/* we need the common name, so if not configured, work out the fully
|
||||
* qualified domain name */
|
||||
if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0)
|
||||
{
|
||||
int fqdn_len;
|
||||
gethostname(fqdn, sizeof(fqdn));
|
||||
fqdn_len = strlen(fqdn);
|
||||
fqdn[fqdn_len++] = '.';
|
||||
getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len);
|
||||
fqdn_len = strlen(fqdn);
|
||||
|
||||
if (fqdn[fqdn_len-1] == '.') /* ensure '.' is not last char */
|
||||
fqdn[fqdn_len-1] = 0;
|
||||
|
||||
dn[X509_COMMON_NAME] = fqdn;
|
||||
}
|
||||
|
||||
if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset)))
|
||||
goto error;
|
||||
|
||||
if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0)
|
||||
{
|
||||
if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (dn[X509_ORGANIZATIONAL_UNIT] != NULL &&
|
||||
strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0)
|
||||
{
|
||||
if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
adjust_with_size(seq_size, seq_offset, buf, offset);
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gen_utc_time(uint8_t *buf, int *offset)
|
||||
{
|
||||
static const uint8_t time_seq[] =
|
||||
{
|
||||
ASN1_SEQUENCE, 30,
|
||||
ASN1_UTC_TIME, 13,
|
||||
'0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z',
|
||||
ASN1_UTC_TIME, 13, /* make it good for 30 or so years */
|
||||
'3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z'
|
||||
};
|
||||
|
||||
/* fixed time */
|
||||
memcpy(&buf[*offset], time_seq, sizeof(time_seq));
|
||||
*offset += sizeof(time_seq);
|
||||
}
|
||||
|
||||
static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
|
||||
{
|
||||
static const uint8_t pub_key_seq[] =
|
||||
{
|
||||
ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */
|
||||
};
|
||||
|
||||
int seq_offset;
|
||||
int pub_key_size = rsa_ctx->num_octets;
|
||||
uint8_t *block = (uint8_t *)alloca(pub_key_size);
|
||||
int seq_size = pre_adjust_with_size(
|
||||
ASN1_SEQUENCE, &seq_offset, buf, offset);
|
||||
buf[(*offset)++] = ASN1_INTEGER;
|
||||
bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size);
|
||||
|
||||
if (*block & 0x80) /* make integer positive */
|
||||
{
|
||||
set_gen_length(pub_key_size+1, buf, offset);
|
||||
buf[(*offset)++] = 0;
|
||||
}
|
||||
else
|
||||
set_gen_length(pub_key_size, buf, offset);
|
||||
|
||||
memcpy(&buf[*offset], block, pub_key_size);
|
||||
*offset += pub_key_size;
|
||||
memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq));
|
||||
*offset += sizeof(pub_key_seq);
|
||||
adjust_with_size(seq_size, seq_offset, buf, offset);
|
||||
}
|
||||
|
||||
static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
|
||||
{
|
||||
int seq_offset;
|
||||
int seq_size = pre_adjust_with_size(
|
||||
ASN1_BIT_STRING, &seq_offset, buf, offset);
|
||||
buf[(*offset)++] = 0; /* bit string is multiple of 8 */
|
||||
gen_pub_key2(rsa_ctx, buf, offset);
|
||||
adjust_with_size(seq_size, seq_offset, buf, offset);
|
||||
}
|
||||
|
||||
static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
|
||||
{
|
||||
/* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */
|
||||
static const uint8_t rsa_enc_oid[] =
|
||||
{
|
||||
ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
|
||||
ASN1_NULL, 0x00
|
||||
};
|
||||
|
||||
int seq_offset;
|
||||
int seq_size = pre_adjust_with_size(
|
||||
ASN1_SEQUENCE, &seq_offset, buf, offset);
|
||||
|
||||
memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid));
|
||||
*offset += sizeof(rsa_enc_oid);
|
||||
gen_pub_key1(rsa_ctx, buf, offset);
|
||||
adjust_with_size(seq_size, seq_offset, buf, offset);
|
||||
}
|
||||
|
||||
static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst,
|
||||
uint8_t *buf, int *offset)
|
||||
{
|
||||
static const uint8_t asn1_sig[] =
|
||||
{
|
||||
ASN1_SEQUENCE, 0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05,
|
||||
0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */
|
||||
ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14
|
||||
};
|
||||
|
||||
uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets);
|
||||
uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE);
|
||||
int sig_size;
|
||||
|
||||
/* add the digest as an embedded asn.1 sequence */
|
||||
memcpy(block, asn1_sig, sizeof(asn1_sig));
|
||||
memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE);
|
||||
|
||||
sig_size = RSA_encrypt(rsa_ctx, block,
|
||||
sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1);
|
||||
|
||||
buf[(*offset)++] = ASN1_BIT_STRING;
|
||||
set_gen_length(sig_size+1, buf, offset);
|
||||
buf[(*offset)++] = 0; /* bit string is multiple of 8 */
|
||||
memcpy(&buf[*offset], enc_block, sig_size);
|
||||
*offset += sig_size;
|
||||
}
|
||||
|
||||
static int gen_tbs_cert(const char * dn[],
|
||||
const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset,
|
||||
uint8_t *sha_dgst)
|
||||
{
|
||||
int ret = X509_OK;
|
||||
SHA1_CTX sha_ctx;
|
||||
int seq_offset;
|
||||
int begin_tbs = *offset;
|
||||
int seq_size = pre_adjust_with_size(
|
||||
ASN1_SEQUENCE, &seq_offset, buf, offset);
|
||||
|
||||
gen_serial_number(buf, offset);
|
||||
gen_signature_alg(buf, offset);
|
||||
|
||||
/* CA certicate issuer */
|
||||
if ((ret = gen_issuer(dn, buf, offset)))
|
||||
goto error;
|
||||
|
||||
gen_utc_time(buf, offset);
|
||||
|
||||
/* certificate issuer */
|
||||
if ((ret = gen_issuer(dn, buf, offset)))
|
||||
goto error;
|
||||
|
||||
gen_pub_key(rsa_ctx, buf, offset);
|
||||
adjust_with_size(seq_size, seq_offset, buf, offset);
|
||||
|
||||
SHA1_Init(&sha_ctx);
|
||||
SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs);
|
||||
SHA1_Final(sha_dgst, &sha_ctx);
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new certificate.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data)
|
||||
{
|
||||
int ret = X509_OK, offset = 0, seq_offset;
|
||||
/* allocate enough space to load a new certificate */
|
||||
uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512);
|
||||
uint8_t sha_dgst[SHA1_SIZE];
|
||||
int seq_size = pre_adjust_with_size(ASN1_SEQUENCE,
|
||||
&seq_offset, buf, &offset);
|
||||
|
||||
if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0)
|
||||
goto error;
|
||||
|
||||
gen_signature_alg(buf, &offset);
|
||||
gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset);
|
||||
adjust_with_size(seq_size, seq_offset, buf, &offset);
|
||||
*cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */
|
||||
memcpy(*cert_data, buf, offset);
|
||||
|
||||
error:
|
||||
return ret < 0 ? ret : offset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,480 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load certificates/keys into memory. These can be in many different formats.
|
||||
* PEM support and other formats can be processed here.
|
||||
*
|
||||
* The PEM private keys may be optionally encrypted with AES128 or AES256.
|
||||
* The encrypted PEM keys were generated with something like:
|
||||
*
|
||||
* openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "os_port.h"
|
||||
#include "ssl.h"
|
||||
#include "config.h"
|
||||
|
||||
static int do_obj(SSL_CTX *ssl_ctx, int obj_type,
|
||||
SSLObjLoader *ssl_obj, const char *password);
|
||||
#ifdef CONFIG_SSL_HAS_PEM
|
||||
static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type,
|
||||
SSLObjLoader *ssl_obj, const char *password);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load a file into memory that is in binary DER (or ascii PEM) format.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type,
|
||||
const char *filename, const char *password)
|
||||
{
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
static const char * const begin = "-----BEGIN";
|
||||
int ret = SSL_OK;
|
||||
SSLObjLoader *ssl_obj = NULL;
|
||||
|
||||
if (filename == NULL)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_KEY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
|
||||
ssl_obj->len = get_file(filename, &ssl_obj->buf);
|
||||
if (ssl_obj->len <= 0)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_KEY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* is the file a PEM file? */
|
||||
if (strstr((char *)ssl_obj->buf, begin) != NULL)
|
||||
{
|
||||
#ifdef CONFIG_SSL_HAS_PEM
|
||||
ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);
|
||||
#else
|
||||
printf(unsupported_str);
|
||||
ret = SSL_ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);
|
||||
|
||||
error:
|
||||
ssl_obj_free(ssl_obj);
|
||||
return ret;
|
||||
#else
|
||||
printf(unsupported_str);
|
||||
return SSL_ERROR_NOT_SUPPORTED;
|
||||
#endif /* CONFIG_SSL_SKELETON_MODE */
|
||||
}
|
||||
|
||||
/*
|
||||
* Transfer binary data into the object loader.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type,
|
||||
const uint8_t *data, int len, const char *password)
|
||||
{
|
||||
int ret;
|
||||
SSLObjLoader ssl_obj;
|
||||
ssl_obj.buf = data;
|
||||
ssl_obj.len = len;
|
||||
ret = do_obj(ssl_ctx, mem_type, &ssl_obj, password);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually work out what we are doing
|
||||
*/
|
||||
static int do_obj(SSL_CTX *ssl_ctx, int obj_type,
|
||||
SSLObjLoader *ssl_obj, const char *password)
|
||||
{
|
||||
int ret = SSL_OK;
|
||||
|
||||
switch (obj_type)
|
||||
{
|
||||
case SSL_OBJ_RSA_KEY:
|
||||
ret = add_private_key(ssl_ctx, ssl_obj);
|
||||
break;
|
||||
|
||||
case SSL_OBJ_X509_CERT:
|
||||
ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
case SSL_OBJ_X509_CACERT:
|
||||
add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SSL_USE_PKCS12
|
||||
case SSL_OBJ_PKCS8:
|
||||
ret = pkcs8_decode(ssl_ctx, ssl_obj, password);
|
||||
break;
|
||||
|
||||
case SSL_OBJ_PKCS12:
|
||||
ret = pkcs12_decode(ssl_ctx, ssl_obj, password);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf(unsupported_str);
|
||||
ret = SSL_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up our mess.
|
||||
*/
|
||||
void ssl_obj_free(SSLObjLoader *ssl_obj)
|
||||
{
|
||||
if (ssl_obj)
|
||||
{
|
||||
free(ssl_obj->buf);
|
||||
free(ssl_obj);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for PEM encoded keys/certificates.
|
||||
*/
|
||||
#ifdef CONFIG_SSL_HAS_PEM
|
||||
|
||||
#define NUM_PEM_TYPES 4
|
||||
#define IV_SIZE 16
|
||||
#define IS_RSA_PRIVATE_KEY 0
|
||||
#define IS_ENCRYPTED_PRIVATE_KEY 1
|
||||
#define IS_PRIVATE_KEY 2
|
||||
#define IS_CERTIFICATE 3
|
||||
|
||||
static const char * const begins[NUM_PEM_TYPES] =
|
||||
{
|
||||
"-----BEGIN RSA PRIVATE KEY-----",
|
||||
"-----BEGIN ENCRYPTED PRIVATE KEY-----",
|
||||
"-----BEGIN PRIVATE KEY-----",
|
||||
"-----BEGIN CERTIFICATE-----",
|
||||
};
|
||||
|
||||
static const char * const ends[NUM_PEM_TYPES] =
|
||||
{
|
||||
"-----END RSA PRIVATE KEY-----",
|
||||
"-----END ENCRYPTED PRIVATE KEY-----",
|
||||
"-----END PRIVATE KEY-----",
|
||||
"-----END CERTIFICATE-----",
|
||||
};
|
||||
|
||||
static const char * const aes_str[2] =
|
||||
{
|
||||
"DEK-Info: AES-128-CBC,",
|
||||
"DEK-Info: AES-256-CBC,"
|
||||
};
|
||||
|
||||
/**
|
||||
* Take a base64 blob of data and decrypt it (using AES) into its
|
||||
* proper ASN.1 form.
|
||||
*/
|
||||
static int pem_decrypt(const char *where, const char *end,
|
||||
const char *password, SSLObjLoader *ssl_obj)
|
||||
{
|
||||
int ret = -1;
|
||||
int is_aes_256 = 0;
|
||||
char *start = NULL;
|
||||
uint8_t iv[IV_SIZE];
|
||||
int i, pem_size;
|
||||
MD5_CTX md5_ctx;
|
||||
AES_CTX aes_ctx;
|
||||
uint8_t key[32]; /* AES256 size */
|
||||
|
||||
if (password == NULL || strlen(password) == 0)
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: Need a password for this PEM file\n"); TTY_FLUSH();
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */
|
||||
{
|
||||
start += strlen(aes_str[0]);
|
||||
}
|
||||
else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */
|
||||
{
|
||||
is_aes_256 = 1;
|
||||
start += strlen(aes_str[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: Unsupported password cipher\n"); TTY_FLUSH();
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* convert from hex to binary - assumes uppercase hex */
|
||||
for (i = 0; i < IV_SIZE; i++)
|
||||
{
|
||||
char c = *start++ - '0';
|
||||
iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;
|
||||
c = *start++ - '0';
|
||||
iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);
|
||||
}
|
||||
|
||||
while (*start == '\r' || *start == '\n')
|
||||
start++;
|
||||
|
||||
/* turn base64 into binary */
|
||||
pem_size = (int)(end-start);
|
||||
if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)
|
||||
goto error;
|
||||
|
||||
/* work out the key */
|
||||
MD5_Init(&md5_ctx);
|
||||
MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
|
||||
MD5_Update(&md5_ctx, iv, SALT_SIZE);
|
||||
MD5_Final(key, &md5_ctx);
|
||||
|
||||
if (is_aes_256)
|
||||
{
|
||||
MD5_Init(&md5_ctx);
|
||||
MD5_Update(&md5_ctx, key, MD5_SIZE);
|
||||
MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
|
||||
MD5_Update(&md5_ctx, iv, SALT_SIZE);
|
||||
MD5_Final(&key[MD5_SIZE], &md5_ctx);
|
||||
}
|
||||
|
||||
/* decrypt using the key/iv */
|
||||
AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);
|
||||
AES_convert_key(&aes_ctx);
|
||||
AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a base64 blob of data and turn it into its proper ASN.1 form.
|
||||
*/
|
||||
static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where,
|
||||
int remain, const char *password)
|
||||
{
|
||||
int ret = SSL_ERROR_BAD_CERTIFICATE;
|
||||
SSLObjLoader *ssl_obj = NULL;
|
||||
|
||||
while (remain > 0)
|
||||
{
|
||||
int i, pem_size, obj_type;
|
||||
char *start = NULL, *end = NULL;
|
||||
|
||||
for (i = 0; i < NUM_PEM_TYPES; i++)
|
||||
{
|
||||
if ((start = strstr(where, begins[i])) &&
|
||||
(end = strstr(where, ends[i])))
|
||||
{
|
||||
remain -= (int)(end-where);
|
||||
start += strlen(begins[i]);
|
||||
pem_size = (int)(end-start);
|
||||
|
||||
ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
|
||||
|
||||
/* 4/3 bigger than what we need but so what */
|
||||
ssl_obj->buf = (uint8_t *)calloc(1, pem_size);
|
||||
ssl_obj->len = pem_size;
|
||||
|
||||
if (i == IS_RSA_PRIVATE_KEY &&
|
||||
strstr(start, "Proc-Type:") &&
|
||||
strstr(start, "4,ENCRYPTED"))
|
||||
{
|
||||
/* check for encrypted PEM file */
|
||||
if (pem_decrypt(start, end, password, ssl_obj) < 0)
|
||||
{
|
||||
ret = SSL_ERROR_BAD_CERTIFICATE;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl_obj->len = pem_size;
|
||||
if (base64_decode(start, pem_size,
|
||||
ssl_obj->buf, &ssl_obj->len) != 0)
|
||||
{
|
||||
ret = SSL_ERROR_BAD_CERTIFICATE;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case IS_RSA_PRIVATE_KEY:
|
||||
obj_type = SSL_OBJ_RSA_KEY;
|
||||
break;
|
||||
|
||||
case IS_ENCRYPTED_PRIVATE_KEY:
|
||||
case IS_PRIVATE_KEY:
|
||||
obj_type = SSL_OBJ_PKCS8;
|
||||
break;
|
||||
|
||||
case IS_CERTIFICATE:
|
||||
obj_type = is_cacert ?
|
||||
SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = SSL_ERROR_BAD_CERTIFICATE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* In a format we can now understand - so process it */
|
||||
if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))
|
||||
goto error;
|
||||
|
||||
end += strlen(ends[i]);
|
||||
remain -= strlen(ends[i]);
|
||||
while (remain > 0 && (*end == '\r' || *end == '\n'))
|
||||
{
|
||||
end++;
|
||||
remain--;
|
||||
}
|
||||
|
||||
where = end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ssl_obj_free(ssl_obj);
|
||||
ssl_obj = NULL;
|
||||
if (start == NULL)
|
||||
break;
|
||||
}
|
||||
error:
|
||||
ssl_obj_free(ssl_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a file into memory that is in ASCII PEM format.
|
||||
*/
|
||||
static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type,
|
||||
SSLObjLoader *ssl_obj, const char *password)
|
||||
{
|
||||
char *start;
|
||||
|
||||
/* add a null terminator */
|
||||
ssl_obj->len++;
|
||||
ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len);
|
||||
ssl_obj->buf[ssl_obj->len-1] = 0;
|
||||
start = (char *)ssl_obj->buf;
|
||||
return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,
|
||||
start, ssl_obj->len, password);
|
||||
}
|
||||
#endif /* CONFIG_SSL_HAS_PEM */
|
||||
|
||||
/**
|
||||
* Load the key/certificates in memory depending on compile-time and user
|
||||
* options.
|
||||
*/
|
||||
int load_key_certs(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
int ret = SSL_OK;
|
||||
uint32_t options = ssl_ctx->options;
|
||||
#ifdef CONFIG_SSL_GENERATE_X509_CERT
|
||||
uint8_t *cert_data = NULL;
|
||||
int cert_size;
|
||||
static const char *dn[] =
|
||||
{
|
||||
CONFIG_SSL_X509_COMMON_NAME,
|
||||
CONFIG_SSL_X509_ORGANIZATION_NAME,
|
||||
CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
|
||||
};
|
||||
#endif
|
||||
|
||||
/* do the private key first */
|
||||
if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)
|
||||
{
|
||||
if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY,
|
||||
CONFIG_SSL_PRIVATE_KEY_LOCATION,
|
||||
CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)
|
||||
goto error;
|
||||
}
|
||||
else if (!(options & SSL_NO_DEFAULT_KEY))
|
||||
{
|
||||
#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
|
||||
// static const /* saves a few more bytes */
|
||||
//#include "private_key.h"
|
||||
// ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,
|
||||
// default_private_key_len, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* now load the certificate */
|
||||
#ifdef CONFIG_SSL_GENERATE_X509_CERT
|
||||
if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)
|
||||
{
|
||||
ret = cert_size;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);
|
||||
free(cert_data);
|
||||
#else
|
||||
if (strlen(CONFIG_SSL_X509_CERT_LOCATION))
|
||||
{
|
||||
if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT,
|
||||
CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)
|
||||
goto error;
|
||||
}
|
||||
else if (!(options & SSL_NO_DEFAULT_KEY))
|
||||
{
|
||||
#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
|
||||
static const /* saves a few bytes and RAM */
|
||||
#include "cert.h"
|
||||
ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT,
|
||||
default_certificate, default_certificate_len, NULL);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
error:
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
if (ret)
|
||||
{
|
||||
printf("Error: Certificate or key not loaded\n"); TTY_FLUSH();
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enable a subset of openssl compatible functions. We don't aim to be 100%
|
||||
* compatible - just to be able to do basic ports etc.
|
||||
*
|
||||
* Only really tested on mini_httpd, so I'm not too sure how extensive this
|
||||
* port is.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef CONFIG_OPENSSL_COMPATIBLE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "os_port.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#define OPENSSL_CTX_ATTR ((OPENSSL_CTX *)ssl_ctx->bonus_attr)
|
||||
|
||||
static char *key_password = NULL;
|
||||
|
||||
void *SSLv23_server_method(void) { return NULL; }
|
||||
void *SSLv3_server_method(void) { return NULL; }
|
||||
void *TLSv1_server_method(void) { return NULL; }
|
||||
void *SSLv23_client_method(void) { return NULL; }
|
||||
void *SSLv3_client_method(void) { return NULL; }
|
||||
void *TLSv1_client_method(void) { return NULL; }
|
||||
|
||||
typedef void * (*ssl_func_type_t)(void);
|
||||
typedef void * (*bio_func_type_t)(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ssl_func_type_t ssl_func_type;
|
||||
} OPENSSL_CTX;
|
||||
|
||||
SSL_CTX * SSL_CTX_new(ssl_func_type_t meth)
|
||||
{
|
||||
SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5);
|
||||
ssl_ctx->bonus_attr = malloc(sizeof(OPENSSL_CTX));
|
||||
OPENSSL_CTX_ATTR->ssl_func_type = meth;
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
void SSL_CTX_free(SSL_CTX * ssl_ctx)
|
||||
{
|
||||
free(ssl_ctx->bonus_attr);
|
||||
ssl_ctx_free(ssl_ctx);
|
||||
}
|
||||
|
||||
SSL * SSL_new(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
SSL *ssl;
|
||||
ssl_func_type_t ssl_func_type;
|
||||
|
||||
ssl = ssl_new(ssl_ctx, -1); /* fd is set later */
|
||||
ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type;
|
||||
|
||||
#ifdef CONFIG_SSL_ENABLE_CLIENT
|
||||
if (ssl_func_type == SSLv23_client_method ||
|
||||
ssl_func_type == SSLv3_client_method ||
|
||||
ssl_func_type == TLSv1_client_method)
|
||||
{
|
||||
SET_SSL_FLAG(SSL_IS_CLIENT);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ssl->next_state = HS_CLIENT_HELLO;
|
||||
}
|
||||
|
||||
return ssl;
|
||||
}
|
||||
|
||||
int SSL_set_fd(SSL *s, int fd)
|
||||
{
|
||||
s->client_fd = fd;
|
||||
return 1; /* always succeeds */
|
||||
}
|
||||
|
||||
int SSL_accept(SSL *ssl)
|
||||
{
|
||||
while (ssl_read(ssl, NULL) == SSL_OK)
|
||||
{
|
||||
if (ssl->next_state == HS_CLIENT_HELLO)
|
||||
return 1; /* we're done */
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_ENABLE_CLIENT
|
||||
int SSL_connect(SSL *ssl)
|
||||
{
|
||||
return do_client_connect(ssl) == SSL_OK ? 1 : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SSL_free(SSL *ssl)
|
||||
{
|
||||
ssl_free(ssl);
|
||||
}
|
||||
|
||||
int SSL_read(SSL *ssl, void *buf, int num)
|
||||
{
|
||||
uint8_t *read_buf;
|
||||
int ret;
|
||||
|
||||
while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
|
||||
|
||||
if (ret > SSL_OK)
|
||||
{
|
||||
memcpy(buf, read_buf, ret > num ? num : ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SSL_write(SSL *ssl, const void *buf, int num)
|
||||
{
|
||||
return ssl_write(ssl, buf, num);
|
||||
}
|
||||
|
||||
int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type)
|
||||
{
|
||||
return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
|
||||
}
|
||||
|
||||
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type)
|
||||
{
|
||||
return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK);
|
||||
}
|
||||
|
||||
int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d)
|
||||
{
|
||||
return (ssl_obj_memory_load(ssl_ctx,
|
||||
SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK);
|
||||
}
|
||||
|
||||
int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
|
||||
unsigned int sid_ctx_len)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file)
|
||||
{
|
||||
return (ssl_obj_load(ssl_ctx,
|
||||
SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
|
||||
}
|
||||
|
||||
int SSL_shutdown(SSL *ssl)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*** get/set session ***/
|
||||
SSL_SESSION *SSL_get1_session(SSL *ssl)
|
||||
{
|
||||
return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */
|
||||
}
|
||||
|
||||
int SSL_set_session(SSL *ssl, SSL_SESSION *session)
|
||||
{
|
||||
memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SSL_SESSION_free(SSL_SESSION *session) { }
|
||||
/*** end get/set session ***/
|
||||
|
||||
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
|
||||
int (*verify_callback)(int, void *)) { }
|
||||
|
||||
void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { }
|
||||
|
||||
int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
|
||||
const char *CApath)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *SSL_load_client_CA_file(const char *file)
|
||||
{
|
||||
return (void *)file;
|
||||
}
|
||||
|
||||
void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file)
|
||||
{
|
||||
|
||||
ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL);
|
||||
}
|
||||
|
||||
void SSLv23_method(void) { }
|
||||
|
||||
void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { }
|
||||
|
||||
void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u)
|
||||
{
|
||||
key_password = (char *)u;
|
||||
}
|
||||
|
||||
int SSL_peek(SSL *ssl, void *buf, int num)
|
||||
{
|
||||
memcpy(buf, ssl->bm_data, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { }
|
||||
|
||||
long SSL_get_verify_result(const SSL *ssl)
|
||||
{
|
||||
return ssl_handshake_status(ssl);
|
||||
}
|
||||
|
||||
int SSL_state(SSL *ssl)
|
||||
{
|
||||
return 0x03; // ok state
|
||||
}
|
||||
|
||||
/** end of could do better list */
|
||||
|
||||
void *SSL_get_peer_certificate(const SSL *ssl)
|
||||
{
|
||||
return &ssl->ssl_ctx->certs[0];
|
||||
}
|
||||
|
||||
int SSL_clear(SSL *ssl)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int SSL_CTX_check_private_key(const SSL_CTX *ctx)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_CTX_set_cipher_list(SSL *s, const char *str)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_get_error(const SSL *ssl, int ret)
|
||||
{
|
||||
ssl_display_error(ret);
|
||||
return 0; /* TODO: return proper return code */
|
||||
}
|
||||
|
||||
void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {}
|
||||
int SSL_library_init(void ) { return 1; }
|
||||
void SSL_load_error_strings(void ) {}
|
||||
void ERR_print_errors_fp(FILE *fp) {}
|
||||
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) {
|
||||
return CONFIG_SSL_EXPIRY_TIME*3600; }
|
||||
long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) {
|
||||
return SSL_CTX_get_timeout(ssl_ctx); }
|
||||
#endif
|
||||
void BIO_printf(FILE *f, const char *format, ...)
|
||||
{
|
||||
va_list(ap);
|
||||
va_start(ap, format);
|
||||
vfprintf(f, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void* BIO_s_null(void) { return NULL; }
|
||||
FILE *BIO_new(bio_func_type_t func)
|
||||
{
|
||||
if (func == BIO_s_null)
|
||||
return fopen("/dev/null", "r");
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; }
|
||||
int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; }
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file os_port.c
|
||||
*
|
||||
* OS specific functions.
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include "os_port.h"
|
||||
#include <stdio.h>
|
||||
#include "sockets.h"
|
||||
|
||||
static int memory_buf[400];
|
||||
static char enable = 1;
|
||||
static int nb_entries = 0;
|
||||
static int nb_alloc = 0;
|
||||
|
||||
void disable_memory_buf(void)
|
||||
{
|
||||
enable = 0;
|
||||
}
|
||||
void enable_memory_buf(void)
|
||||
{
|
||||
enable = 1;
|
||||
}
|
||||
void init_memory_buf(void)
|
||||
{
|
||||
for(int i = 0; i < 400; i += 2)
|
||||
{
|
||||
memory_buf[i] = -1;
|
||||
memory_buf[i+1] = 0;
|
||||
}
|
||||
}
|
||||
void print_buf_stats(void)
|
||||
{
|
||||
if(enable)
|
||||
{
|
||||
int used = 0;
|
||||
for(int i = 1; i < 400; i += 2)
|
||||
used += memory_buf[i];
|
||||
printf("%d\n", used);
|
||||
}
|
||||
}
|
||||
|
||||
void print_all_buf_stats(void)
|
||||
{
|
||||
int used = 0;
|
||||
for(int i = 1; i < 400; i += 2)
|
||||
used += memory_buf[i];
|
||||
printf("used: %d bytes\n", used);
|
||||
|
||||
for(int i = 0; i < 400; i += 2)
|
||||
if(memory_buf[i] != -1)
|
||||
printf("ptr:%X, size:%d\n", memory_buf[i], memory_buf[i+1]);
|
||||
}
|
||||
|
||||
static void add_entry(void *x, size_t s, const char* f, const int l)
|
||||
{
|
||||
nb_entries++;
|
||||
for(int i = 0; i < 400; i += 2)
|
||||
{
|
||||
if(memory_buf[i] == -1)
|
||||
{
|
||||
if(enable)
|
||||
printf("new ptr:%X, size:%d at %s:%d\n", x, s, f, l);
|
||||
memory_buf[i] = (int)(x);
|
||||
memory_buf[i+1] = s;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(enable)
|
||||
printf("No space left in buffer\n");
|
||||
}
|
||||
|
||||
static void remove_entry(void *x, const char* f, const int l)
|
||||
{
|
||||
nb_entries--;
|
||||
for(int i = 0; i < 400; i += 2)
|
||||
{
|
||||
if(memory_buf[i] == (int)(x))
|
||||
{
|
||||
if(enable)
|
||||
printf("free ptr:%X, size:%d at %s:%d\n", memory_buf[i], memory_buf[i+1], f, l);
|
||||
memory_buf[i] = -1;
|
||||
memory_buf[i+1] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(enable)
|
||||
printf("not found\n");
|
||||
}
|
||||
|
||||
#ifdef MBED
|
||||
/**
|
||||
* gettimeofday() not in mbed
|
||||
*/
|
||||
EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
|
||||
{
|
||||
t->tv_sec = time(NULL);
|
||||
t->tv_usec = 0; /* 1sec precision only */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
/**
|
||||
* gettimeofday() not in Win32
|
||||
*/
|
||||
EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
|
||||
{
|
||||
#if defined(_WIN32_WCE)
|
||||
t->tv_sec = time(NULL);
|
||||
t->tv_usec = 0; /* 1sec precision only */
|
||||
#else
|
||||
struct _timeb timebuffer;
|
||||
_ftime(&timebuffer);
|
||||
t->tv_sec = (long)timebuffer.time;
|
||||
t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* strcasecmp() not in Win32
|
||||
*/
|
||||
EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2)
|
||||
{
|
||||
while (tolower(*s1) == tolower(*s2++))
|
||||
{
|
||||
if (*s1++ == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1);
|
||||
}
|
||||
|
||||
|
||||
EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size)
|
||||
{
|
||||
HKEY hKey;
|
||||
unsigned long datatype;
|
||||
unsigned long bufferlength = buf_size;
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
|
||||
0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
|
||||
return -1;
|
||||
|
||||
RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength);
|
||||
RegCloseKey(hKey);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef calloc
|
||||
#undef free
|
||||
|
||||
static const char * out_of_mem_str = "out of memory";
|
||||
static const char * file_open_str = "Could not open file \"%s\"";
|
||||
|
||||
/*
|
||||
* Some functions that call display some error trace and then call abort().
|
||||
* This just makes life much easier on embedded systems, since we're
|
||||
* suffering major trauma...
|
||||
*/
|
||||
EXP_FUNC void * STDCALL ax_malloc(size_t s, const char* f, const int l)
|
||||
{
|
||||
if(enable)
|
||||
printf("malloc\t");
|
||||
|
||||
void *x;
|
||||
|
||||
if ((x = malloc(s)) == NULL)
|
||||
exit_now(out_of_mem_str);
|
||||
add_entry(x,s, f, l);
|
||||
print_buf_stats();
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l)
|
||||
{
|
||||
if(enable)
|
||||
printf("realloc\t");
|
||||
|
||||
void *x;
|
||||
|
||||
if ((x = realloc(y, s)) == NULL)
|
||||
exit_now(out_of_mem_str);
|
||||
remove_entry(y, f, l);
|
||||
add_entry(x,s, f, l);
|
||||
print_buf_stats();
|
||||
return x;
|
||||
}
|
||||
|
||||
EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l)
|
||||
{
|
||||
if(enable)
|
||||
printf("calloc\t");
|
||||
void *x;
|
||||
|
||||
if ((x = calloc(n, s)) == NULL) {
|
||||
exit_now(out_of_mem_str);
|
||||
}
|
||||
|
||||
add_entry(x,n*s, f, l);
|
||||
print_buf_stats();
|
||||
return x;
|
||||
}
|
||||
|
||||
EXP_FUNC void STDCALL ax_free(void *y, const char* f, const int l)
|
||||
{
|
||||
if(enable)
|
||||
printf("free\t");
|
||||
|
||||
remove_entry(y, f, l);
|
||||
print_buf_stats();
|
||||
free(y);
|
||||
}
|
||||
/*
|
||||
EXP_FUNC int STDCALL ax_open(const char *pathname, int flags)
|
||||
{
|
||||
int x;
|
||||
|
||||
if ((x = open(pathname, flags)) < 0)
|
||||
exit_now(file_open_str, pathname);
|
||||
|
||||
return x;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a call which will deliberately exit an application, but will
|
||||
* display some information before dying.
|
||||
*/
|
||||
void exit_now(const char *format, ...)
|
||||
{
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, format);
|
||||
vfprintf(stderr, format, argp);
|
||||
va_end(argp);
|
||||
abort();
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#ifndef HEADER_OS_PORT_H
|
||||
#define HEADER_OS_PORT_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
//#include <Thread.h>
|
||||
#define SSL_CTX_MUTEX_TYPE //Mutex
|
||||
#define SSL_CTX_MUTEX_INIT(A) //pthread_mutex_init(&A, NULL)
|
||||
#define SSL_CTX_MUTEX_DESTROY(A) //pthread_mutex_destroy(&A)
|
||||
#define SSL_CTX_LOCK(A) //pthread_mutex_lock(&A)
|
||||
#define SSL_CTX_UNLOCK(A) //pthread_mutex_unlock(&A)
|
||||
|
||||
#define malloc(A) ax_malloc(A, __FILE__, __LINE__)
|
||||
#ifndef realloc
|
||||
#define realloc(A,B) ax_realloc(A,B, __FILE__, __LINE__)
|
||||
#endif
|
||||
#define calloc(A,B) ax_calloc(A,B, __FILE__, __LINE__)
|
||||
#define free(A) ax_free(A, __FILE__, __LINE__)
|
||||
|
||||
#define STDCALL
|
||||
#define EXP_FUNC
|
||||
void init_memory_buf(void);
|
||||
void disable_memory_buf(void);
|
||||
void enable_memory_buf(void);
|
||||
void print_buf_stats(void);
|
||||
void print_all_buf_stats(void);
|
||||
|
||||
EXP_FUNC void * STDCALL ax_malloc(size_t s, const char* f, const int l);
|
||||
EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l);
|
||||
EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l);
|
||||
EXP_FUNC void STDCALL ax_free(void *y, const char* f, const int l);
|
||||
|
||||
//EXP_FUNC int STDCALL ax_open(const char *pathname, int flags);
|
||||
|
||||
#define SOCKET_READ(A,B,C) lwip_read(A,B,C)
|
||||
#define SOCKET_WRITE(A,B,C) lwip_write(A,B,C)
|
||||
#define SOCKET_CLOSE(A) closesocket(A)
|
||||
#define TTY_FLUSH()
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file os_port.h
|
||||
*
|
||||
* Some stuff to minimise the differences between windows and linux/unix
|
||||
*/
|
||||
|
||||
#ifndef HEADER_OS_PORT_H
|
||||
#define HEADER_OS_PORT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "os_int.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#define STDCALL __stdcall
|
||||
#define EXP_FUNC __declspec(dllexport)
|
||||
#else
|
||||
#define STDCALL
|
||||
#define EXP_FUNC
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
#undef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/* Windows CE stuff */
|
||||
#if defined(_WIN32_WCE)
|
||||
#include <basetsd.h>
|
||||
#define abort() exit(1)
|
||||
#else
|
||||
#include <io.h>
|
||||
#include <process.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <fcntl.h>
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
#include <winsock.h>
|
||||
#include <direct.h>
|
||||
#undef getpid
|
||||
#undef open
|
||||
#undef close
|
||||
#undef sleep
|
||||
#undef gettimeofday
|
||||
#undef dup2
|
||||
#undef unlink
|
||||
|
||||
#define SOCKET_READ(A,B,C) recv(A,B,C,0)
|
||||
#define SOCKET_WRITE(A,B,C) send(A,B,C,0)
|
||||
#define SOCKET_CLOSE(A) closesocket(A)
|
||||
#define srandom(A) srand(A)
|
||||
#define random() rand()
|
||||
#define getpid() _getpid()
|
||||
#define snprintf _snprintf
|
||||
#define open(A,B) _open(A,B)
|
||||
#define dup2(A,B) _dup2(A,B)
|
||||
#define unlink(A) _unlink(A)
|
||||
#define close(A) _close(A)
|
||||
#define read(A,B,C) _read(A,B,C)
|
||||
#define write(A,B,C) _write(A,B,C)
|
||||
#define sleep(A) Sleep(A*1000)
|
||||
#define usleep(A) Sleep(A/1000)
|
||||
#define strdup(A) _strdup(A)
|
||||
#define chroot(A) _chdir(A)
|
||||
#define chdir(A) _chdir(A)
|
||||
#define alloca(A) _alloca(A)
|
||||
|
||||
|
||||
#ifndef lseek
|
||||
#define lseek(A,B,C) _lseek(A,B,C)
|
||||
|
||||
#endif
|
||||
|
||||
/* This fix gets around a problem where a win32 application on a cygwin xterm
|
||||
doesn't display regular output (until a certain buffer limit) - but it works
|
||||
fine under a normal DOS window. This is a hack to get around the issue -
|
||||
see http://www.khngai.com/emacs/tty.php */
|
||||
#define TTY_FLUSH() if (!_isatty(_fileno(stdout))) fflush(stdout);
|
||||
|
||||
/*
|
||||
* automatically build some library dependencies.
|
||||
*/
|
||||
#pragma comment(lib, "WS2_32.lib")
|
||||
#pragma comment(lib, "AdvAPI32.lib")
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone);
|
||||
EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2);
|
||||
EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size);
|
||||
|
||||
#else /* Not Win32 */
|
||||
|
||||
//#include <unistd.h>
|
||||
//#include <pwd.h>
|
||||
//#include <netdb.h>
|
||||
//#include <dirent.h>
|
||||
//#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
//#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <socket.h>
|
||||
//#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <inet.h>
|
||||
|
||||
#define SOCKET_READ(A,B,C) read(A,B,C)
|
||||
#define SOCKET_WRITE(A,B,C) write(A,B,C)
|
||||
#define SOCKET_CLOSE(A) if (A >= 0) close(A)
|
||||
#define TTY_FLUSH()
|
||||
|
||||
#endif /* Not Win32 */
|
||||
|
||||
/* some functions to mutate the way these work */
|
||||
#define malloc(A) ax_malloc(A)
|
||||
#ifndef realloc
|
||||
#define realloc(A,B) ax_realloc(A,B)
|
||||
#endif
|
||||
#define calloc(A,B) ax_calloc(A,B)
|
||||
|
||||
EXP_FUNC void * STDCALL ax_malloc(size_t s);
|
||||
EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s);
|
||||
EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s);
|
||||
EXP_FUNC int STDCALL ax_open(const char *pathname, int flags);
|
||||
|
||||
#ifdef CONFIG_PLATFORM_LINUX
|
||||
void exit_now(const char *format, ...) __attribute((noreturn));
|
||||
#else
|
||||
void exit_now(const char *format, ...);
|
||||
#endif
|
||||
|
||||
/* Mutexing definitions */
|
||||
#if defined(CONFIG_SSL_CTX_MUTEXING)
|
||||
#if defined(WIN32)
|
||||
#define SSL_CTX_MUTEX_TYPE HANDLE
|
||||
#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0)
|
||||
#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A)
|
||||
#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE)
|
||||
#define SSL_CTX_UNLOCK(A) ReleaseMutex(A)
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#define SSL_CTX_MUTEX_TYPE pthread_mutex_t
|
||||
#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL)
|
||||
#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A)
|
||||
#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A)
|
||||
#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A)
|
||||
#endif
|
||||
#else /* no mutexing */
|
||||
#define SSL_CTX_MUTEX_INIT(A)
|
||||
#define SSL_CTX_MUTEX_DESTROY(A)
|
||||
#define SSL_CTX_LOCK(A)
|
||||
#define SSL_CTX_UNLOCK(A)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,483 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Process PKCS#8/PKCS#12 keys.
|
||||
*
|
||||
* The decoding of a PKCS#12 key is fairly specific - this code was tested on a
|
||||
* key generated with:
|
||||
*
|
||||
* openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
|
||||
* -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128
|
||||
* -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
|
||||
*
|
||||
* or with a certificate chain:
|
||||
*
|
||||
* openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
|
||||
* -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
|
||||
* PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
|
||||
*
|
||||
* Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
|
||||
* private/public keys/certs have to use RSA encryption. Both the integrity
|
||||
* and privacy passwords are the same.
|
||||
*
|
||||
* The PKCS#8 files were generated with something like:
|
||||
*
|
||||
* PEM format:
|
||||
* openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
|
||||
* PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
|
||||
*
|
||||
* DER format:
|
||||
* openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
|
||||
* -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "os_port.h"
|
||||
#include "ssl.h"
|
||||
|
||||
/* all commented out if not used */
|
||||
#ifdef CONFIG_SSL_USE_PKCS12
|
||||
|
||||
#define BLOCK_SIZE 64
|
||||
#define PKCS12_KEY_ID 1
|
||||
#define PKCS12_IV_ID 2
|
||||
#define PKCS12_MAC_ID 3
|
||||
|
||||
static char *make_uni_pass(const char *password, int *uni_pass_len);
|
||||
static int p8_decrypt(const char *uni_pass, int uni_pass_len,
|
||||
const uint8_t *salt, int iter,
|
||||
uint8_t *priv_key, int priv_key_len, int id);
|
||||
static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);
|
||||
static int get_pbe_params(uint8_t *buf, int *offset,
|
||||
const uint8_t **salt, int *iterations);
|
||||
|
||||
/*
|
||||
* Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
|
||||
*/
|
||||
int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
|
||||
{
|
||||
uint8_t *buf = ssl_obj->buf;
|
||||
int len, offset = 0;
|
||||
int iterations;
|
||||
int ret = SSL_NOT_OK;
|
||||
uint8_t *version = NULL;
|
||||
const uint8_t *salt;
|
||||
uint8_t *priv_key;
|
||||
int uni_pass_len;
|
||||
char *uni_pass = make_uni_pass(password, &uni_pass_len);
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: Invalid p8 ASN.1 file\n");
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* unencrypted key? */
|
||||
if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
|
||||
{
|
||||
ret = p8_add_key(ssl_ctx, buf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)
|
||||
goto error;
|
||||
|
||||
if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
|
||||
goto error;
|
||||
|
||||
priv_key = &buf[offset];
|
||||
|
||||
p8_decrypt(uni_pass, uni_pass_len, salt,
|
||||
iterations, priv_key, len, PKCS12_KEY_ID);
|
||||
ret = p8_add_key(ssl_ctx, priv_key);
|
||||
|
||||
error:
|
||||
free(version);
|
||||
free(uni_pass);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the unencrypted pkcs8 and turn it into a private key
|
||||
*/
|
||||
static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)
|
||||
{
|
||||
uint8_t *buf = priv_key;
|
||||
int len, offset = 0;
|
||||
int ret = SSL_NOT_OK;
|
||||
|
||||
/* Skip the preamble and go straight to the private key.
|
||||
We only support rsaEncryption (1.2.840.113549.1.1.1) */
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
|
||||
asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
|
||||
goto error;
|
||||
|
||||
ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the unicode password
|
||||
*/
|
||||
static char *make_uni_pass(const char *password, int *uni_pass_len)
|
||||
{
|
||||
int pass_len = 0, i;
|
||||
char *uni_pass;
|
||||
|
||||
if (password == NULL)
|
||||
{
|
||||
password = "";
|
||||
}
|
||||
|
||||
uni_pass = (char *)malloc((strlen(password)+1)*2);
|
||||
|
||||
/* modify the password into a unicode version */
|
||||
for (i = 0; i < (int)strlen(password); i++)
|
||||
{
|
||||
uni_pass[pass_len++] = 0;
|
||||
uni_pass[pass_len++] = password[i];
|
||||
}
|
||||
|
||||
uni_pass[pass_len++] = 0; /* null terminate */
|
||||
uni_pass[pass_len++] = 0;
|
||||
*uni_pass_len = pass_len;
|
||||
return uni_pass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt a pkcs8 block.
|
||||
*/
|
||||
static int p8_decrypt(const char *uni_pass, int uni_pass_len,
|
||||
const uint8_t *salt, int iter,
|
||||
uint8_t *priv_key, int priv_key_len, int id)
|
||||
{
|
||||
uint8_t p[BLOCK_SIZE*2];
|
||||
uint8_t d[BLOCK_SIZE];
|
||||
uint8_t Ai[SHA1_SIZE];
|
||||
SHA1_CTX sha_ctx;
|
||||
RC4_CTX rc4_ctx;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BLOCK_SIZE; i++)
|
||||
{
|
||||
p[i] = salt[i % SALT_SIZE];
|
||||
p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];
|
||||
d[i] = id;
|
||||
}
|
||||
|
||||
/* get the key - no IV since we are using RC4 */
|
||||
SHA1_Init(&sha_ctx);
|
||||
SHA1_Update(&sha_ctx, d, sizeof(d));
|
||||
SHA1_Update(&sha_ctx, p, sizeof(p));
|
||||
SHA1_Final(Ai, &sha_ctx);
|
||||
|
||||
for (i = 1; i < iter; i++)
|
||||
{
|
||||
SHA1_Init(&sha_ctx);
|
||||
SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);
|
||||
SHA1_Final(Ai, &sha_ctx);
|
||||
}
|
||||
|
||||
/* do the decryption */
|
||||
if (id == PKCS12_KEY_ID)
|
||||
{
|
||||
RC4_setup(&rc4_ctx, Ai, 16);
|
||||
RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);
|
||||
}
|
||||
else /* MAC */
|
||||
memcpy(priv_key, Ai, SHA1_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
|
||||
* and keys.
|
||||
*/
|
||||
int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
|
||||
{
|
||||
uint8_t *buf = ssl_obj->buf;
|
||||
int len, iterations, auth_safes_start,
|
||||
auth_safes_end, auth_safes_len, key_offset, offset = 0;
|
||||
int all_certs = 0;
|
||||
uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;
|
||||
uint8_t key[SHA1_SIZE];
|
||||
uint8_t mac[SHA1_SIZE];
|
||||
const uint8_t *salt;
|
||||
int uni_pass_len, ret = SSL_OK;
|
||||
char *uni_pass = make_uni_pass(password, &uni_pass_len);
|
||||
static const uint8_t pkcs_data[] = /* pkc7 data */
|
||||
{ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };
|
||||
static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */
|
||||
{ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };
|
||||
static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */
|
||||
{ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: Invalid p12 ASN.1 file\n");
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_VERSION;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* remove all the boring pcks7 bits */
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
|
||||
len != sizeof(pkcs_data) ||
|
||||
memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)
|
||||
goto error;
|
||||
|
||||
/* work out the MAC start/end points (done on AuthSafes) */
|
||||
auth_safes_start = offset;
|
||||
auth_safes_end = offset;
|
||||
if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)
|
||||
goto error;
|
||||
|
||||
auth_safes_len = auth_safes_end - auth_safes_start;
|
||||
auth_safes = malloc(auth_safes_len);
|
||||
|
||||
memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
|
||||
(len != sizeof(pkcs_encrypted) ||
|
||||
memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
|
||||
len != sizeof(pkcs_data) ||
|
||||
memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
/* work out the salt for the certificate */
|
||||
if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)
|
||||
goto error;
|
||||
|
||||
/* decrypt the certificate */
|
||||
cert = &buf[offset];
|
||||
if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
|
||||
len, PKCS12_KEY_ID)) < 0)
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
/* load the certificate */
|
||||
key_offset = 0;
|
||||
all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);
|
||||
|
||||
/* keep going until all certs are loaded */
|
||||
while (key_offset < all_certs)
|
||||
{
|
||||
int cert_offset = key_offset;
|
||||
|
||||
if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
|
||||
asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
|
||||
asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
|
||||
asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
|
||||
(len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)
|
||||
goto error;
|
||||
|
||||
if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)
|
||||
goto error;
|
||||
|
||||
key_offset = cert_offset;
|
||||
}
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
|
||||
len != sizeof(pkcs_data) ||
|
||||
memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
|
||||
(len != sizeof(pkcs8_key_bag)) ||
|
||||
memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
/* work out the salt for the private key */
|
||||
if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
|
||||
goto error;
|
||||
|
||||
/* decrypt the private key */
|
||||
cert = &buf[offset];
|
||||
if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
|
||||
len, PKCS12_KEY_ID)) < 0)
|
||||
goto error;
|
||||
|
||||
offset += len;
|
||||
|
||||
/* load the private key */
|
||||
if ((ret = p8_add_key(ssl_ctx, cert)) < 0)
|
||||
goto error;
|
||||
|
||||
/* miss out on friendly name, local key id etc */
|
||||
if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)
|
||||
goto error;
|
||||
|
||||
/* work out the MAC */
|
||||
if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||
|
||||
len != SHA1_SIZE)
|
||||
goto error;
|
||||
|
||||
orig_mac = &buf[offset];
|
||||
offset += len;
|
||||
|
||||
/* get the salt */
|
||||
if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)
|
||||
goto error;
|
||||
|
||||
salt = &buf[offset];
|
||||
|
||||
/* work out what the mac should be */
|
||||
if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations,
|
||||
key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)
|
||||
goto error;
|
||||
|
||||
hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);
|
||||
|
||||
if (memcmp(mac, orig_mac, SHA1_SIZE))
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_HMAC;
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
free(version);
|
||||
free(uni_pass);
|
||||
free(auth_safes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the salt/iteration details from a PBE block.
|
||||
*/
|
||||
static int get_pbe_params(uint8_t *buf, int *offset,
|
||||
const uint8_t **salt, int *iterations)
|
||||
{
|
||||
static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */
|
||||
{ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };
|
||||
|
||||
int i, len;
|
||||
uint8_t *iter = NULL;
|
||||
int error_code = SSL_ERROR_NOT_SUPPORTED;
|
||||
|
||||
/* Get the PBE type */
|
||||
if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
|
||||
goto error;
|
||||
|
||||
/* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1)
|
||||
which is the only algorithm we support */
|
||||
if (len != sizeof(pbeSH1RC4) ||
|
||||
memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n");
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
*offset += len;
|
||||
|
||||
if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
|
||||
(len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 ||
|
||||
len != 8)
|
||||
goto error;
|
||||
|
||||
*salt = &buf[*offset];
|
||||
*offset += len;
|
||||
|
||||
if ((len = asn1_get_int(buf, offset, &iter)) < 0)
|
||||
goto error;
|
||||
|
||||
*iterations = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
(*iterations) <<= 8;
|
||||
(*iterations) += iter[i];
|
||||
}
|
||||
|
||||
free(iter);
|
||||
error_code = SSL_OK; /* got here - we are ok */
|
||||
|
||||
error:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,54 +0,0 @@
|
|||
unsigned char default_private_key[] = {
|
||||
0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xcd,
|
||||
0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, 0xd4, 0x13, 0x30, 0x0e,
|
||||
0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, 0x51, 0x09, 0x9d, 0x29,
|
||||
0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, 0x80, 0xa1, 0x71, 0xdf,
|
||||
0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, 0x90, 0x0a, 0xf9, 0xb7,
|
||||
0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, 0x57, 0x41, 0x86, 0x60,
|
||||
0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, 0x1b, 0xf6, 0xa2, 0x84,
|
||||
0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, 0x91, 0xf8, 0x61, 0x04,
|
||||
0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, 0xcc, 0x31, 0x01, 0x14,
|
||||
0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, 0xd6, 0xc6, 0xc4, 0xbe,
|
||||
0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, 0x7a, 0x86, 0x0e, 0x91,
|
||||
0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01,
|
||||
0x02, 0x81, 0x81, 0x00, 0x95, 0xaa, 0x6e, 0x11, 0xf5, 0x6a, 0x8b, 0xa2,
|
||||
0xc6, 0x48, 0xc6, 0x7c, 0x37, 0x6b, 0x1f, 0x55, 0x10, 0x76, 0x26, 0x24,
|
||||
0xc3, 0xf2, 0x5c, 0x5a, 0xdd, 0x2e, 0xf3, 0xa4, 0x1e, 0xbc, 0x7b, 0x1c,
|
||||
0x80, 0x10, 0x85, 0xbc, 0xd8, 0x45, 0x3c, 0xb8, 0xb2, 0x06, 0x53, 0xb5,
|
||||
0xd5, 0x7a, 0xe7, 0x0e, 0x92, 0xe6, 0x42, 0xc2, 0xe2, 0x2a, 0xd5, 0xd1,
|
||||
0x03, 0x9f, 0x6f, 0x53, 0x74, 0x68, 0x72, 0x8e, 0xbf, 0x03, 0xbb, 0xab,
|
||||
0xbd, 0xa1, 0xf9, 0x81, 0x7d, 0x12, 0xd4, 0x9d, 0xb6, 0xae, 0x4c, 0xad,
|
||||
0xca, 0xa8, 0xc9, 0x80, 0x8d, 0x0d, 0xd5, 0xd0, 0xa1, 0xbf, 0xec, 0x60,
|
||||
0x48, 0x49, 0xed, 0x97, 0x0f, 0x5e, 0xed, 0xfc, 0x39, 0x15, 0x96, 0x9e,
|
||||
0x5d, 0xe2, 0xb4, 0x5d, 0x2e, 0x04, 0xdc, 0x08, 0xa2, 0x65, 0x29, 0x2d,
|
||||
0x37, 0xfb, 0x62, 0x90, 0x1b, 0x7b, 0xe5, 0x3a, 0x58, 0x05, 0x55, 0xc1,
|
||||
0x02, 0x41, 0x00, 0xfc, 0x69, 0x28, 0xc9, 0xa8, 0xc4, 0x5c, 0xe3, 0xd0,
|
||||
0x5e, 0xaa, 0xda, 0xde, 0x87, 0x74, 0xdb, 0xcb, 0x40, 0x78, 0x8e, 0x1d,
|
||||
0x12, 0x96, 0x16, 0x61, 0x3f, 0xb3, 0x3e, 0xa3, 0x0d, 0xdc, 0x49, 0xa5,
|
||||
0x25, 0x87, 0xc5, 0x97, 0x85, 0x9d, 0xbb, 0xb4, 0xf0, 0x44, 0xfd, 0x6c,
|
||||
0xe8, 0xd2, 0x8c, 0xec, 0x33, 0x81, 0x46, 0x1e, 0x10, 0x12, 0x33, 0x16,
|
||||
0x95, 0x00, 0x4f, 0x75, 0xb4, 0xe5, 0x79, 0x02, 0x41, 0x00, 0xd0, 0xeb,
|
||||
0x65, 0x07, 0x10, 0x3b, 0xd9, 0x03, 0xeb, 0xdc, 0x6f, 0x4b, 0x8f, 0xc3,
|
||||
0x87, 0xce, 0x76, 0xd6, 0xc5, 0x14, 0x21, 0x4e, 0xe7, 0x4f, 0x1b, 0xe8,
|
||||
0x05, 0xf8, 0x84, 0x1a, 0xe0, 0xc5, 0xd6, 0xe3, 0x08, 0xb3, 0x54, 0x57,
|
||||
0x02, 0x1f, 0xd4, 0xd9, 0xfb, 0xff, 0x40, 0xb1, 0x56, 0x1c, 0x60, 0xf7,
|
||||
0xac, 0x91, 0xf3, 0xd3, 0xc6, 0x7f, 0x84, 0xfd, 0x84, 0x9d, 0xea, 0x26,
|
||||
0xee, 0xc9, 0x02, 0x41, 0x00, 0xa6, 0xcf, 0x1c, 0x6c, 0x81, 0x03, 0x1c,
|
||||
0x5c, 0x56, 0x05, 0x6a, 0x26, 0x70, 0xef, 0xd6, 0x13, 0xb7, 0x74, 0x28,
|
||||
0xf7, 0xca, 0x50, 0xd1, 0x2d, 0x83, 0x21, 0x64, 0xe4, 0xdd, 0x3f, 0x38,
|
||||
0xb8, 0xd6, 0xd2, 0x41, 0xb3, 0x1c, 0x9a, 0xea, 0x0d, 0xf5, 0xda, 0xdf,
|
||||
0xcd, 0x17, 0x9f, 0x9a, 0x1e, 0x15, 0xaf, 0x48, 0x1c, 0xbd, 0x9b, 0x63,
|
||||
0x5b, 0xad, 0xed, 0xd4, 0xa1, 0xae, 0xa9, 0x59, 0x09, 0x02, 0x40, 0x4e,
|
||||
0x08, 0xce, 0xa8, 0x8f, 0xc0, 0xba, 0xf3, 0x83, 0x02, 0xc8, 0x33, 0x62,
|
||||
0x14, 0x77, 0xc2, 0x7f, 0x93, 0x02, 0xf3, 0xdc, 0xe9, 0x1a, 0xee, 0xea,
|
||||
0x8e, 0x84, 0xc4, 0x69, 0x9b, 0x9c, 0x7f, 0x69, 0x1f, 0x4e, 0x1d, 0xa5,
|
||||
0x90, 0x06, 0x44, 0x1b, 0x7d, 0xfc, 0x69, 0x40, 0x21, 0xbc, 0xf7, 0x46,
|
||||
0xa4, 0xdc, 0x39, 0x7b, 0xe8, 0x8b, 0x49, 0x10, 0x44, 0x9d, 0x67, 0x5a,
|
||||
0x91, 0x86, 0x39, 0x02, 0x40, 0x41, 0x2c, 0x4e, 0xfe, 0xd9, 0x90, 0x89,
|
||||
0x00, 0x5c, 0x94, 0x0a, 0x4a, 0x7e, 0x1b, 0x1a, 0x80, 0x06, 0x01, 0x37,
|
||||
0xda, 0x50, 0x61, 0x9d, 0x9c, 0xfe, 0x25, 0x7f, 0xd8, 0xd4, 0xc4, 0x9e,
|
||||
0x81, 0xf2, 0x0c, 0x1e, 0x38, 0x21, 0x1e, 0x90, 0x3f, 0xd4, 0xba, 0x6c,
|
||||
0x53, 0xcb, 0xf0, 0x77, 0x79, 0x9b, 0xf1, 0xfa, 0x3f, 0x81, 0xdc, 0xf3,
|
||||
0x21, 0x02, 0x6d, 0xb7, 0x95, 0xc3, 0x2e, 0xce, 0xd5
|
||||
};
|
||||
unsigned int default_private_key_len = 609;
|
|
@ -1,499 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mainpage axTLS API
|
||||
*
|
||||
* @image html axolotl.jpg
|
||||
*
|
||||
* The axTLS library has features such as:
|
||||
* - The TLSv1 SSL client/server protocol
|
||||
* - No requirement to use any openssl libraries.
|
||||
* - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.
|
||||
* - RSA encryption/decryption with variable sized keys (up to 4096 bits).
|
||||
* - Certificate chaining and peer authentication.
|
||||
* - Session resumption, session renegotiation.
|
||||
* - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.
|
||||
* - Highly configurable compile time options.
|
||||
* - Portable across many platforms (written in ANSI C), and has language
|
||||
* bindings in C, C#, VB.NET, Java, Perl and Lua.
|
||||
* - Partial openssl API compatibility (via a wrapper).
|
||||
* - A very small footprint (around 50-60kB for the library in 'server-only'
|
||||
* mode).
|
||||
* - No dependencies on sockets - can use serial connections for example.
|
||||
* - A very simple API - ~ 20 functions/methods.
|
||||
*
|
||||
* A list of these functions/methods are described below.
|
||||
*
|
||||
* @ref c_api
|
||||
*
|
||||
* @ref bigint_api
|
||||
*
|
||||
* @ref csharp_api
|
||||
*
|
||||
* @ref java_api
|
||||
*/
|
||||
#ifndef HEADER_SSL_H
|
||||
#define HEADER_SSL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/* need to predefine before ssl_lib.h gets to it */
|
||||
#define SSL_SESSION_ID_SIZE 32
|
||||
|
||||
#include "tls1.h"
|
||||
|
||||
/* The optional parameters that can be given to the client/server SSL engine */
|
||||
#define SSL_CLIENT_AUTHENTICATION 0x00010000
|
||||
#define SSL_SERVER_VERIFY_LATER 0x00020000
|
||||
#define SSL_NO_DEFAULT_KEY 0x00040000
|
||||
#define SSL_DISPLAY_STATES 0x00080000
|
||||
#define SSL_DISPLAY_BYTES 0x00100000
|
||||
#define SSL_DISPLAY_CERTS 0x00200000
|
||||
#define SSL_DISPLAY_RSA 0x00400000
|
||||
#define SSL_CONNECT_IN_PARTS 0x00800000
|
||||
|
||||
/* errors that can be generated */
|
||||
#define SSL_OK 0
|
||||
#define SSL_NOT_OK -1
|
||||
#define SSL_ERROR_DEAD -2
|
||||
#define SSL_CLOSE_NOTIFY -3
|
||||
#define SSL_ERROR_CONN_LOST -256
|
||||
#define SSL_ERROR_SOCK_SETUP_FAILURE -258
|
||||
#define SSL_ERROR_INVALID_HANDSHAKE -260
|
||||
#define SSL_ERROR_INVALID_PROT_MSG -261
|
||||
#define SSL_ERROR_INVALID_HMAC -262
|
||||
#define SSL_ERROR_INVALID_VERSION -263
|
||||
#define SSL_ERROR_INVALID_SESSION -265
|
||||
#define SSL_ERROR_NO_CIPHER -266
|
||||
#define SSL_ERROR_BAD_CERTIFICATE -268
|
||||
#define SSL_ERROR_INVALID_KEY -269
|
||||
#define SSL_ERROR_FINISHED_INVALID -271
|
||||
#define SSL_ERROR_NO_CERT_DEFINED -272
|
||||
#define SSL_ERROR_NO_CLIENT_RENOG -273
|
||||
#define SSL_ERROR_NOT_SUPPORTED -274
|
||||
#define SSL_X509_OFFSET -512
|
||||
#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A)
|
||||
|
||||
/* alert types that are recognized */
|
||||
#define SSL_ALERT_TYPE_WARNING 1
|
||||
#define SLL_ALERT_TYPE_FATAL 2
|
||||
|
||||
/* these are all the alerts that are recognized */
|
||||
#define SSL_ALERT_CLOSE_NOTIFY 0
|
||||
#define SSL_ALERT_UNEXPECTED_MESSAGE 10
|
||||
#define SSL_ALERT_BAD_RECORD_MAC 20
|
||||
#define SSL_ALERT_HANDSHAKE_FAILURE 40
|
||||
#define SSL_ALERT_BAD_CERTIFICATE 42
|
||||
#define SSL_ALERT_ILLEGAL_PARAMETER 47
|
||||
#define SSL_ALERT_DECODE_ERROR 50
|
||||
#define SSL_ALERT_DECRYPT_ERROR 51
|
||||
#define SSL_ALERT_INVALID_VERSION 70
|
||||
#define SSL_ALERT_NO_RENEGOTIATION 100
|
||||
|
||||
/* The ciphers that are supported */
|
||||
#define SSL_AES128_SHA 0x2f
|
||||
#define SSL_AES256_SHA 0x35
|
||||
#define SSL_RC4_128_SHA 0x05
|
||||
#define SSL_RC4_128_MD5 0x04
|
||||
|
||||
/* build mode ids' */
|
||||
#define SSL_BUILD_SKELETON_MODE 0x01
|
||||
#define SSL_BUILD_SERVER_ONLY 0x02
|
||||
#define SSL_BUILD_ENABLE_VERIFICATION 0x03
|
||||
#define SSL_BUILD_ENABLE_CLIENT 0x04
|
||||
#define SSL_BUILD_FULL_MODE 0x05
|
||||
|
||||
/* offsets to retrieve configuration information */
|
||||
#define SSL_BUILD_MODE 0
|
||||
#define SSL_MAX_CERT_CFG_OFFSET 1
|
||||
#define SSL_MAX_CA_CERT_CFG_OFFSET 2
|
||||
#define SSL_HAS_PEM 3
|
||||
|
||||
/* default session sizes */
|
||||
#define SSL_DEFAULT_SVR_SESS 5
|
||||
#define SSL_DEFAULT_CLNT_SESS 1
|
||||
|
||||
/* X.509/X.520 distinguished name types */
|
||||
#define SSL_X509_CERT_COMMON_NAME 0
|
||||
#define SSL_X509_CERT_ORGANIZATION 1
|
||||
#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2
|
||||
#define SSL_X509_CA_CERT_COMMON_NAME 3
|
||||
#define SSL_X509_CA_CERT_ORGANIZATION 4
|
||||
#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5
|
||||
|
||||
/* SSL object loader types */
|
||||
#define SSL_OBJ_X509_CERT 1
|
||||
#define SSL_OBJ_X509_CACERT 2
|
||||
#define SSL_OBJ_RSA_KEY 3
|
||||
#define SSL_OBJ_PKCS8 4
|
||||
#define SSL_OBJ_PKCS12 5
|
||||
|
||||
/**
|
||||
* @defgroup c_api Standard C API
|
||||
* @brief The standard interface in C.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Establish a new client/server context.
|
||||
*
|
||||
* This function is called before any client/server SSL connections are made.
|
||||
*
|
||||
* Each new connection will use the this context's private key and
|
||||
* certificate chain. If a different certificate chain is required, then a
|
||||
* different context needs to be be used.
|
||||
*
|
||||
* There are two threading models supported - a single thread with one
|
||||
* SSL_CTX can support any number of SSL connections - and multiple threads can
|
||||
* support one SSL_CTX object each (the default). But if a single SSL_CTX
|
||||
* object uses many SSL objects in individual threads, then the
|
||||
* CONFIG_SSL_CTX_MUTEXING option needs to be configured.
|
||||
*
|
||||
* @param options [in] Any particular options. At present the options
|
||||
* supported are:
|
||||
* - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server
|
||||
* authentication fails. The certificate can be authenticated later with a
|
||||
* call to ssl_verify_cert().
|
||||
* - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
|
||||
* i.e. each handshake will include a "certificate request" message from the
|
||||
* server. Only available if verification has been enabled.
|
||||
* - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
|
||||
* during the handshake.
|
||||
* - SSL_DISPLAY_STATES (full mode build only): Display the state changes
|
||||
* during the handshake.
|
||||
* - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
|
||||
* are passed during a handshake.
|
||||
* - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that
|
||||
* are passed during a handshake.
|
||||
* - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of
|
||||
* ssl_client_new().
|
||||
* @param num_sessions [in] The number of sessions to be used for session
|
||||
* caching. If this value is 0, then there is no session caching. This option
|
||||
* is not used in skeleton mode.
|
||||
* @return A client/server context.
|
||||
*/
|
||||
EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(SSL_CTX *ssl_ctx, uint32_t options, int num_sessions);
|
||||
|
||||
/**
|
||||
* @brief Remove a client/server context.
|
||||
*
|
||||
* Frees any used resources used by this context. Each connection will be
|
||||
* sent a "Close Notify" alert (if possible).
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx);
|
||||
|
||||
/**
|
||||
* @brief (server only) Establish a new SSL connection to an SSL client.
|
||||
*
|
||||
* It is up to the application to establish the logical connection (whether it
|
||||
* is a socket, serial connection etc).
|
||||
* @param ssl_ctx [in] The server context.
|
||||
* @param client_fd [in] The client's file descriptor.
|
||||
* @return An SSL object reference.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd);
|
||||
|
||||
/**
|
||||
* @brief (client only) Establish a new SSL connection to an SSL server.
|
||||
*
|
||||
* It is up to the application to establish the initial logical connection
|
||||
* (whether it is a socket, serial connection etc).
|
||||
*
|
||||
* This is a normally a blocking call - it will finish when the handshake is
|
||||
* complete (or has failed). To use in non-blocking mode, set
|
||||
* SSL_CONNECT_IN_PARTS in ssl_ctx_new().
|
||||
* @param ssl_ctx [in] The client context.
|
||||
* @param client_fd [in] The client's file descriptor.
|
||||
* @param session_id [in] A 32 byte session id for session resumption. This
|
||||
* can be null if no session resumption is being used or required. This option
|
||||
* is not used in skeleton mode.
|
||||
* @param sess_id_size The size of the session id (max 32)
|
||||
* @return An SSL object reference. Use ssl_handshake_status() to check
|
||||
* if a handshake succeeded.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_client_new(SSL *ssl, int client_fd, const uint8_t *session_id, uint8_t sess_id_size);
|
||||
|
||||
/**
|
||||
* @brief Free any used resources on this connection.
|
||||
|
||||
* A "Close Notify" message is sent on this connection (if possible). It is up
|
||||
* to the application to close the socket or file descriptor.
|
||||
* @param ssl [in] The ssl object reference.
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_free(SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Read the SSL data stream.
|
||||
* If the socket is non-blocking and data is blocked then SSO_OK will be
|
||||
* returned.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param in_data [out] If the read was successful, a pointer to the read
|
||||
* buffer will be here. Do NOT ever free this memory as this buffer is used in
|
||||
* sucessive calls. If the call was unsuccessful, this value will be null.
|
||||
* @return The number of decrypted bytes:
|
||||
* - if > 0, then the handshaking is complete and we are returning the number
|
||||
* of decrypted bytes.
|
||||
* - SSL_OK if the handshaking stage is successful (but not yet complete).
|
||||
* - < 0 if an error.
|
||||
* @see ssl.h for the error code list.
|
||||
* @note Use in_data before doing any successive ssl calls.
|
||||
*/
|
||||
//EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data);
|
||||
|
||||
/**
|
||||
* @brief Write to the SSL data stream.
|
||||
* if the socket is non-blocking and data is blocked then a check is made
|
||||
* to ensure that all data is sent (i.e. blocked mode is forced).
|
||||
* @param ssl [in] An SSL obect reference.
|
||||
* @param out_data [in] The data to be written
|
||||
* @param out_len [in] The number of bytes to be written.
|
||||
* @return The number of bytes sent, or if < 0 if an error.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len);
|
||||
|
||||
/**
|
||||
* @brief Find an ssl object based on a file descriptor.
|
||||
*
|
||||
* Goes through the list of SSL objects maintained in a client/server context
|
||||
* to look for a file descriptor match.
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param client_fd [in] The file descriptor.
|
||||
* @return A reference to the SSL object. Returns null if the object could not
|
||||
* be found.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd);
|
||||
|
||||
/**
|
||||
* @brief Get the session id for a handshake.
|
||||
*
|
||||
* This will be a 32 byte sequence and is available after the first
|
||||
* handshaking messages are sent.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return The session id as a 32 byte sequence.
|
||||
* @note A SSLv23 handshake may have only 16 valid bytes.
|
||||
*/
|
||||
EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Get the session id size for a handshake.
|
||||
*
|
||||
* This will normally be 32 but could be 0 (no session id) or something else.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return The size of the session id.
|
||||
*/
|
||||
EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Return the cipher id (in the SSL form).
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return The cipher id. This will be one of the following:
|
||||
* - SSL_AES128_SHA (0x2f)
|
||||
* - SSL_AES256_SHA (0x35)
|
||||
* - SSL_RC4_128_SHA (0x05)
|
||||
* - SSL_RC4_128_MD5 (0x04)
|
||||
*/
|
||||
EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Return the status of the handshake.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return SSL_OK if the handshake is complete and ok.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Retrieve various parameters about the axTLS engine.
|
||||
* @param offset [in] The configuration offset. It will be one of the following:
|
||||
* - SSL_BUILD_MODE The build mode. This will be one of the following:
|
||||
* - SSL_BUILD_SERVER_ONLY (basic server mode)
|
||||
* - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication)
|
||||
* - SSL_BUILD_ENABLE_CLIENT (client/server capabilties)
|
||||
* - SSL_BUILD_FULL_MODE (client/server with diagnostics)
|
||||
* - SSL_BUILD_SKELETON_MODE (skeleton mode)
|
||||
* - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.
|
||||
* - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.
|
||||
* - SSL_HAS_PEM 1 if supported
|
||||
* @return The value of the requested parameter.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_get_config(int offset);
|
||||
|
||||
/**
|
||||
* @brief Display why the handshake failed.
|
||||
*
|
||||
* This call is only useful in a 'full mode' build. The output is to stdout.
|
||||
* @param error_code [in] An error code.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_display_error(int error_code);
|
||||
|
||||
/**
|
||||
* @brief Authenticate a received certificate.
|
||||
*
|
||||
* This call is usually made by a client after a handshake is complete and the
|
||||
* context is in SSL_SERVER_VERIFY_LATER mode.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Retrieve an X.509 distinguished name component.
|
||||
*
|
||||
* When a handshake is complete and a certificate has been exchanged, then the
|
||||
* details of the remote certificate can be retrieved.
|
||||
*
|
||||
* This will usually be used by a client to check that the server's common
|
||||
* name matches the URL.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param component [in] one of:
|
||||
* - SSL_X509_CERT_COMMON_NAME
|
||||
* - SSL_X509_CERT_ORGANIZATION
|
||||
* - SSL_X509_CERT_ORGANIZATIONAL_NAME
|
||||
* - SSL_X509_CA_CERT_COMMON_NAME
|
||||
* - SSL_X509_CA_CERT_ORGANIZATION
|
||||
* - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
|
||||
* @return The appropriate string (or null if not defined)
|
||||
* @note Verification build mode must be enabled.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a Subject Alternative DNSName
|
||||
*
|
||||
* When a handshake is complete and a certificate has been exchanged, then the
|
||||
* details of the remote certificate can be retrieved.
|
||||
*
|
||||
* This will usually be used by a client to check that the server's DNS
|
||||
* name matches the URL.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param dnsindex [in] The index of the DNS name to retrieve.
|
||||
* @return The appropriate string (or null if not defined)
|
||||
* @note Verification build mode must be enabled.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex);
|
||||
|
||||
/**
|
||||
* @brief Force the client to perform its handshake again.
|
||||
*
|
||||
* For a client this involves sending another "client hello" message.
|
||||
* For the server is means sending a "hello request" message.
|
||||
*
|
||||
* This is a blocking call on the client (until the handshake completes).
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return SSL_OK if renegotiation instantiation was ok
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Process a file that is in binary DER or ASCII PEM format.
|
||||
*
|
||||
* These are temporary objects that are used to load private keys,
|
||||
* certificates etc into memory.
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param obj_type [in] The format of the file. Can be one of:
|
||||
* - SSL_OBJ_X509_CERT (no password required)
|
||||
* - SSL_OBJ_X509_CACERT (no password required)
|
||||
* - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
|
||||
* - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)
|
||||
* - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)
|
||||
*
|
||||
* PEM files are automatically detected (if supported). The object type is
|
||||
* also detected, and so is not relevant for these types of files.
|
||||
* @param filename [in] The location of a file in DER/PEM format.
|
||||
* @param password [in] The password used. Can be null if not required.
|
||||
* @return SSL_OK if all ok
|
||||
* @note Not available in skeleton build mode.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password);
|
||||
|
||||
/**
|
||||
* @brief Process binary data.
|
||||
*
|
||||
* These are temporary objects that are used to load private keys,
|
||||
* certificates etc into memory.
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param obj_type [in] The format of the memory data.
|
||||
* @param data [in] The binary data to be loaded.
|
||||
* @param len [in] The amount of data to be loaded.
|
||||
* @param password [in] The password used. Can be null if not required.
|
||||
* @return SSL_OK if all ok
|
||||
* @see ssl_obj_load for more details on obj_type.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password);
|
||||
|
||||
#ifdef CONFIG_SSL_GENERATE_X509_CERT
|
||||
/**
|
||||
* @brief Create an X.509 certificate.
|
||||
*
|
||||
* This certificate is a self-signed v1 cert with a fixed start/stop validity
|
||||
* times. It is signed with an internal private key in ssl_ctx.
|
||||
*
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param options [in] Not used yet.
|
||||
* @param dn [in] An array of distinguished name strings. The array is defined
|
||||
* by:
|
||||
* - SSL_X509_CERT_COMMON_NAME (0)
|
||||
* - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the
|
||||
* hostname will be used.
|
||||
* - SSL_X509_CERT_ORGANIZATION (1)
|
||||
* - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME
|
||||
* will be used.
|
||||
* - SSL_X509_CERT_ORGANIZATIONAL_NAME (2)
|
||||
* - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.
|
||||
* @param cert_data [out] The certificate as a sequence of bytes.
|
||||
* @return < 0 if an error, or the size of the certificate in bytes.
|
||||
* @note cert_data must be freed when there is no more need for it.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return the axTLS library version as a string.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_version(void);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,304 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file tls1.h
|
||||
*
|
||||
* @brief The definitions for the TLS library.
|
||||
*/
|
||||
#ifndef HEADER_SSL_LIB_H
|
||||
#define HEADER_SSL_LIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "version.h"
|
||||
#include "os_int.h"
|
||||
#include "crypto.h"
|
||||
#include "crypto_misc.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */
|
||||
#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */
|
||||
#define SSL_PROTOCOL_VERSION_MAX 0x32 /* TLS v1.1 */
|
||||
#define SSL_PROTOCOL_VERSION1_1 0x32 /* TLS v1.1 */
|
||||
#define SSL_RANDOM_SIZE 32
|
||||
#define SSL_SECRET_SIZE 48
|
||||
#define SSL_FINISHED_HASH_SIZE 12
|
||||
#define SSL_RECORD_SIZE 5
|
||||
#define SSL_SERVER_READ 0
|
||||
#define SSL_SERVER_WRITE 1
|
||||
#define SSL_CLIENT_READ 2
|
||||
#define SSL_CLIENT_WRITE 3
|
||||
#define SSL_HS_HDR_SIZE 4
|
||||
|
||||
/* the flags we use while establishing a connection */
|
||||
#define SSL_NEED_RECORD 0x0001
|
||||
#define SSL_TX_ENCRYPTED 0x0002
|
||||
#define SSL_RX_ENCRYPTED 0x0004
|
||||
#define SSL_SESSION_RESUME 0x0008
|
||||
#define SSL_IS_CLIENT 0x0010
|
||||
#define SSL_HAS_CERT_REQ 0x0020
|
||||
#define SSL_SENT_CLOSE_NOTIFY 0x0040
|
||||
|
||||
/* some macros to muck around with flag bits */
|
||||
#define SET_SSL_FLAG(A) (ssl->flag |= A)
|
||||
#define CLR_SSL_FLAG(A) (ssl->flag &= ~A)
|
||||
#define IS_SET_SSL_FLAG(A) (ssl->flag & A)
|
||||
|
||||
#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */
|
||||
#define RT_MAX_PLAIN_LENGTH 2048//16384
|
||||
#define RT_EXTRA 512//1024
|
||||
#define BM_RECORD_OFFSET 5
|
||||
#define BM_ALL_DATA_SIZE (RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET)
|
||||
|
||||
#ifdef CONFIG_SSL_SKELETON_MODE
|
||||
#define NUM_PROTOCOLS 1
|
||||
#else
|
||||
#define NUM_PROTOCOLS 4
|
||||
#endif
|
||||
|
||||
#define PARANOIA_CHECK(A, B) if (A < B) { \
|
||||
ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; }
|
||||
|
||||
/* protocol types */
|
||||
enum
|
||||
{
|
||||
PT_CHANGE_CIPHER_SPEC = 20,
|
||||
PT_ALERT_PROTOCOL,
|
||||
PT_HANDSHAKE_PROTOCOL,
|
||||
PT_APP_PROTOCOL_DATA
|
||||
};
|
||||
|
||||
/* handshaking types */
|
||||
enum
|
||||
{
|
||||
HS_HELLO_REQUEST,
|
||||
HS_CLIENT_HELLO,
|
||||
HS_SERVER_HELLO,
|
||||
HS_CERTIFICATE = 11,
|
||||
HS_SERVER_KEY_XCHG,
|
||||
HS_CERT_REQ,
|
||||
HS_SERVER_HELLO_DONE,
|
||||
HS_CERT_VERIFY,
|
||||
HS_CLIENT_KEY_XCHG,
|
||||
HS_FINISHED = 20
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cipher;
|
||||
uint8_t key_size;
|
||||
uint8_t iv_size;
|
||||
uint8_t key_block_size;
|
||||
uint8_t padding_size;
|
||||
uint8_t digest_size;
|
||||
hmac_func hmac;
|
||||
crypt_func encrypt;
|
||||
crypt_func decrypt;
|
||||
} cipher_info_t;
|
||||
|
||||
struct _SSLObjLoader
|
||||
{
|
||||
uint8_t *buf;
|
||||
int len;
|
||||
};
|
||||
|
||||
typedef struct _SSLObjLoader SSLObjLoader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
time_t conn_time;
|
||||
uint8_t session_id[SSL_SESSION_ID_SIZE];
|
||||
uint8_t master_secret[SSL_SECRET_SIZE];
|
||||
} SSL_SESSION;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *buf;
|
||||
int size;
|
||||
} SSL_CERT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MD5_CTX md5_ctx;
|
||||
SHA1_CTX sha1_ctx;
|
||||
uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE];
|
||||
uint8_t key_block[MAX_KEYBLOCK_SIZE];
|
||||
uint8_t master_secret[SSL_SECRET_SIZE];
|
||||
uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */
|
||||
uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */
|
||||
uint16_t bm_proc_index;
|
||||
} DISPOSABLE_CTX;
|
||||
|
||||
struct _SSL
|
||||
{
|
||||
uint32_t flag;
|
||||
uint16_t need_bytes;
|
||||
uint16_t got_bytes;
|
||||
uint8_t record_type;
|
||||
uint8_t cipher;
|
||||
uint8_t sess_id_size;
|
||||
uint8_t version;
|
||||
uint8_t client_version;
|
||||
int16_t next_state;
|
||||
int16_t hs_status;
|
||||
DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */
|
||||
int client_fd;
|
||||
void *connection;
|
||||
const cipher_info_t *cipher_info;
|
||||
void *encrypt_ctx;
|
||||
void *decrypt_ctx;
|
||||
uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH];
|
||||
uint8_t *bm_data;
|
||||
uint16_t bm_index;
|
||||
uint16_t bm_read_index;
|
||||
struct _SSL *next; /* doubly linked list */
|
||||
struct _SSL *prev;
|
||||
struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
uint16_t session_index;
|
||||
SSL_SESSION *session;
|
||||
#endif
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
X509_CTX *x509_ctx;
|
||||
#endif
|
||||
|
||||
uint8_t session_id[SSL_SESSION_ID_SIZE];
|
||||
uint8_t client_mac[SHA1_SIZE]; /* for HMAC verification */
|
||||
uint8_t server_mac[SHA1_SIZE]; /* for HMAC verification */
|
||||
uint8_t read_sequence[8]; /* 64 bit sequence number */
|
||||
uint8_t write_sequence[8]; /* 64 bit sequence number */
|
||||
uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */
|
||||
};
|
||||
|
||||
typedef struct _SSL SSL;
|
||||
|
||||
struct _SSL_CTX
|
||||
{
|
||||
uint32_t options;
|
||||
uint8_t chain_length;
|
||||
RSA_CTX *rsa_ctx;
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
CA_CERT_CTX *ca_cert_ctx;
|
||||
#endif
|
||||
SSL *head;
|
||||
SSL *tail;
|
||||
SSL_CERT certs[CONFIG_SSL_MAX_CERTS];
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
uint16_t num_sessions;
|
||||
SSL_SESSION **ssl_sessions;
|
||||
#endif
|
||||
#ifdef CONFIG_SSL_CTX_MUTEXING
|
||||
SSL_CTX_MUTEX_TYPE mutex;
|
||||
#endif
|
||||
#ifdef CONFIG_OPENSSL_COMPATIBLE
|
||||
void *bonus_attr;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct _SSL_CTX SSL_CTX;
|
||||
|
||||
/* backwards compatibility */
|
||||
typedef struct _SSL_CTX SSLCTX;
|
||||
|
||||
extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS];
|
||||
|
||||
SSL *ssl_new(SSL *ssl, int client_fd);
|
||||
void disposable_new(SSL *ssl);
|
||||
void disposable_free(SSL *ssl);
|
||||
int send_packet(SSL *ssl, uint8_t protocol,
|
||||
const uint8_t *in, int length);
|
||||
int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
|
||||
int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
|
||||
int process_finished(SSL *ssl, uint8_t *buf, int hs_len);
|
||||
int process_sslv23_client_hello(SSL *ssl);
|
||||
int send_alert(SSL *ssl, int error_code);
|
||||
int send_finished(SSL *ssl);
|
||||
int send_certificate(SSL *ssl);
|
||||
int basic_read2(SSL *ssl, uint8_t *data, uint32_t length);
|
||||
int read_record(SSL *ssl);
|
||||
int basic_decrypt(SSL *ssl, uint8_t *buf, int len);
|
||||
int process_data(SSL* ssl, uint8_t *in_data, int len);
|
||||
int ssl_read(SSL *ssl, uint8_t *in_data, int len);
|
||||
int send_change_cipher_spec(SSL *ssl);
|
||||
void finished_digest(SSL *ssl, const char *label, uint8_t *digest);
|
||||
void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret);
|
||||
void add_packet(SSL *ssl, const uint8_t *pkt, int len);
|
||||
int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
|
||||
int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj);
|
||||
void ssl_obj_free(SSLObjLoader *ssl_obj);
|
||||
int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
|
||||
int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
|
||||
int load_key_certs(SSL_CTX *ssl_ctx);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
|
||||
void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx);
|
||||
#endif
|
||||
#ifdef CONFIG_SSL_ENABLE_CLIENT
|
||||
int do_client_connect(SSL *ssl);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok);
|
||||
void DISPLAY_BYTES(SSL *ssl, const char *format,
|
||||
const uint8_t *data, int size, ...);
|
||||
void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx);
|
||||
void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx);
|
||||
void DISPLAY_ALERT(SSL *ssl, int alert);
|
||||
#else
|
||||
#define DISPLAY_STATE(A,B,C,D)
|
||||
#define DISPLAY_CERT(A,B)
|
||||
#define DISPLAY_RSA(A,B)
|
||||
#define DISPLAY_ALERT(A, B)
|
||||
#ifdef WIN32
|
||||
void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */
|
||||
const uint8_t *data, int size, ...);
|
||||
#else
|
||||
#define DISPLAY_BYTES(A,B,C,D,...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
int process_certificate(SSL *ssl, X509_CTX **x509_ctx);
|
||||
#endif
|
||||
|
||||
SSL_SESSION *ssl_session_update(int max_sessions,
|
||||
SSL_SESSION *ssl_sessions[], SSL *ssl,
|
||||
const uint8_t *session_id);
|
||||
void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,414 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include "os_port.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */
|
||||
|
||||
static int send_client_hello(SSL *ssl);
|
||||
static int process_server_hello(SSL *ssl);
|
||||
static int process_server_hello_done(SSL *ssl);
|
||||
static int send_client_key_xchg(SSL *ssl);
|
||||
static int process_cert_req(SSL *ssl);
|
||||
static int send_cert_verify(SSL *ssl);
|
||||
|
||||
/*
|
||||
* Establish a new SSL connection to an SSL server.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_client_new(SSL *ssl, int client_fd, const
|
||||
uint8_t *session_id, uint8_t sess_id_size)
|
||||
{
|
||||
SSL_CTX *ssl_ctx = ssl->ssl_ctx;
|
||||
ssl_new(ssl, client_fd);
|
||||
ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */
|
||||
|
||||
if (session_id && ssl_ctx->num_sessions)
|
||||
{
|
||||
if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */
|
||||
{
|
||||
ssl_free(ssl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ssl->session_id, session_id, sess_id_size);
|
||||
ssl->sess_id_size = sess_id_size;
|
||||
SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */
|
||||
}
|
||||
|
||||
SET_SSL_FLAG(SSL_IS_CLIENT);
|
||||
do_client_connect(ssl);
|
||||
return ssl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the handshake record.
|
||||
*/
|
||||
int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* To get here the state must be valid */
|
||||
switch (handshake_type)
|
||||
{
|
||||
case HS_SERVER_HELLO:
|
||||
ret = process_server_hello(ssl);
|
||||
break;
|
||||
|
||||
case HS_CERTIFICATE:
|
||||
ret = process_certificate(ssl, &ssl->x509_ctx);
|
||||
break;
|
||||
|
||||
case HS_SERVER_HELLO_DONE:
|
||||
if ((ret = process_server_hello_done(ssl)) == SSL_OK)
|
||||
{
|
||||
if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ))
|
||||
{
|
||||
if ((ret = send_certificate(ssl)) == SSL_OK &&
|
||||
(ret = send_client_key_xchg(ssl)) == SSL_OK)
|
||||
{
|
||||
send_cert_verify(ssl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = send_client_key_xchg(ssl);
|
||||
}
|
||||
|
||||
if (ret == SSL_OK &&
|
||||
(ret = send_change_cipher_spec(ssl)) == SSL_OK)
|
||||
{
|
||||
ret = send_finished(ssl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HS_CERT_REQ:
|
||||
ret = process_cert_req(ssl);
|
||||
break;
|
||||
|
||||
case HS_FINISHED:
|
||||
ret = process_finished(ssl, buf, hs_len);
|
||||
disposable_free(ssl); /* free up some memory */
|
||||
/* note: client renegotiation is not allowed after this */
|
||||
break;
|
||||
|
||||
case HS_HELLO_REQUEST:
|
||||
disposable_new(ssl);
|
||||
ret = do_client_connect(ssl);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = SSL_ERROR_INVALID_HANDSHAKE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the handshaking from the beginning.
|
||||
*/
|
||||
int do_client_connect(SSL *ssl)
|
||||
{
|
||||
int ret = SSL_OK;
|
||||
|
||||
send_client_hello(ssl); /* send the client hello */
|
||||
ssl->bm_read_index = 0;
|
||||
ssl->next_state = HS_SERVER_HELLO;
|
||||
ssl->hs_status = SSL_NOT_OK; /* not connected */
|
||||
|
||||
/* sit in a loop until it all looks good */
|
||||
if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS))
|
||||
{
|
||||
while (ssl->hs_status != SSL_OK)
|
||||
{
|
||||
ret = read_record(ssl);
|
||||
if (ret < SSL_OK)
|
||||
break;
|
||||
ret = process_data(ssl, NULL, 0);
|
||||
if (ret < SSL_OK)
|
||||
break;
|
||||
}
|
||||
ssl->hs_status = ret; /* connected? */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compute_size_send_client_hello(SSL *ssl)
|
||||
{
|
||||
int size = 6 + SSL_RANDOM_SIZE;
|
||||
size++;
|
||||
if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
|
||||
{
|
||||
|
||||
size += ssl->sess_id_size;
|
||||
}
|
||||
size += 2;
|
||||
int i;
|
||||
for (i = 0; i < NUM_PROTOCOLS; i++)
|
||||
size += 2;
|
||||
size += 2;
|
||||
return size+BM_RECORD_OFFSET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the initial client hello.
|
||||
*/
|
||||
static int send_client_hello(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
time_t tm = time(NULL);
|
||||
uint8_t *tm_ptr = &buf[6]; /* time will go here */
|
||||
int i, offset;
|
||||
|
||||
buf[0] = HS_CLIENT_HELLO;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
/* byte 3 is calculated later */
|
||||
buf[4] = 0x03;
|
||||
buf[5] = ssl->version & 0x0f;
|
||||
|
||||
/* client random value - spec says that 1st 4 bytes are big endian time */
|
||||
*tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24);
|
||||
*tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16);
|
||||
*tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8);
|
||||
*tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff));
|
||||
get_random(SSL_RANDOM_SIZE-4, &buf[10]);
|
||||
memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
|
||||
offset = 6 + SSL_RANDOM_SIZE;
|
||||
|
||||
/* give session resumption a go */
|
||||
if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */
|
||||
{
|
||||
buf[offset++] = ssl->sess_id_size;
|
||||
memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size);
|
||||
offset += ssl->sess_id_size;
|
||||
CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no session id - because no session resumption just yet */
|
||||
buf[offset++] = 0;
|
||||
}
|
||||
|
||||
buf[offset++] = 0; /* number of ciphers */
|
||||
buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */
|
||||
|
||||
/* put all our supported protocols in our request */
|
||||
for (i = 0; i < NUM_PROTOCOLS; i++)
|
||||
{
|
||||
buf[offset++] = 0; /* cipher we are using */
|
||||
buf[offset++] = ssl_prot_prefs[i];
|
||||
}
|
||||
|
||||
buf[offset++] = 1; /* no compression */
|
||||
buf[offset++] = 0;
|
||||
buf[3] = offset - 4; /* handshake size */
|
||||
|
||||
return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the server hello.
|
||||
*/
|
||||
static int process_server_hello(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
int pkt_size = ssl->bm_index;
|
||||
int num_sessions = ssl->ssl_ctx->num_sessions;
|
||||
uint8_t sess_id_size;
|
||||
int offset, ret = SSL_OK;
|
||||
|
||||
/* check that we are talking to a TLSv1 server */
|
||||
uint8_t version = (buf[0] << 4) + buf[1];
|
||||
if (version > SSL_PROTOCOL_VERSION_MAX)
|
||||
{
|
||||
version = SSL_PROTOCOL_VERSION_MAX;
|
||||
}
|
||||
else if (ssl->version < SSL_PROTOCOL_MIN_VERSION)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_VERSION;
|
||||
ssl_display_error(ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssl->version = version;
|
||||
|
||||
/* get the server random value */
|
||||
memcpy(ssl->dc->server_random, &buf[2], SSL_RANDOM_SIZE);
|
||||
offset = 2 + SSL_RANDOM_SIZE; /* skip of session id size */
|
||||
sess_id_size = buf[offset++];
|
||||
|
||||
if (sess_id_size > SSL_SESSION_ID_SIZE)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_SESSION;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (num_sessions)
|
||||
{
|
||||
ssl->session = ssl_session_update(num_sessions,
|
||||
ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]);
|
||||
memcpy(ssl->session->session_id, &buf[offset], sess_id_size);
|
||||
|
||||
/* pad the rest with 0's */
|
||||
if (sess_id_size < SSL_SESSION_ID_SIZE)
|
||||
{
|
||||
memset(&ssl->session->session_id[sess_id_size], 0,
|
||||
SSL_SESSION_ID_SIZE-sess_id_size);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(ssl->session_id, &buf[offset], sess_id_size);
|
||||
ssl->sess_id_size = sess_id_size;
|
||||
offset += sess_id_size;
|
||||
|
||||
/* get the real cipher we are using */
|
||||
ssl->cipher = buf[++offset];
|
||||
ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ?
|
||||
HS_FINISHED : HS_CERTIFICATE;
|
||||
|
||||
offset++; // skip the compr
|
||||
PARANOIA_CHECK(pkt_size, offset);
|
||||
ssl->dc->bm_proc_index = offset+1;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the server hello done message.
|
||||
*/
|
||||
static int process_server_hello_done(SSL *ssl)
|
||||
{
|
||||
ssl->next_state = HS_FINISHED;
|
||||
return SSL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a client key exchange message.
|
||||
*/
|
||||
static int send_client_key_xchg(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
uint8_t premaster_secret[SSL_SECRET_SIZE];
|
||||
int enc_secret_size = -1;
|
||||
|
||||
buf[0] = HS_CLIENT_KEY_XCHG;
|
||||
buf[1] = 0;
|
||||
|
||||
premaster_secret[0] = 0x03; /* encode the version number */
|
||||
premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */
|
||||
get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]);
|
||||
DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);
|
||||
|
||||
/* rsa_ctx->bi_ctx is not thread-safe */
|
||||
SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
|
||||
enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret,
|
||||
SSL_SECRET_SIZE, &buf[6], 0);
|
||||
SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
|
||||
|
||||
buf[2] = (enc_secret_size + 2) >> 8;
|
||||
buf[3] = (enc_secret_size + 2) & 0xff;
|
||||
buf[4] = enc_secret_size >> 8;
|
||||
buf[5] = enc_secret_size & 0xff;
|
||||
|
||||
generate_master_secret(ssl, premaster_secret);
|
||||
|
||||
return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the certificate request.
|
||||
*/
|
||||
static int process_cert_req(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
|
||||
int ret = SSL_OK;
|
||||
int offset = (buf[2] << 4) + buf[3];
|
||||
int pkt_size = ssl->bm_index;
|
||||
|
||||
/* don't do any processing - we will send back an RSA certificate anyway */
|
||||
ssl->next_state = HS_SERVER_HELLO_DONE;
|
||||
SET_SSL_FLAG(SSL_HAS_CERT_REQ);
|
||||
ssl->dc->bm_proc_index += offset;
|
||||
PARANOIA_CHECK(pkt_size, offset);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a certificate verify message.
|
||||
*/
|
||||
static int send_cert_verify(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
uint8_t dgst[MD5_SIZE+SHA1_SIZE];
|
||||
RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
|
||||
int n = 0, ret;
|
||||
|
||||
DISPLAY_RSA(ssl, rsa_ctx);
|
||||
|
||||
buf[0] = HS_CERT_VERIFY;
|
||||
buf[1] = 0;
|
||||
|
||||
finished_digest(ssl, NULL, dgst); /* calculate the digest */
|
||||
|
||||
/* rsa_ctx->bi_ctx is not thread-safe */
|
||||
if (rsa_ctx)
|
||||
{
|
||||
SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
|
||||
n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1);
|
||||
SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_KEY;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
buf[4] = n >> 8; /* add the RSA size (not officially documented) */
|
||||
buf[5] = n & 0xff;
|
||||
n += 2;
|
||||
buf[2] = n >> 8;
|
||||
buf[3] = n & 0xff;
|
||||
ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4);
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSL_ENABLE_CLIENT */
|
|
@ -1,478 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "os_port.h"
|
||||
#include "ssl.h"
|
||||
|
||||
static const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 };
|
||||
|
||||
static int process_client_hello(SSL *ssl);
|
||||
static int send_server_hello_sequence(SSL *ssl);
|
||||
static int send_server_hello(SSL *ssl);
|
||||
static int send_server_hello_done(SSL *ssl);
|
||||
static int process_client_key_xchg(SSL *ssl);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
static int send_certificate_request(SSL *ssl);
|
||||
static int process_cert_verify(SSL *ssl);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Establish a new SSL connection to an SSL client.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd)
|
||||
{
|
||||
SSL *ssl;
|
||||
|
||||
ssl = ssl_new(ssl_ctx, client_fd);
|
||||
ssl->next_state = HS_CLIENT_HELLO;
|
||||
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
if (ssl_ctx->chain_length == 0)
|
||||
printf("Warning - no server certificate defined\n"); TTY_FLUSH();
|
||||
#endif
|
||||
|
||||
return ssl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the handshake record.
|
||||
*/
|
||||
int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
|
||||
{
|
||||
int ret = SSL_OK;
|
||||
ssl->hs_status = SSL_NOT_OK; /* not connected */
|
||||
|
||||
/* To get here the state must be valid */
|
||||
switch (handshake_type)
|
||||
{
|
||||
case HS_CLIENT_HELLO:
|
||||
if ((ret = process_client_hello(ssl)) == SSL_OK)
|
||||
ret = send_server_hello_sequence(ssl);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
case HS_CERTIFICATE:/* the client sends its cert */
|
||||
ret = process_certificate(ssl, &ssl->x509_ctx);
|
||||
|
||||
if (ret == SSL_OK) /* verify the cert */
|
||||
{
|
||||
int cert_res;
|
||||
cert_res = x509_verify(
|
||||
ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
|
||||
ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);
|
||||
}
|
||||
break;
|
||||
|
||||
case HS_CERT_VERIFY:
|
||||
ret = process_cert_verify(ssl);
|
||||
add_packet(ssl, buf, hs_len); /* needs to be done after */
|
||||
break;
|
||||
#endif
|
||||
case HS_CLIENT_KEY_XCHG:
|
||||
ret = process_client_key_xchg(ssl);
|
||||
break;
|
||||
|
||||
case HS_FINISHED:
|
||||
ret = process_finished(ssl, buf, hs_len);
|
||||
disposable_free(ssl); /* free up some memory */
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a client hello message.
|
||||
*/
|
||||
static int process_client_hello(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
uint8_t *record_buf = ssl->hmac_header;
|
||||
int pkt_size = ssl->bm_index;
|
||||
int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE;
|
||||
int ret = SSL_OK;
|
||||
|
||||
uint8_t version = (buf[4] << 4) + buf[5];
|
||||
ssl->version = ssl->client_version = version;
|
||||
|
||||
if (version > SSL_PROTOCOL_VERSION_MAX)
|
||||
{
|
||||
/* use client's version instead */
|
||||
ssl->version = SSL_PROTOCOL_VERSION_MAX;
|
||||
}
|
||||
else if (version < SSL_PROTOCOL_MIN_VERSION) /* old version supported? */
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_VERSION;
|
||||
ssl_display_error(ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
|
||||
|
||||
/* process the session id */
|
||||
id_len = buf[offset++];
|
||||
if (id_len > SSL_SESSION_ID_SIZE)
|
||||
{
|
||||
return SSL_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
|
||||
ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
|
||||
#endif
|
||||
|
||||
offset += id_len;
|
||||
cs_len = (buf[offset]<<8) + buf[offset+1];
|
||||
offset += 3; /* add 1 due to all cipher suites being 8 bit */
|
||||
|
||||
PARANOIA_CHECK(pkt_size, offset);
|
||||
|
||||
/* work out what cipher suite we are going to use - client defines
|
||||
the preference */
|
||||
for (i = 0; i < cs_len; i += 2)
|
||||
{
|
||||
for (j = 0; j < NUM_PROTOCOLS; j++)
|
||||
{
|
||||
if (ssl_prot_prefs[j] == buf[offset+i]) /* got a match? */
|
||||
{
|
||||
ssl->cipher = ssl_prot_prefs[j];
|
||||
goto do_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ouch! protocol is not supported */
|
||||
ret = SSL_ERROR_NO_CIPHER;
|
||||
|
||||
do_state:
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
|
||||
/*
|
||||
* Some browsers use a hybrid SSLv2 "client hello"
|
||||
*/
|
||||
int process_sslv23_client_hello(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1];
|
||||
int ret = SSL_OK;
|
||||
|
||||
/* we have already read 3 extra bytes so far */
|
||||
int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3);
|
||||
int cs_len = buf[1];
|
||||
int id_len = buf[3];
|
||||
int ch_len = buf[5];
|
||||
int i, j, offset = 8; /* start at first cipher */
|
||||
int random_offset = 0;
|
||||
|
||||
DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len);
|
||||
|
||||
add_packet(ssl, buf, read_len);
|
||||
|
||||
/* connection has gone, so die */
|
||||
if (bytes_needed < 0)
|
||||
{
|
||||
return SSL_ERROR_CONN_LOST;
|
||||
}
|
||||
|
||||
/* now work out what cipher suite we are going to use */
|
||||
for (j = 0; j < NUM_PROTOCOLS; j++)
|
||||
{
|
||||
for (i = 0; i < cs_len; i += 3)
|
||||
{
|
||||
if (ssl_prot_prefs[j] == buf[offset+i])
|
||||
{
|
||||
ssl->cipher = ssl_prot_prefs[j];
|
||||
goto server_hello;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ouch! protocol is not supported */
|
||||
ret = SSL_ERROR_NO_CIPHER;
|
||||
goto error;
|
||||
|
||||
server_hello:
|
||||
/* get the session id */
|
||||
offset += cs_len - 2; /* we've gone 2 bytes past the end */
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
|
||||
ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
|
||||
#endif
|
||||
|
||||
/* get the client random data */
|
||||
offset += id_len;
|
||||
|
||||
/* random can be anywhere between 16 and 32 bytes long - so it is padded
|
||||
* with 0's to the left */
|
||||
if (ch_len == 0x10)
|
||||
{
|
||||
random_offset += 0x10;
|
||||
}
|
||||
|
||||
memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len);
|
||||
ret = send_server_hello_sequence(ssl);
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Send the entire server hello sequence
|
||||
*/
|
||||
static int send_server_hello_sequence(SSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = send_server_hello(ssl)) == SSL_OK)
|
||||
{
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
/* resume handshake? */
|
||||
if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
|
||||
{
|
||||
if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
|
||||
{
|
||||
ret = send_finished(ssl);
|
||||
ssl->next_state = HS_FINISHED;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((ret = send_certificate(ssl)) == SSL_OK)
|
||||
{
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
/* ask the client for its certificate */
|
||||
if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION))
|
||||
{
|
||||
if ((ret = send_certificate_request(ssl)) == SSL_OK)
|
||||
{
|
||||
ret = send_server_hello_done(ssl);
|
||||
ssl->next_state = HS_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = send_server_hello_done(ssl);
|
||||
ssl->next_state = HS_CLIENT_KEY_XCHG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a server hello message.
|
||||
*/
|
||||
static int send_server_hello(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = ssl->bm_data;
|
||||
int offset = 0;
|
||||
|
||||
buf[0] = HS_SERVER_HELLO;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
/* byte 3 is calculated later */
|
||||
buf[4] = 0x03;
|
||||
buf[5] = ssl->version & 0x0f;
|
||||
|
||||
/* server random value */
|
||||
get_random(SSL_RANDOM_SIZE, &buf[6]);
|
||||
memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
|
||||
offset = 6 + SSL_RANDOM_SIZE;
|
||||
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
|
||||
{
|
||||
/* retrieve id from session cache */
|
||||
buf[offset++] = SSL_SESSION_ID_SIZE;
|
||||
memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE);
|
||||
memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE);
|
||||
ssl->sess_id_size = SSL_SESSION_ID_SIZE;
|
||||
offset += SSL_SESSION_ID_SIZE;
|
||||
}
|
||||
else /* generate our own session id */
|
||||
#endif
|
||||
{
|
||||
#ifndef CONFIG_SSL_SKELETON_MODE
|
||||
buf[offset++] = SSL_SESSION_ID_SIZE;
|
||||
get_random(SSL_SESSION_ID_SIZE, &buf[offset]);
|
||||
memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE);
|
||||
ssl->sess_id_size = SSL_SESSION_ID_SIZE;
|
||||
|
||||
/* store id in session cache */
|
||||
if (ssl->ssl_ctx->num_sessions)
|
||||
{
|
||||
memcpy(ssl->session->session_id,
|
||||
ssl->session_id, SSL_SESSION_ID_SIZE);
|
||||
}
|
||||
|
||||
offset += SSL_SESSION_ID_SIZE;
|
||||
#else
|
||||
buf[offset++] = 0; /* don't bother with session id in skelton mode */
|
||||
#endif
|
||||
}
|
||||
|
||||
buf[offset++] = 0; /* cipher we are using */
|
||||
buf[offset++] = ssl->cipher;
|
||||
buf[offset++] = 0; /* no compression */
|
||||
buf[3] = offset - 4; /* handshake size */
|
||||
return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the server hello done message.
|
||||
*/
|
||||
static int send_server_hello_done(SSL *ssl)
|
||||
{
|
||||
return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
|
||||
g_hello_done, sizeof(g_hello_done));
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull apart a client key exchange message. Decrypt the pre-master key (using
|
||||
* our RSA private key) and then work out the master key. Initialise the
|
||||
* ciphers.
|
||||
*/
|
||||
static int process_client_key_xchg(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
|
||||
int pkt_size = ssl->bm_index;
|
||||
int premaster_size, secret_length = (buf[2] << 8) + buf[3];
|
||||
uint8_t premaster_secret[MAX_KEY_BYTE_SIZE];
|
||||
RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
|
||||
int offset = 4;
|
||||
int ret = SSL_OK;
|
||||
|
||||
if (rsa_ctx == NULL)
|
||||
{
|
||||
ret = SSL_ERROR_NO_CERT_DEFINED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* is there an extra size field? */
|
||||
if ((secret_length - 2) == rsa_ctx->num_octets)
|
||||
offset += 2;
|
||||
|
||||
PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset);
|
||||
|
||||
/* rsa_ctx->bi_ctx is not thread-safe */
|
||||
SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
|
||||
premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1);
|
||||
SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
|
||||
|
||||
if (premaster_size != SSL_SECRET_SIZE ||
|
||||
premaster_secret[0] != 0x03 || /* must be the same as client
|
||||
offered version */
|
||||
premaster_secret[1] != (ssl->client_version & 0x0f))
|
||||
{
|
||||
/* guard against a Bleichenbacher attack */
|
||||
get_random(SSL_SECRET_SIZE, premaster_secret);
|
||||
/* and continue - will die eventually when checking the mac */
|
||||
}
|
||||
|
||||
#if 0
|
||||
print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE);
|
||||
#endif
|
||||
|
||||
generate_master_secret(ssl, premaster_secret);
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ?
|
||||
HS_CERT_VERIFY : HS_FINISHED;
|
||||
#else
|
||||
ssl->next_state = HS_FINISHED;
|
||||
#endif
|
||||
|
||||
ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset;
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
static const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 };
|
||||
|
||||
/*
|
||||
* Send the certificate request message.
|
||||
*/
|
||||
static int send_certificate_request(SSL *ssl)
|
||||
{
|
||||
return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
|
||||
g_cert_request, sizeof(g_cert_request));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the client has the private key by first decrypting the packet and
|
||||
* then checking the packet digests.
|
||||
*/
|
||||
static int process_cert_verify(SSL *ssl)
|
||||
{
|
||||
uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
|
||||
int pkt_size = ssl->bm_index;
|
||||
uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];
|
||||
uint8_t dgst[MD5_SIZE+SHA1_SIZE];
|
||||
X509_CTX *x509_ctx = ssl->x509_ctx;
|
||||
int ret = SSL_OK;
|
||||
int n;
|
||||
|
||||
PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6);
|
||||
DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);
|
||||
|
||||
/* rsa_ctx->bi_ctx is not thread-safe */
|
||||
SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
|
||||
n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0);
|
||||
SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
|
||||
|
||||
if (n != SHA1_SIZE + MD5_SIZE)
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_KEY;
|
||||
goto end_cert_vfy;
|
||||
}
|
||||
|
||||
finished_digest(ssl, NULL, dgst); /* calculate the digest */
|
||||
if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))
|
||||
{
|
||||
ret = SSL_ERROR_INVALID_KEY;
|
||||
}
|
||||
|
||||
end_cert_vfy:
|
||||
ssl->next_state = HS_FINISHED;
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
#define AXTLS_VERSION "1.4.9"
|
|
@ -1,556 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file x509.c
|
||||
*
|
||||
* Certificate processing.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto_misc.h"
|
||||
#include "sockets.h"
|
||||
#include "config.h"
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
/**
|
||||
* Retrieve the signature from a certificate.
|
||||
*/
|
||||
static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
|
||||
{
|
||||
int offset = 0;
|
||||
const uint8_t *ptr = NULL;
|
||||
|
||||
if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
|
||||
asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
|
||||
goto end_get_sig;
|
||||
|
||||
if (asn1_sig[offset++] != ASN1_OCTET_STRING)
|
||||
goto end_get_sig;
|
||||
*len = get_asn1_length(asn1_sig, &offset);
|
||||
ptr = &asn1_sig[offset]; /* all ok */
|
||||
|
||||
end_get_sig:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Construct a new x509 object.
|
||||
* @return 0 if ok. < 0 if there was a problem.
|
||||
*/
|
||||
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
|
||||
{
|
||||
|
||||
int begin_tbs, end_tbs;
|
||||
int ret = X509_NOT_OK, offset = 0, cert_size = 0;
|
||||
X509_CTX *x509_ctx;
|
||||
BI_CTX *bi_ctx;
|
||||
*ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
|
||||
x509_ctx = *ctx;
|
||||
/* get the certificate size */
|
||||
asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
|
||||
|
||||
if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
||||
goto end_cert;
|
||||
|
||||
begin_tbs = offset; /* start of the tbs */
|
||||
end_tbs = begin_tbs; /* work out the end of the tbs */
|
||||
asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
|
||||
if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
||||
goto end_cert;
|
||||
if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
|
||||
{
|
||||
if (asn1_version(cert, &offset, x509_ctx))
|
||||
goto end_cert;
|
||||
}
|
||||
if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
|
||||
asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
||||
{
|
||||
goto end_cert;
|
||||
}
|
||||
/* make sure the signature is ok */
|
||||
if (asn1_signature_type(cert, &offset, x509_ctx))
|
||||
{
|
||||
ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
|
||||
goto end_cert;
|
||||
}
|
||||
if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
|
||||
asn1_validity(cert, &offset, x509_ctx) ||
|
||||
asn1_name(cert, &offset, x509_ctx->cert_dn) ||
|
||||
asn1_public_key(cert, &offset, x509_ctx))
|
||||
{
|
||||
goto end_cert;
|
||||
}
|
||||
bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
|
||||
|
||||
/* use the appropriate signature algorithm (SHA1/MD5/MD2) */
|
||||
if (x509_ctx->sig_type == SIG_TYPE_MD5)
|
||||
{
|
||||
MD5_CTX md5_ctx;
|
||||
uint8_t md5_dgst[MD5_SIZE];
|
||||
MD5_Init(&md5_ctx);
|
||||
MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
|
||||
MD5_Final(md5_dgst, &md5_ctx);
|
||||
x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
|
||||
}
|
||||
else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
|
||||
{
|
||||
SHA1_CTX sha_ctx;
|
||||
uint8_t sha_dgst[SHA1_SIZE];
|
||||
SHA1_Init(&sha_ctx);
|
||||
SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
|
||||
SHA1_Final(sha_dgst, &sha_ctx);
|
||||
x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
|
||||
}
|
||||
else if (x509_ctx->sig_type == SIG_TYPE_MD2)
|
||||
{
|
||||
MD2_CTX md2_ctx;
|
||||
uint8_t md2_dgst[MD2_SIZE];
|
||||
MD2_Init(&md2_ctx);
|
||||
MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
|
||||
MD2_Final(md2_dgst, &md2_ctx);
|
||||
x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
|
||||
}
|
||||
|
||||
if (cert[offset] == ASN1_V3_DATA)
|
||||
{
|
||||
int suboffset;
|
||||
|
||||
++offset;
|
||||
get_asn1_length(cert, &offset);
|
||||
|
||||
if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
|
||||
{
|
||||
if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
|
||||
{
|
||||
int altlen;
|
||||
|
||||
if ((altlen = asn1_next_obj(cert,
|
||||
&suboffset, ASN1_SEQUENCE)) > 0)
|
||||
{
|
||||
int endalt = suboffset + altlen;
|
||||
int totalnames = 0;
|
||||
|
||||
while (suboffset < endalt)
|
||||
{
|
||||
int type = cert[suboffset++];
|
||||
int dnslen = get_asn1_length(cert, &suboffset);
|
||||
|
||||
if (type == ASN1_CONTEXT_DNSNAME)
|
||||
{
|
||||
x509_ctx->subject_alt_dnsnames = (char**)
|
||||
realloc(x509_ctx->subject_alt_dnsnames,
|
||||
(totalnames + 2) * sizeof(char*));
|
||||
x509_ctx->subject_alt_dnsnames[totalnames] =
|
||||
(char*)malloc(dnslen + 1);
|
||||
x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
|
||||
memcpy(x509_ctx->subject_alt_dnsnames[totalnames],
|
||||
cert + suboffset, dnslen);
|
||||
x509_ctx->subject_alt_dnsnames[
|
||||
totalnames][dnslen] = 0;
|
||||
++totalnames;
|
||||
}
|
||||
|
||||
suboffset += dnslen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset = end_tbs; /* skip the rest of v3 data */
|
||||
if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
|
||||
asn1_signature(cert, &offset, x509_ctx))
|
||||
goto end_cert;
|
||||
|
||||
#endif
|
||||
ret = X509_OK;
|
||||
end_cert:
|
||||
if (len)
|
||||
{
|
||||
*len = cert_size;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
printf("Error: Invalid X509 ASN.1 file (%s)\n",
|
||||
x509_display_error(ret));
|
||||
#endif
|
||||
x509_free(x509_ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an X.509 object's resources.
|
||||
*/
|
||||
void x509_free(X509_CTX *x509_ctx)
|
||||
{
|
||||
X509_CTX *next;
|
||||
int i;
|
||||
|
||||
if (x509_ctx == NULL) /* if already null, then don't bother */
|
||||
return;
|
||||
|
||||
for (i = 0; i < X509_NUM_DN_TYPES; i++)
|
||||
{
|
||||
free(x509_ctx->ca_cert_dn[i]);
|
||||
free(x509_ctx->cert_dn[i]);
|
||||
}
|
||||
|
||||
free(x509_ctx->signature);
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
if (x509_ctx->digest)
|
||||
{
|
||||
bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
|
||||
}
|
||||
|
||||
if (x509_ctx->subject_alt_dnsnames)
|
||||
{
|
||||
for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
|
||||
free(x509_ctx->subject_alt_dnsnames[i]);
|
||||
|
||||
free(x509_ctx->subject_alt_dnsnames);
|
||||
}
|
||||
#endif
|
||||
|
||||
RSA_free(x509_ctx->rsa_ctx);
|
||||
next = x509_ctx->next;
|
||||
free(x509_ctx);
|
||||
x509_free(next); /* clear the chain */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
/**
|
||||
* Take a signature and decrypt it.
|
||||
*/
|
||||
static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
|
||||
bigint *modulus, bigint *pub_exp)
|
||||
{
|
||||
int i, size;
|
||||
bigint *decrypted_bi, *dat_bi;
|
||||
bigint *bir = NULL;
|
||||
uint8_t *block = (uint8_t *)alloca(sig_len);
|
||||
|
||||
/* decrypt */
|
||||
dat_bi = bi_import(ctx, sig, sig_len);
|
||||
ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
|
||||
/* convert to a normal block */
|
||||
decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
|
||||
|
||||
bi_export(ctx, decrypted_bi, block, sig_len);
|
||||
ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
|
||||
i = 10; /* start at the first possible non-padded byte */
|
||||
while (block[i++] && i < sig_len);
|
||||
size = sig_len - i;
|
||||
|
||||
/* get only the bit we want */
|
||||
if (size > 0)
|
||||
{
|
||||
int len;
|
||||
const uint8_t *sig_ptr = get_signature(&block[i], &len);
|
||||
|
||||
if (sig_ptr)
|
||||
{
|
||||
bir = bi_import(ctx, sig_ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* save a few bytes of memory */
|
||||
bi_clear_cache(ctx);
|
||||
return bir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do some basic checks on the certificate chain.
|
||||
*
|
||||
* Certificate verification consists of a number of checks:
|
||||
* - The date of the certificate is after the start date.
|
||||
* - The date of the certificate is before the finish date.
|
||||
* - A root certificate exists in the certificate store.
|
||||
* - That the certificate(s) are not self-signed.
|
||||
* - The certificate chain is valid.
|
||||
* - The signature of the certificate is valid.
|
||||
*/
|
||||
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
|
||||
{
|
||||
int ret = X509_OK, i = 0;
|
||||
bigint *cert_sig;
|
||||
X509_CTX *next_cert = NULL;
|
||||
BI_CTX *ctx = NULL;
|
||||
bigint *mod = NULL, *expn = NULL;
|
||||
int match_ca_cert = 0;
|
||||
struct timeval tv;
|
||||
uint8_t is_self_signed = 0;
|
||||
|
||||
if (cert == NULL)
|
||||
{
|
||||
ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
|
||||
goto end_verify;
|
||||
}
|
||||
|
||||
/* a self-signed certificate that is not in the CA store - use this
|
||||
to check the signature */
|
||||
if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
|
||||
{
|
||||
printf("self signed cert\r\n");
|
||||
is_self_signed = 1;
|
||||
ctx = cert->rsa_ctx->bi_ctx;
|
||||
mod = cert->rsa_ctx->m;
|
||||
expn = cert->rsa_ctx->e;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
/* check the not before date */
|
||||
if (tv.tv_sec < cert->not_before)
|
||||
{
|
||||
ret = X509_VFY_ERROR_NOT_YET_VALID;
|
||||
goto end_verify;
|
||||
}
|
||||
|
||||
/* check the not after date */
|
||||
if (tv.tv_sec > cert->not_after)
|
||||
{
|
||||
ret = X509_VFY_ERROR_EXPIRED;
|
||||
goto end_verify;
|
||||
}
|
||||
|
||||
next_cert = cert->next;
|
||||
|
||||
/* last cert in the chain - look for a trusted cert */
|
||||
if (next_cert == NULL)
|
||||
{
|
||||
if (ca_cert_ctx != NULL)
|
||||
{
|
||||
/* go thu the CA store */
|
||||
while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
|
||||
{
|
||||
if (asn1_compare_dn(cert->ca_cert_dn,
|
||||
ca_cert_ctx->cert[i]->cert_dn) == 0)
|
||||
{
|
||||
/* use this CA certificate for signature verification */
|
||||
match_ca_cert = 1;
|
||||
ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
|
||||
mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
|
||||
expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* couldn't find a trusted cert (& let self-signed errors
|
||||
be returned) */
|
||||
if (!match_ca_cert && !is_self_signed)
|
||||
{
|
||||
ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
|
||||
goto end_verify;
|
||||
}
|
||||
}
|
||||
else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
|
||||
{
|
||||
/* check the chain */
|
||||
ret = X509_VFY_ERROR_INVALID_CHAIN;
|
||||
goto end_verify;
|
||||
}
|
||||
else /* use the next certificate in the chain for signature verify */
|
||||
{
|
||||
ctx = next_cert->rsa_ctx->bi_ctx;
|
||||
mod = next_cert->rsa_ctx->m;
|
||||
expn = next_cert->rsa_ctx->e;
|
||||
}
|
||||
|
||||
/* cert is self signed */
|
||||
if (!match_ca_cert && is_self_signed)
|
||||
{
|
||||
ret = X509_VFY_ERROR_SELF_SIGNED;
|
||||
goto end_verify;
|
||||
}
|
||||
|
||||
/* check the signature */
|
||||
cert_sig = sig_verify(ctx, cert->signature, cert->sig_len,
|
||||
bi_clone(ctx, mod), bi_clone(ctx, expn));
|
||||
|
||||
if (cert_sig && cert->digest)
|
||||
{
|
||||
if (bi_compare(cert_sig, cert->digest) != 0)
|
||||
ret = X509_VFY_ERROR_BAD_SIGNATURE;
|
||||
|
||||
|
||||
bi_free(ctx, cert_sig);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = X509_VFY_ERROR_BAD_SIGNATURE;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto end_verify;
|
||||
|
||||
/* go down the certificate chain using recursion. */
|
||||
if (next_cert != NULL)
|
||||
{
|
||||
ret = x509_verify(ca_cert_ctx, next_cert);
|
||||
}
|
||||
|
||||
end_verify:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_SSL_FULL_MODE)
|
||||
/**
|
||||
* Used for diagnostics.
|
||||
*/
|
||||
static const char *not_part_of_cert = "<Not Part Of Certificate>";
|
||||
void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx)
|
||||
{
|
||||
if (cert == NULL)
|
||||
return;
|
||||
|
||||
printf("=== CERTIFICATE ISSUED TO ===\n");
|
||||
printf("Common Name (CN):\t\t");
|
||||
printf("%s\r\n", cert->cert_dn[X509_COMMON_NAME] ?
|
||||
cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
|
||||
|
||||
printf("Organization (O):\t\t");
|
||||
printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ?
|
||||
cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
|
||||
|
||||
printf("Organizational Unit (OU):\t");
|
||||
printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
|
||||
cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
|
||||
|
||||
printf("=== CERTIFICATE ISSUED BY ===\r\n");
|
||||
printf("Common Name (CN):\t\t");
|
||||
printf("%s\r\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
|
||||
cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
|
||||
|
||||
printf("Organization (O):\t\t");
|
||||
printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
|
||||
cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
|
||||
|
||||
printf("Organizational Unit (OU):\t");
|
||||
printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
|
||||
cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
|
||||
|
||||
printf("Not Before:\t\t\t%s\r\n", ctime(&cert->not_before));
|
||||
printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after));
|
||||
printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8);
|
||||
printf("Sig Type:\t\t\t");
|
||||
switch (cert->sig_type)
|
||||
{
|
||||
case SIG_TYPE_MD5:
|
||||
printf("MD5\r\n");
|
||||
break;
|
||||
case SIG_TYPE_SHA1:
|
||||
printf("SHA1\r\n");
|
||||
break;
|
||||
case SIG_TYPE_MD2:
|
||||
printf("MD2\r\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unrecognized: %d\r\n", cert->sig_type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ca_cert_ctx)
|
||||
{
|
||||
printf("Verify:\t\t\t\t%s\r\n",
|
||||
x509_display_error(x509_verify(ca_cert_ctx, cert)));
|
||||
}
|
||||
|
||||
#if 0
|
||||
print_blob("Signature", cert->signature, cert->sig_len);
|
||||
bi_print("Modulus", cert->rsa_ctx->m);
|
||||
bi_print("Pub Exp", cert->rsa_ctx->e);
|
||||
#endif
|
||||
|
||||
if (ca_cert_ctx)
|
||||
{
|
||||
x509_print(cert->next, ca_cert_ctx);
|
||||
}
|
||||
|
||||
TTY_FLUSH();
|
||||
}
|
||||
|
||||
const char * x509_display_error(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case X509_OK:
|
||||
return "Certificate verify successful";
|
||||
|
||||
case X509_NOT_OK:
|
||||
return "X509 not ok";
|
||||
|
||||
case X509_VFY_ERROR_NO_TRUSTED_CERT:
|
||||
return "No trusted cert is available";
|
||||
|
||||
case X509_VFY_ERROR_BAD_SIGNATURE:
|
||||
return "Bad signature";
|
||||
|
||||
case X509_VFY_ERROR_NOT_YET_VALID:
|
||||
return "Cert is not yet valid";
|
||||
|
||||
case X509_VFY_ERROR_EXPIRED:
|
||||
return "Cert has expired";
|
||||
|
||||
case X509_VFY_ERROR_SELF_SIGNED:
|
||||
return "Cert is self-signed";
|
||||
|
||||
case X509_VFY_ERROR_INVALID_CHAIN:
|
||||
return "Chain is invalid (check order of certs)";
|
||||
|
||||
case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
|
||||
return "Unsupported digest";
|
||||
|
||||
case X509_INVALID_PRIV_KEY:
|
||||
return "Invalid private key";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SSL_FULL_MODE */
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "Socket/Socket.h"
|
||||
#include "Socket/Endpoint.h"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
Endpoint::Endpoint() {
|
||||
reset_address();
|
||||
}
|
||||
Endpoint::~Endpoint() {}
|
||||
|
||||
void Endpoint::reset_address(void) {
|
||||
std::memset(&_remoteHost, 0, sizeof(struct sockaddr_in));
|
||||
_ipAddress[0] = '\0';
|
||||
}
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
int Endpoint::set_address(const char* host, const int port) {
|
||||
reset_address();
|
||||
|
||||
// IP Address
|
||||
char address[5];
|
||||
char *p_address = address;
|
||||
|
||||
// Dot-decimal notation
|
||||
int result = std::sscanf(host, "%3u.%3u.%3u.%3u",
|
||||
(unsigned int*)&address[0], (unsigned int*)&address[1],
|
||||
(unsigned int*)&address[2], (unsigned int*)&address[3]);
|
||||
|
||||
if (result != 4) {
|
||||
// Resolve address with DNS
|
||||
struct hostent *host_address = lwip_gethostbyname(host);
|
||||
if (host_address == NULL)
|
||||
return -1; //Could not resolve address
|
||||
p_address = (char*)host_address->h_addr_list[0];
|
||||
}
|
||||
std::memcpy((char*)&_remoteHost.sin_addr.s_addr, p_address, 4);
|
||||
|
||||
// Address family
|
||||
_remoteHost.sin_family = AF_INET;
|
||||
|
||||
// Set port
|
||||
_remoteHost.sin_port = htons(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* Endpoint::get_address() {
|
||||
if ((_ipAddress[0] == '\0') && (_remoteHost.sin_addr.s_addr != 0))
|
||||
inet_ntoa_r(_remoteHost.sin_addr, _ipAddress, sizeof(_ipAddress));
|
||||
return _ipAddress;
|
||||
}
|
||||
|
||||
int Endpoint::get_port() {
|
||||
return ntohs(_remoteHost.sin_port);
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ENDPOINT_H
|
||||
#define ENDPOINT_H
|
||||
|
||||
class UDPSocket;
|
||||
|
||||
/**
|
||||
IP Endpoint (address, port)
|
||||
*/
|
||||
class Endpoint {
|
||||
friend class UDPSocket;
|
||||
|
||||
public:
|
||||
/** IP Endpoint (address, port)
|
||||
*/
|
||||
Endpoint(void);
|
||||
|
||||
~Endpoint(void);
|
||||
|
||||
/** Reset the address of this endpoint
|
||||
*/
|
||||
void reset_address(void);
|
||||
|
||||
/** Set the address of this endpoint
|
||||
\param host The endpoint address (it can either be an IP Address or a hostname that will be resolved with DNS).
|
||||
\param port The endpoint port
|
||||
\return 0 on success, -1 on failure (when an hostname cannot be resolved by DNS).
|
||||
*/
|
||||
int set_address(const char* host, const int port);
|
||||
|
||||
/** Get the IP address of this endpoint
|
||||
\return The IP address of this endpoint.
|
||||
*/
|
||||
char* get_address(void);
|
||||
|
||||
/** Get the port of this endpoint
|
||||
\return The port of this endpoint
|
||||
*/
|
||||
int get_port(void);
|
||||
|
||||
protected:
|
||||
char _ipAddress[17];
|
||||
struct sockaddr_in _remoteHost;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,91 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "Socket/Socket.h"
|
||||
#include <cstring>
|
||||
|
||||
using std::memset;
|
||||
|
||||
Socket::Socket() : _sock_fd(-1), _blocking(true), _timeout(1500) {
|
||||
|
||||
}
|
||||
|
||||
void Socket::set_blocking(bool blocking, unsigned int timeout) {
|
||||
_blocking = blocking;
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
int Socket::init_socket(int type) {
|
||||
if (_sock_fd != -1)
|
||||
return -1;
|
||||
|
||||
int fd = lwip_socket(AF_INET, type, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
_sock_fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen) {
|
||||
return lwip_setsockopt(_sock_fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) {
|
||||
return lwip_getsockopt(_sock_fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int Socket::select(struct timeval *timeout, bool read, bool write) {
|
||||
fd_set fdSet;
|
||||
FD_ZERO(&fdSet);
|
||||
FD_SET(_sock_fd, &fdSet);
|
||||
|
||||
fd_set* readset = (read ) ? (&fdSet) : (NULL);
|
||||
fd_set* writeset = (write) ? (&fdSet) : (NULL);
|
||||
|
||||
int ret = lwip_select(FD_SETSIZE, readset, writeset, NULL, timeout);
|
||||
return (ret <= 0 || !FD_ISSET(_sock_fd, &fdSet)) ? (-1) : (0);
|
||||
}
|
||||
|
||||
int Socket::wait_readable(TimeInterval& timeout) {
|
||||
return select(&timeout._time, true, false);
|
||||
}
|
||||
|
||||
int Socket::wait_writable(TimeInterval& timeout) {
|
||||
return select(&timeout._time, false, true);
|
||||
}
|
||||
|
||||
int Socket::close(bool shutdown) {
|
||||
if (_sock_fd < 0)
|
||||
return -1;
|
||||
|
||||
if (shutdown)
|
||||
lwip_shutdown(_sock_fd, SHUT_RDWR);
|
||||
lwip_close(_sock_fd);
|
||||
_sock_fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Socket::~Socket() {
|
||||
close(); //Don't want to leak
|
||||
}
|
||||
|
||||
TimeInterval::TimeInterval(unsigned int ms) {
|
||||
_time.tv_sec = ms / 1000;
|
||||
_time.tv_usec = (ms - (_time.tv_sec * 1000)) * 1000;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SOCKET_H_
|
||||
#define SOCKET_H_
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
//DNS
|
||||
inline struct hostent *gethostbyname(const char *name) {
|
||||
return lwip_gethostbyname(name);
|
||||
}
|
||||
|
||||
inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) {
|
||||
return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
|
||||
}
|
||||
|
||||
class TimeInterval;
|
||||
|
||||
/** Socket file descriptor and select wrapper
|
||||
*/
|
||||
class Socket {
|
||||
public:
|
||||
/** Socket
|
||||
*/
|
||||
Socket();
|
||||
|
||||
/** Set blocking or non-blocking mode of the socket and a timeout on
|
||||
blocking socket operations
|
||||
\param blocking true for blocking mode, false for non-blocking mode.
|
||||
\param timeout timeout in ms [Default: (1500)ms].
|
||||
*/
|
||||
void set_blocking(bool blocking, unsigned int timeout=1500);
|
||||
|
||||
/** Set socket options
|
||||
\param level stack level (see: lwip/sockets.h)
|
||||
\param optname option ID
|
||||
\param optval option value
|
||||
\param socklen_t length of the option value
|
||||
\return 0 on success, -1 on failure
|
||||
*/
|
||||
int set_option(int level, int optname, const void *optval, socklen_t optlen);
|
||||
|
||||
/** Get socket options
|
||||
\param level stack level (see: lwip/sockets.h)
|
||||
\param optname option ID
|
||||
\param optval buffer pointer where to write the option value
|
||||
\param socklen_t length of the option value
|
||||
\return 0 on success, -1 on failure
|
||||
*/
|
||||
int get_option(int level, int optname, void *optval, socklen_t *optlen);
|
||||
|
||||
/** Close the socket
|
||||
\param shutdown free the left-over data in message queues
|
||||
*/
|
||||
int close(bool shutdown=true);
|
||||
|
||||
~Socket();
|
||||
|
||||
protected:
|
||||
int _sock_fd;
|
||||
int init_socket(int type);
|
||||
|
||||
int wait_readable(TimeInterval& timeout);
|
||||
int wait_writable(TimeInterval& timeout);
|
||||
|
||||
bool _blocking;
|
||||
unsigned int _timeout;
|
||||
|
||||
private:
|
||||
int select(struct timeval *timeout, bool read, bool write);
|
||||
};
|
||||
|
||||
/** Time interval class used to specify timeouts
|
||||
*/
|
||||
class TimeInterval {
|
||||
friend class Socket;
|
||||
|
||||
public:
|
||||
/** Time Interval
|
||||
\param ms time interval expressed in milliseconds
|
||||
*/
|
||||
TimeInterval(unsigned int ms);
|
||||
|
||||
private:
|
||||
struct timeval _time;
|
||||
};
|
||||
|
||||
#endif /* SOCKET_H_ */
|
|
@ -1,133 +0,0 @@
|
|||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "TCPSocketConnection.h"
|
||||
#include <cstring>
|
||||
|
||||
using std::memset;
|
||||
using std::memcpy;
|
||||
|
||||
TCPSocketConnection::TCPSocketConnection() :
|
||||
_is_connected(false) {
|
||||
}
|
||||
|
||||
int TCPSocketConnection::connect(const char* host, const int port) {
|
||||
if (init_socket(SOCK_STREAM) < 0)
|
||||
return -1;
|
||||
|
||||
if (set_address(host, port) != 0)
|
||||
return -1;
|
||||
|
||||
if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) {
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
_is_connected = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TCPSocketConnection::is_connected(void) {
|
||||
return _is_connected;
|
||||
}
|
||||
|
||||
int TCPSocketConnection::send(char* data, int length) {
|
||||
if ((_sock_fd < 0) || !_is_connected)
|
||||
return -1;
|
||||
|
||||
if (!_blocking) {
|
||||
TimeInterval timeout(_timeout);
|
||||
if (wait_writable(timeout) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int n = lwip_send(_sock_fd, data, length, 0);
|
||||
_is_connected = (n != 0);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// -1 if unsuccessful, else number of bytes written
|
||||
int TCPSocketConnection::send_all(char* data, int length) {
|
||||
if ((_sock_fd < 0) || !_is_connected)
|
||||
return -1;
|
||||
|
||||
int writtenLen = 0;
|
||||
TimeInterval timeout(_timeout);
|
||||
while (writtenLen < length) {
|
||||
if (!_blocking) {
|
||||
// Wait for socket to be writeable
|
||||
if (wait_writable(timeout) != 0)
|
||||
return writtenLen;
|
||||
}
|
||||
|
||||
int ret = lwip_send(_sock_fd, data + writtenLen, length - writtenLen, 0);
|
||||
if (ret > 0) {
|
||||
writtenLen += ret;
|
||||
continue;
|
||||
} else if (ret == 0) {
|
||||
_is_connected = false;
|
||||
return writtenLen;
|
||||
} else {
|
||||
return -1; //Connnection error
|
||||
}
|
||||
}
|
||||
return writtenLen;
|
||||
}
|
||||
|
||||
int TCPSocketConnection::receive(char* data, int length) {
|
||||
if ((_sock_fd < 0) || !_is_connected)
|
||||
return -1;
|
||||
|
||||
if (!_blocking) {
|
||||
TimeInterval timeout(_timeout);
|
||||
if (wait_readable(timeout) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int n = lwip_recv(_sock_fd, data, length, 0);
|
||||
_is_connected = (n != 0);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// -1 if unsuccessful, else number of bytes received
|
||||
int TCPSocketConnection::receive_all(char* data, int length) {
|
||||
if ((_sock_fd < 0) || !_is_connected)
|
||||
return -1;
|
||||
|
||||
int readLen = 0;
|
||||
TimeInterval timeout(_timeout);
|
||||
while (readLen < length) {
|
||||
if (!_blocking) {
|
||||
//Wait for socket to be readable
|
||||
if (wait_readable(timeout) != 0)
|
||||
return readLen;
|
||||
}
|
||||
|
||||
int ret = lwip_recv(_sock_fd, data + readLen, length - readLen, 0);
|
||||
if (ret > 0) {
|
||||
readLen += ret;
|
||||
} else if (ret == 0) {
|
||||
_is_connected = false;
|
||||
return readLen;
|
||||
} else {
|
||||
return -1; //Connnection error
|
||||
}
|
||||
}
|
||||
return readLen;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue