1
0
Fork 0

Squashed 'tmk_core/' changes from 7967731..b9e0ea0

b9e0ea0 Merge commit '7fa9d8bdea3773d1195b04d98fcf27cf48ddd81d' as 'tool/mbed/mbed-sdk'
7fa9d8b Squashed 'tool/mbed/mbed-sdk/' content from commit 7c21ce5

git-subtree-dir: tmk_core
git-subtree-split: b9e0ea08cb940de20b3610ecdda18e9d8cd7c552
This commit is contained in:
Jun Wako 2015-04-24 16:26:14 +09:00
parent a20ef7052c
commit 1fe4406f37
4198 changed files with 2016457 additions and 0 deletions

View file

@ -0,0 +1,78 @@
/* 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_ */

View file

@ -0,0 +1,902 @@
/* 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");
}
}

View file

@ -0,0 +1,153 @@
/* 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_ */

View file

@ -0,0 +1,59 @@
/* 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_ */

View file

@ -0,0 +1,95 @@
/* 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

View file

@ -0,0 +1,27 @@
/* 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_ */

View file

@ -0,0 +1,127 @@
/* 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);
}

View file

@ -0,0 +1,79 @@
/* 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_ */

View file

@ -0,0 +1,47 @@
/* 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_ */

View file

@ -0,0 +1,61 @@
/* 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_ */

View file

@ -0,0 +1,81 @@
/* 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;
}

View file

@ -0,0 +1,60 @@
/* 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_ */

View file

@ -0,0 +1,52 @@
/* 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();
}

View file

@ -0,0 +1,44 @@
/* 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_ */

View file

@ -0,0 +1,466 @@
/* 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");
}
}

View file

@ -0,0 +1,69 @@
/* 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_ */

View file

@ -0,0 +1,175 @@
/* 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;
}

View file

@ -0,0 +1,96 @@
/* 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_ */

View file

@ -0,0 +1,26 @@
/* 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_ */

View file

@ -0,0 +1,350 @@
/* 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;
}

View file

@ -0,0 +1,90 @@
/* 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_ */

View file

@ -0,0 +1,423 @@
/* 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;
}

View file

@ -0,0 +1,97 @@
/* 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_ */

View file

@ -0,0 +1,67 @@
/* 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_ */

View file

@ -0,0 +1,196 @@
/* 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
}

View file

@ -0,0 +1,80 @@
/* 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_ */

View file

@ -0,0 +1,253 @@
/* 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
}

View file

@ -0,0 +1,72 @@
/* 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_ */

View file

@ -0,0 +1,236 @@
/* 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
}
}

View file

@ -0,0 +1,74 @@
/* 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_ */

View file

@ -0,0 +1,114 @@
/* 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;
}

View file

@ -0,0 +1,63 @@
/* 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

View file

@ -0,0 +1,131 @@
/* 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;
}

View file

@ -0,0 +1,63 @@
/* 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

View file

@ -0,0 +1,559 @@
/* 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*/);
}

View file

@ -0,0 +1,183 @@
/* 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_ */

View file

@ -0,0 +1,398 @@
/* 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;
}

View file

@ -0,0 +1,118 @@
/* 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_ */

View file

@ -0,0 +1,605 @@
/* 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;
}

View file

@ -0,0 +1,155 @@
/* 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_ */

View file

@ -0,0 +1,156 @@
/* 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;
}

View file

@ -0,0 +1,90 @@
/* 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_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_ */

View file

@ -0,0 +1,41 @@
/* 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
void eth_arch_enable_interrupts(void);
void eth_arch_disable_interrupts(void);
err_t eth_arch_enetif_init(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif // #ifndef ETHARCHINTERFACE_H_

View file

@ -0,0 +1,469 @@
/*
* 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.
*/
/* Modified by mbed for the lwIP port */
#include "fsl_enet_driver.h"
#include "fsl_enet_hal.h"
#include "fsl_clock_manager.h"
#include "fsl_interrupt_manager.h"
#include <string.h>
#include "sys_arch.h"
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Define ENET's IRQ list */
void *enetIfHandle;
/*! @brief Define MAC driver API structure and for application of stack adaptor layer*/
const enet_mac_api_t g_enetMacApi =
{
enet_mac_init,
NULL, // enet_mac_deinit,
NULL, // enet_mac_send,
#if !ENET_RECEIVE_ALL_INTERRUPT
NULL, // enet_mac_receive,
#endif
enet_mii_read,
enet_mii_write,
NULL, // enet_mac_add_multicast_group,
NULL, //enet_mac_leave_multicast_group,
};
/*******************************************************************************
* Code
******************************************************************************/
// NOTE: we need these functions to be non-blocking fpr the PHY task, hence the
// osDelay() below
/*FUNCTION****************************************************************
*
* Function Name: enet_mii_read
* Return Value: The execution status.
* Description: Read function.
* This interface read data over the (R)MII bus from the specified PHY register,
* This function is called by all PHY interfaces.
*END*********************************************************************/
uint32_t enet_mii_read(uint32_t instance, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
{
uint32_t counter;
/* Check the input parameters*/
if (!dataPtr)
{
return kStatus_ENET_InvalidInput;
}
/* Check if the mii is enabled*/
if (!enet_hal_is_mii_enabled(instance))
{
return kStatus_ENET_Miiuninitialized;
}
/* Clear the MII interrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
/* Read command operation*/
enet_hal_set_mii_command(instance, phyAddr, phyReg, kEnetReadValidFrame, 0);
/* Poll for MII complete*/
for (counter = 0; counter < kEnetMaxTimeout; counter++)
{
if (enet_hal_get_interrupt_status(instance, kEnetMiiInterrupt))
{
break;
}
osDelay(1);
}
/* Check for timeout*/
if (counter == kEnetMaxTimeout)
{
return kStatus_ENET_TimeOut;
}
/* Get data from mii register*/
*dataPtr = enet_hal_get_mii_data(instance);
/* Clear MII interrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mii_write
* Return Value: The execution status.
* Description: Write function.
* This interface write data over the (R)MII bus to the specified PHY register.
* This function is called by all PHY interfaces.
*END*********************************************************************/
uint32_t enet_mii_write(uint32_t instance, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
{
uint32_t counter;
/* Check if the mii is enabled*/
if (!enet_hal_is_mii_enabled(instance))
{
return kStatus_ENET_Miiuninitialized;
}
/* Clear the MII interrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
/* Read command operation*/
enet_hal_set_mii_command(instance, phyAddr, phyReg, kEnetWriteValidFrame, data);
/* Poll for MII complete*/
for (counter = 0; counter < kEnetMaxTimeout; counter++)
{
if (enet_hal_get_interrupt_status(instance, kEnetMiiInterrupt))
{
break;
}
osDelay(1);
}
/* Check for timeout*/
if (counter == kEnetMaxTimeout)
{
return kStatus_ENET_TimeOut;
}
/* Clear MII intrrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_mii_init
* Return Value: The execution status.
* Description:Initialize the ENET Mac mii(mdc/mdio)interface.
*END*********************************************************************/
uint32_t enet_mac_mii_init(enet_dev_if_t * enetIfPtr)
{
uint32_t frequency;
/* Check the input parameters*/
if (enetIfPtr == NULL)
{
return kStatus_ENET_InvalidInput;
}
/* Configure mii speed*/
CLOCK_SYS_GetFreq(kSystemClock, &frequency);
enet_hal_config_mii(enetIfPtr->deviceNumber, (frequency/(2 * enetIfPtr->macCfgPtr->miiClock) + 1),
kEnetMdioHoldOneClkCycle, false);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_rxbd_init
* Return Value: The execution status.
* Description:Initialize the ENET receive buffer descriptors.
* Note: If you do receive on receive interrupt handler the receive
* data buffer number can be the same as the receive descriptor numbers.
* But if you are polling receive frames please make sure the receive data
* buffers are more than buffer descriptors to guarantee a good performance.
*END*********************************************************************/
uint32_t enet_mac_rxbd_init(enet_dev_if_t * enetIfPtr, enet_rxbd_config_t *rxbdCfg)
{
/* Check the input parameters*/
if ((!enetIfPtr) || (!rxbdCfg))
{
return kStatus_ENET_InvalidInput;
}
enetIfPtr->macContextPtr->bufferdescSize = enet_hal_get_bd_size();
/* Initialize the bd status*/
enetIfPtr->macContextPtr->isRxFull = false;
/* Initialize receive bd base address and current address*/
enetIfPtr->macContextPtr->rxBdBasePtr = rxbdCfg->rxBdPtrAlign;
enetIfPtr->macContextPtr->rxBdCurPtr = enetIfPtr->macContextPtr->rxBdBasePtr;
enetIfPtr->macContextPtr->rxBdDirtyPtr = enetIfPtr->macContextPtr->rxBdBasePtr;
enet_hal_set_rxbd_address(enetIfPtr->deviceNumber, (uint32_t)(enetIfPtr->macContextPtr->rxBdBasePtr));
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_txbd_init
* Return Value: The execution status.
* Description:Initialize the ENET transmit buffer descriptors.
* This function prepare all of the transmit buffer descriptors.
*END*********************************************************************/
uint32_t enet_mac_txbd_init(enet_dev_if_t * enetIfPtr, enet_txbd_config_t *txbdCfg)
{
/* Check the input parameters*/
if ((!enetIfPtr) || (!txbdCfg))
{
return kStatus_ENET_InvalidInput;
}
/* Initialize the bd status*/
enetIfPtr->macContextPtr->isTxFull = false;
/* Initialize transmit bd base address and current address*/
enetIfPtr->macContextPtr->txBdBasePtr = txbdCfg->txBdPtrAlign;
enetIfPtr->macContextPtr->txBdCurPtr = enetIfPtr->macContextPtr->txBdBasePtr;
enetIfPtr->macContextPtr->txBdDirtyPtr = enetIfPtr->macContextPtr->txBdBasePtr;
enet_hal_set_txbd_address(enetIfPtr->deviceNumber, (uint32_t)(enetIfPtr->macContextPtr->txBdBasePtr));
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_configure_fifo_accel
* Return Value: The execution status.
* Description: Configure the ENET FIFO and Accelerator.
*END*********************************************************************/
uint32_t enet_mac_configure_fifo_accel(enet_dev_if_t * enetIfPtr)
{
enet_config_rx_fifo_t rxFifo;
enet_config_tx_fifo_t txFifo;
/* Check the input parameters*/
if (!enetIfPtr)
{
return kStatus_ENET_InvalidInput;
}
/* Initialize values that will not be initialized later on */
rxFifo.rxEmpty = 0;
rxFifo.rxFull = 0;
txFifo.isStoreForwardEnabled = 0;
txFifo.txFifoWrite = 0;
txFifo.txEmpty = 0;
/* Configure tx/rx accelerator*/
if (enetIfPtr->macCfgPtr->isRxAccelEnabled)
{
enet_hal_config_rx_accelerator(enetIfPtr->deviceNumber,
(enet_config_rx_accelerator_t *)&(enetIfPtr->macCfgPtr->rxAcceler));
if ((enetIfPtr->macCfgPtr->rxAcceler.isIpcheckEnabled) || (enetIfPtr->macCfgPtr->rxAcceler.isProtocolCheckEnabled))
{
rxFifo.rxFull = 0;
}
}
if (enetIfPtr->macCfgPtr->isTxAccelEnabled)
{
enet_hal_config_tx_accelerator(enetIfPtr->deviceNumber,
(enet_config_tx_accelerator_t *)&(enetIfPtr->macCfgPtr->txAcceler));
if ((enetIfPtr->macCfgPtr->txAcceler.isIpCheckEnabled) || (enetIfPtr->macCfgPtr->txAcceler.isProtocolCheckEnabled))
{
txFifo.isStoreForwardEnabled = 1;
}
}
if (enetIfPtr->macCfgPtr->isStoreAndFwEnabled)
{
rxFifo.rxFull = 0;
txFifo.isStoreForwardEnabled = 1;
}
/* Set TFWR value if STRFWD is not being used */
if (txFifo.isStoreForwardEnabled == 1)
txFifo.txFifoWrite = 0;
else
/* TFWR value is a trade-off between transmit latency and risk of transmit FIFO underrun due to contention for the system bus
TFWR = 15 means transmission will begin once 960 bytes has been written to the Tx FIFO (for frames larger than 960 bytes)
See Section 45.4.18 - Transmit FIFO Watermark Register of the K64F Reference Manual for details */
txFifo.txFifoWrite = 15;
/* Configure tx/rx FIFO with default value*/
rxFifo.rxAlmostEmpty = 4;
rxFifo.rxAlmostFull = 4;
txFifo.txAlmostEmpty = 4;
txFifo.txAlmostFull = 8;
enet_hal_config_rx_fifo(enetIfPtr->deviceNumber, &rxFifo);
enet_hal_config_tx_fifo(enetIfPtr->deviceNumber, &txFifo);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_configure_controller
* Return Value: The execution status.
* Description: Configure the ENET controller with the basic configuration.
*END*********************************************************************/
uint32_t enet_mac_configure_controller(enet_dev_if_t * enetIfPtr)
{
uint32_t macCtlCfg;
/* Check the input parameters*/
if (enetIfPtr == NULL)
{
return kStatus_ENET_InvalidInput;
}
macCtlCfg = enetIfPtr->macCfgPtr->macCtlConfigure;
/* Configure rmii/mii interface*/
enet_hal_config_rmii(enetIfPtr->deviceNumber, enetIfPtr->macCfgPtr->rmiiCfgMode,
enetIfPtr->macCfgPtr->speed, enetIfPtr->macCfgPtr->duplex, false,
(macCtlCfg & kEnetRxMiiLoopback));
/* Configure receive buffer size*/
if (enetIfPtr->macCfgPtr->isVlanEnabled)
{
enetIfPtr->maxFrameSize = kEnetMaxFrameVlanSize;
enet_hal_set_rx_max_size(enetIfPtr->deviceNumber,
enetIfPtr->macContextPtr->rxBufferSizeAligned, kEnetMaxFrameVlanSize);
}
else
{
enetIfPtr->maxFrameSize = kEnetMaxFrameSize;
enet_hal_set_rx_max_size(enetIfPtr->deviceNumber,
enetIfPtr->macContextPtr->rxBufferSizeAligned, kEnetMaxFrameSize);
}
/* Set receive controller promiscuous */
enet_hal_config_promiscuous(enetIfPtr->deviceNumber, macCtlCfg & kEnetRxPromiscuousEnable);
/* Set receive flow control*/
enet_hal_enable_flowcontrol(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxFlowControlEnable));
/* Set received PAUSE frames are forwarded/terminated*/
enet_hal_enable_pauseforward(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxPauseFwdEnable));
/* Set receive broadcast frame reject*/
enet_hal_enable_broadcastreject(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxBcRejectEnable));
/* Set padding is removed from the received frame*/
enet_hal_enable_padremove(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxPadRemoveEnable));
/* Set the crc of the received frame is stripped from the frame*/
enet_hal_enable_rxcrcforward(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxCrcFwdEnable));
/* Set receive payload length check*/
enet_hal_enable_payloadcheck(enetIfPtr->deviceNumber, (macCtlCfg & kEnetPayloadlenCheckEnable));
/* Set control sleep mode*/
enet_hal_enable_sleep(enetIfPtr->deviceNumber, (macCtlCfg & kEnetSleepModeEnable));
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_init
* Return Value: The execution status.
* Description:Initialize the ENET device with the basic configuration
* When ENET is used, this function need to be called by the NET initialize
* interface.
*END*********************************************************************/
uint32_t enet_mac_init(enet_dev_if_t * enetIfPtr, enet_rxbd_config_t *rxbdCfg,
enet_txbd_config_t *txbdCfg)
{
uint32_t timeOut = 0;
uint32_t devNumber, result = 0;
/* Check the input parameters*/
if (enetIfPtr == NULL)
{
return kStatus_ENET_InvalidInput;
}
/* Get device number and check the parameter*/
devNumber = enetIfPtr->deviceNumber;
/* Store the global ENET structure for ISR input parameters */
enetIfHandle = enetIfPtr;
/* Turn on ENET module clock gate */
CLOCK_SYS_EnableEnetClock(0U);
/* Reset ENET mac*/
enet_hal_reset_ethernet(devNumber);
while ((!enet_hal_is_reset_completed(devNumber)) && (timeOut < kEnetMaxTimeout))
{
time_delay(1);
timeOut++;
}
/* Check out if timeout*/
if (timeOut == kEnetMaxTimeout)
{
return kStatus_ENET_TimeOut;
}
/* Disable all ENET mac interrupt and Clear all interrupt events*/
enet_hal_config_interrupt(devNumber, kEnetAllInterrupt, false);
enet_hal_clear_interrupt(devNumber, kEnetAllInterrupt);
/* Program this station's physical address*/
enet_hal_set_mac_address(devNumber, enetIfPtr->macCfgPtr->macAddr);
/* Clear group and individual hash register*/
enet_hal_set_group_hashtable(devNumber, 0, kEnetSpecialAddressInit);
enet_hal_set_individual_hashtable(devNumber, 0, kEnetSpecialAddressInit);
/* Configure mac controller*/
result = enet_mac_configure_controller(enetIfPtr);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Clear mib zero counters*/
enet_hal_clear_mib(devNumber, true);
/* Initialize FIFO and accelerator*/
result = enet_mac_configure_fifo_accel(enetIfPtr);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Initialize receive buffer descriptors*/
result = enet_mac_rxbd_init(enetIfPtr, rxbdCfg);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Initialize transmit buffer descriptors*/
result = enet_mac_txbd_init(enetIfPtr, txbdCfg);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Initialize rmii/mii interface*/
result = enet_mac_mii_init(enetIfPtr);
if (result != kStatus_ENET_Success)
{
return result;
}
return kStatus_ENET_Success;
}
/*******************************************************************************
* EOF
******************************************************************************/

View file

@ -0,0 +1,93 @@
/*
* 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_hal.h"
#include "fsl_clock_manager.h"
#include "fsl_device_registers.h"
#include "fsl_sim_hal.h"
/*******************************************************************************
* Code
******************************************************************************/
void k64f_init_eth_hardware(void)
{
uint8_t count;
/* Disable the mpu*/
BW_MPU_CESR_VLD(MPU_BASE, 0);
/* Open POTR clock gate*/
for (count = 0; count < HW_PORT_INSTANCE_COUNT; count++)
{
CLOCK_SYS_EnablePortClock(count);
}
/* Configure gpio*/
PORT_HAL_SetMuxMode(PORTA_BASE, 12, kPortMuxAlt4); /*!< ENET RMII0_RXD1/MII0_RXD1*/
PORT_HAL_SetMuxMode(PORTA_BASE, 13, kPortMuxAlt4); /*!< ENET RMII0_RXD0/MII0_RXD0*/
PORT_HAL_SetMuxMode(PORTA_BASE, 14, kPortMuxAlt4); /*!< ENET RMII0_CRS_DV/MII0_RXDV*/
PORT_HAL_SetMuxMode(PORTA_BASE, 15, kPortMuxAlt4); /*!< ENET RMII0_TXEN/MII0_TXEN*/
PORT_HAL_SetMuxMode(PORTA_BASE, 16, kPortMuxAlt4); /*!< ENET RMII0_TXD0/MII0_TXD0*/
PORT_HAL_SetMuxMode(PORTA_BASE, 17, kPortMuxAlt4); /*!< ENET RMII0_TXD01/MII0_TXD1*/
PORT_HAL_SetMuxMode(PORTB_BASE, 0, kPortMuxAlt4); /*!< ENET RMII0_MDIO/MII0_MDIO*/
PORT_HAL_SetOpenDrainCmd(PORTB_BASE,0, true); /*!< ENET RMII0_MDC/MII0_MDC*/
// Added for FRDM-K64F
PORT_HAL_SetPullMode(PORTB_BASE, 0, kPortPullUp);
PORT_HAL_SetPullCmd(PORTB_BASE, 0, true);
PORT_HAL_SetMuxMode(PORTB_BASE, 1, kPortMuxAlt4);
/* Configure GPIO for MII interface */
PORT_HAL_SetMuxMode(PORTA_BASE, 9, kPortMuxAlt4); /*!< ENET MII0_RXD3*/
PORT_HAL_SetMuxMode(PORTA_BASE, 10, kPortMuxAlt4); /*!< ENET MII0_RXD2*/
PORT_HAL_SetMuxMode(PORTA_BASE, 11, kPortMuxAlt4); /*!< ENET MII0_RXCLK*/
PORT_HAL_SetMuxMode(PORTA_BASE, 24, kPortMuxAlt4); /*!< ENET MII0_TXD2*/
PORT_HAL_SetMuxMode(PORTA_BASE, 25, kPortMuxAlt4); /*!< ENET MII0_TXCLK*/
PORT_HAL_SetMuxMode(PORTA_BASE, 26, kPortMuxAlt4); /*!< ENET MII0_TXD3*/
PORT_HAL_SetMuxMode(PORTA_BASE, 27, kPortMuxAlt4); /*!< ENET MII0_CRS*/
PORT_HAL_SetMuxMode(PORTA_BASE, 28, kPortMuxAlt4); /*!< ENET MII0_TXER*/
PORT_HAL_SetMuxMode(PORTA_BASE, 29, kPortMuxAlt4); /*!< ENET MII0_COL*/
#if FSL_FEATURE_ENET_SUPPORT_PTP
PORT_HAL_SetMuxMode(PORTC_BASE, (16 + ENET_TIMER_CHANNEL_NUM), kPortMuxAlt4); /* ENET ENET0_1588_TMR0*/
PORT_HAL_SetDriveStrengthMode(PORTC_BASE, (16 + ENET_TIMER_CHANNEL_NUM), kPortHighDriveStrength);
#endif
/* Open ENET clock gate*/
CLOCK_SYS_EnableEnetClock( 0U);
/* Select the ptp timer outclk*/
CLOCK_HAL_SetSource(g_simBaseAddr[0], kClockTimeSrc, 2);
}
/*******************************************************************************
* EOF
******************************************************************************/

View file

@ -0,0 +1,885 @@
#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_enet_driver.h"
#include "fsl_enet_hal.h"
#include "fsl_device_registers.h"
#include "fsl_phy_driver.h"
#include "fsl_interrupt_manager.h"
#include "k64f_emac_config.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mbed_interface.h"
extern IRQn_Type enet_irq_ids[HW_ENET_INSTANCE_COUNT][FSL_FEATURE_ENET_INTERRUPT_COUNT];
extern uint8_t enetIntMap[kEnetIntNum];
extern void *enetIfHandle;
/********************************************************************************
* Internal data
********************************************************************************/
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 */
volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
struct pbuf *rxb[ENET_RX_RING_LEN]; /**< RX pbuf pointer list, zero-copy mode */
uint8_t *rx_desc_start_addr; /**< RX descriptor start address */
uint8_t *tx_desc_start_addr; /**< TX descriptor start address */
uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */
uint8_t rx_fill_index; /**< RX ring fill index */
struct pbuf *txb[ENET_TX_RING_LEN]; /**< TX pbuf pointer list, zero-copy mode */
void *txb_aligned[ENET_TX_RING_LEN]; /**< TX aligned buffers (if needed) */
};
static struct k64f_enetdata k64f_enetdata;
static enet_dev_if_t enetDevIf[HW_ENET_INSTANCE_COUNT];
static enet_mac_config_t g_enetMacCfg[HW_ENET_INSTANCE_COUNT] =
{
{
ENET_ETH_MAX_FLEN , /*!< enet receive buffer size*/
ENET_RX_LARGE_BUFFER_NUM, /*!< enet large receive buffer number*/
ENET_RX_RING_LEN, /*!< enet receive bd number*/
ENET_TX_RING_LEN, /*!< enet transmit bd number*/
{0}, /*!< enet mac address*/
kEnetCfgRmii, /*!< enet rmii interface*/
kEnetCfgSpeed100M, /*!< enet rmii 100M*/
kEnetCfgFullDuplex, /*!< enet rmii Full- duplex*/
/*!< enet mac control flag recommended to use enet_mac_control_flag_t
we send frame with crc so receive crc forward for data length check test*/
kEnetRxCrcFwdEnable | kEnetRxFlowControlEnable,
true, /*!< enet txaccelerator enabled*/
true, /*!< enet rxaccelerator enabled*/
false, /*!< enet store and forward*/
{false, false, true, false, true}, /*!< enet rxaccelerator config*/
{false, false, true}, /*!< enet txaccelerator config*/
true, /*!< vlan frame support*/
true, /*!< phy auto discover*/
ENET_MII_CLOCK, /*!< enet MDC clock*/
},
};
static enet_phy_config_t g_enetPhyCfg[HW_ENET_INSTANCE_COUNT] =
{
{0, false}
};
/** \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)
/** \brief Debug output formatter lock define
*
* When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
* define will allow RX debug messages to not interleave with the
* TX messages (so they are actually readable). Not enabling this
* define when the system is under load will cause the output to
* be unreadable. There is a small tradeoff in performance for this
* so use it only for debug. */
//#define LOCK_RX_THREAD
/** \brief Signal used for ethernet ISR to signal packet_rx() thread.
*/
#define RX_SIGNAL 1
// K64F-specific macros
#define RX_PBUF_AUTO_INDEX (-1)
/********************************************************************************
* Buffer management
********************************************************************************/
/** \brief Queues a pbuf into the RX descriptor list
*
* \param[in] k64f_enet Pointer to the drvier data structure
* \param[in] p Pointer to pbuf to queue
* \param[in] bidx Index to queue into
*/
static void k64f_rxqueue_pbuf(struct k64f_enetdata *k64f_enet, struct pbuf *p, int bidx)
{
enet_bd_struct_t *start = (enet_bd_struct_t *)k64f_enet->rx_desc_start_addr;
int idx;
/* Get next free descriptor index */
if (bidx == RX_PBUF_AUTO_INDEX)
idx = k64f_enet->rx_fill_index;
else
idx = bidx;
/* Setup descriptor and clear statuses */
enet_hal_init_rxbds(start + idx, (uint8_t*)p->payload, idx == ENET_RX_RING_LEN - 1);
/* Save pbuf pointer for push to network layer later */
k64f_enet->rxb[idx] = p;
/* Wrap at end of descriptor list */
idx = (idx + 1) % ENET_RX_RING_LEN;
/* Queue descriptor(s) */
k64f_enet->rx_free_descs -= 1;
if (bidx == RX_PBUF_AUTO_INDEX)
k64f_enet->rx_fill_index = idx;
enet_hal_active_rxbd(BOARD_DEBUG_ENET_INSTANCE_ADDR);
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
k64f_enet->rx_free_descs));
}
/** \brief Attempt to allocate and requeue a new pbuf for RX
*
* \param[in] netif Pointer to the netif structure
* \returns number of queued packets
*/
s32_t k64f_rx_queue(struct netif *netif, int idx)
{
struct k64f_enetdata *k64f_enet = netif->state;
enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
struct pbuf *p;
int queued = 0;
/* Attempt to requeue as many packets as possible */
while (k64f_enet->rx_free_descs > 0) {
/* Allocate a pbuf from the pool. We need to allocate at the
maximum size as we don't know the size of the yet to be
received packet. */
p = pbuf_alloc(PBUF_RAW, enetIfPtr->macCfgPtr->rxBufferSize + RX_BUF_ALIGNMENT, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
k64f_enet->rx_free_descs));
return queued;
}
/* 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 */
p->payload = (void*)ENET_ALIGN((uint32_t)p->payload, RX_BUF_ALIGNMENT);
/* pbufs allocated from the RAM pool should be non-chained. */
LWIP_ASSERT("k64f_rx_queue: pbuf is not contiguous (chained)", pbuf_clen(p) <= 1);
/* Queue packet */
k64f_rxqueue_pbuf(k64f_enet, p, idx);
queued++;
}
return queued;
}
/** \brief Sets up the RX descriptor ring buffers.
*
* This function sets up the descriptor list used for receive packets.
*
* \param[in] netif Pointer to driver data structure
* \returns ERR_MEM if out of memory, ERR_OK otherwise
*/
static err_t k64f_rx_setup(struct netif *netif, enet_rxbd_config_t *rxbdCfg) {
struct k64f_enetdata *k64f_enet = netif->state;
enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
uint8_t *rxBdPtr;
uint32_t rxBufferSizeAligned;
// Allocate RX descriptors
rxBdPtr = (uint8_t *)calloc(1, enet_hal_get_bd_size() * enetIfPtr->macCfgPtr->rxBdNumber + ENET_BD_ALIGNMENT);
if(!rxBdPtr)
return ERR_MEM;
k64f_enet->rx_desc_start_addr = (uint8_t *)ENET_ALIGN((uint32_t)rxBdPtr, ENET_BD_ALIGNMENT);
k64f_enet->rx_free_descs = enetIfPtr->macCfgPtr->rxBdNumber;
k64f_enet->rx_fill_index = 0;
rxBufferSizeAligned = ENET_ALIGN(enetIfPtr->macCfgPtr->rxBufferSize, ENET_RX_BUFFER_ALIGNMENT);
enetIfPtr->macContextPtr->rxBufferSizeAligned = rxBufferSizeAligned;
rxbdCfg->rxBdPtrAlign = k64f_enet->rx_desc_start_addr;
rxbdCfg->rxBdNum = enetIfPtr->macCfgPtr->rxBdNumber;
rxbdCfg->rxBufferNum = enetIfPtr->macCfgPtr->rxBdNumber;
k64f_rx_queue(netif, RX_PBUF_AUTO_INDEX);
return ERR_OK;
}
/** \brief Sets up the TX descriptor ring buffers.
*
* This function sets up the descriptor list used for transmit packets.
*
* \param[in] netif Pointer to driver data structure
* \returns ERR_MEM if out of memory, ERR_OK otherwise
*/
static err_t k64f_tx_setup(struct netif *netif, enet_txbd_config_t *txbdCfg) {
struct k64f_enetdata *k64f_enet = netif->state;
enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
uint8_t *txBdPtr;
// Allocate TX descriptors
txBdPtr = (uint8_t *)calloc(1, enet_hal_get_bd_size() * enetIfPtr->macCfgPtr->txBdNumber + ENET_BD_ALIGNMENT);
if(!txBdPtr)
return ERR_MEM;
k64f_enet->tx_desc_start_addr = (uint8_t *)ENET_ALIGN((uint32_t)txBdPtr, ENET_BD_ALIGNMENT);
k64f_enet->tx_consume_index = k64f_enet->tx_produce_index = 0;
txbdCfg->txBdPtrAlign = k64f_enet->tx_desc_start_addr;
txbdCfg->txBufferNum = enetIfPtr->macCfgPtr->txBdNumber;
txbdCfg->txBufferSizeAlign = ENET_ALIGN(enetIfPtr->maxFrameSize, ENET_TX_BUFFER_ALIGNMENT);
// Make the TX descriptor ring circular
enet_hal_init_txbds(k64f_enet->tx_desc_start_addr + enet_hal_get_bd_size() * (ENET_TX_RING_LEN - 1), 1);
return ERR_OK;
}
/** \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;
volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t *)k64f_enet->tx_desc_start_addr;
/* Get exclusive access */
sys_mutex_lock(&k64f_enet->TXLockMutex);
// Traverse all descriptors, looking for the ones modified by the uDMA
i = k64f_enet->tx_consume_index;
while(i != k64f_enet->tx_produce_index && !(bdPtr[i].control & kEnetTxBdReady)) {
if (k64f_enet->txb_aligned[i]) {
free(k64f_enet->txb_aligned[i]);
k64f_enet->txb_aligned[i] = NULL;
} else if (k64f_enet->txb[i]) {
pbuf_free(k64f_enet->txb[i]);
k64f_enet->txb[i] = NULL;
}
osSemaphoreRelease(k64f_enet->xTXDCountSem.id);
bdPtr[i].controlExtend2 &= ~TX_DESC_UPDATED_MASK;
i = (i + 1) % ENET_TX_RING_LEN;
}
k64f_enet->tx_consume_index = i;
/* Restore access */
sys_mutex_unlock(&k64f_enet->TXLockMutex);
}
/** \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)
{
enet_dev_if_t * enetIfPtr;
uint32_t device = BOARD_DEBUG_ENET_INSTANCE_ADDR;
enet_rxbd_config_t rxbdCfg;
enet_txbd_config_t txbdCfg;
enet_phy_speed_t phy_speed;
enet_phy_duplex_t phy_duplex;
k64f_init_eth_hardware();
/* Initialize device*/
enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
enetIfPtr->deviceNumber = device;
enetIfPtr->macCfgPtr = &g_enetMacCfg[BOARD_DEBUG_ENET_INSTANCE];
enetIfPtr->phyCfgPtr = &g_enetPhyCfg[BOARD_DEBUG_ENET_INSTANCE];
enetIfPtr->macApiPtr = &g_enetMacApi;
enetIfPtr->phyApiPtr = (void *)&g_enetPhyApi;
memcpy(enetIfPtr->macCfgPtr->macAddr, (char*)netif->hwaddr, kEnetMacAddrLen);
/* Allocate buffer for ENET mac context*/
enetIfPtr->macContextPtr = (enet_mac_context_t *)calloc(1, sizeof(enet_mac_context_t));
if (!enetIfPtr->macContextPtr) {
return ERR_BUF;
}
/* Initialize enet buffers*/
if(k64f_rx_setup(netif, &rxbdCfg) != ERR_OK) {
return ERR_BUF;
}
/* Initialize enet buffers*/
if(k64f_tx_setup(netif, &txbdCfg) != ERR_OK) {
return ERR_BUF;
}
/* Initialize enet module*/
if (enet_mac_init(enetIfPtr, &rxbdCfg, &txbdCfg) == kStatus_ENET_Success)
{
/* Initialize PHY*/
if (enetIfPtr->macCfgPtr->isPhyAutoDiscover) {
if (((enet_phy_api_t *)(enetIfPtr->phyApiPtr))->phy_auto_discover(enetIfPtr) != kStatus_PHY_Success)
return ERR_IF;
}
if (((enet_phy_api_t *)(enetIfPtr->phyApiPtr))->phy_init(enetIfPtr) != kStatus_PHY_Success)
return ERR_IF;
enetIfPtr->isInitialized = true;
}
else
{
// TODOETH: cleanup memory
return ERR_IF;
}
/* Get link information from PHY */
phy_get_link_speed(enetIfPtr, &phy_speed);
phy_get_link_duplex(enetIfPtr, &phy_duplex);
BW_ENET_RCR_RMII_10T(enetIfPtr->deviceNumber, phy_speed == kEnetSpeed10M ? kEnetCfgSpeed10M : kEnetCfgSpeed100M);
BW_ENET_TCR_FDEN(enetIfPtr->deviceNumber, phy_duplex == kEnetFullDuplex ? kEnetCfgFullDuplex : kEnetCfgHalfDuplex);
/* Enable Ethernet module*/
enet_hal_config_ethernet(BOARD_DEBUG_ENET_INSTANCE_ADDR, true, true);
/* Active Receive buffer descriptor must be done after module enable*/
enet_hal_active_rxbd(enetIfPtr->deviceNumber);
return ERR_OK;
}
/********************************************************************************
* LWIP port
********************************************************************************/
/** \brief Ethernet receive interrupt handler
*
* This function handles the receive interrupt of K64F.
*/
void enet_mac_rx_isr(void *enetIfPtr)
{
/* Clear interrupt */
enet_hal_clear_interrupt(((enet_dev_if_t *)enetIfPtr)->deviceNumber, kEnetRxFrameInterrupt);
sys_sem_signal(&k64f_enetdata.RxReadySem);
}
void enet_mac_tx_isr(void *enetIfPtr)
{
/*Clear interrupt*/
enet_hal_clear_interrupt(((enet_dev_if_t *)enetIfPtr)->deviceNumber, kEnetTxFrameInterrupt);
sys_sem_signal(&k64f_enetdata.TxCleanSem);
}
/**
* 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)
{
struct k64f_enetdata *k64f_enet = netif->state;
enet_bd_struct_t * bdPtr = (enet_bd_struct_t*)k64f_enet->rx_desc_start_addr;
struct pbuf *p = NULL;
u32_t length = 0, orig_length;
const u16_t err_mask = kEnetRxBdTrunc | kEnetRxBdCrc | kEnetRxBdNoOctet | kEnetRxBdLengthViolation;
#ifdef LOCK_RX_THREAD
/* Get exclusive access */
sys_mutex_lock(&k64f_enet->TXLockMutex);
#endif
/* Determine if a frame has been received */
if ((bdPtr[idx].control & err_mask) != 0) {
#if LINK_STATS
if ((bdPtr[idx].control & kEnetRxBdLengthViolation) != 0)
LINK_STATS_INC(link.lenerr);
else
LINK_STATS_INC(link.chkerr);
#endif
LINK_STATS_INC(link.drop);
/* Re-queue the same buffer */
k64f_enet->rx_free_descs++;
p = k64f_enet->rxb[idx];
k64f_enet->rxb[idx] = NULL;
k64f_rxqueue_pbuf(k64f_enet, p, idx);
p = NULL;
} else {
/* A packet is waiting, get length */
length = enet_hal_get_bd_length(bdPtr + idx);
/* Zero-copy */
p = k64f_enet->rxb[idx];
orig_length = p->len;
p->len = (u16_t) length;
/* Free pbuf from descriptor */
k64f_enet->rxb[idx] = NULL;
k64f_enet->rx_free_descs++;
/* Attempt to queue new buffer */
if (k64f_rx_queue(netif, idx) == 0) {
/* Drop frame (out of memory) */
LINK_STATS_INC(link.drop);
/* Re-queue the same buffer */
p->len = orig_length;
k64f_rxqueue_pbuf(k64f_enet, p, idx);
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;
}
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;
volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t*)k64f_enet->rx_desc_start_addr;
int idx = 0;
while (1) {
/* Wait for receive task to wakeup */
sys_arch_sem_wait(&k64f_enet->RxReadySem, 0);
if ((bdPtr[idx].control & kEnetRxBdEmpty) == 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);
// TODOETH: handle TX underrun?
k64f_tx_reclaim(k64f_enet);
}
}
/** \brief Polls if an available TX descriptor is ready. Can be used to
* determine if the low level transmit function will block.
*
* \param[in] netif the lwip network interface structure
* \return 0 if no descriptors are read, or >0
*/
s32_t k64f_tx_ready(struct netif *netif)
{
struct k64f_enetdata *k64f_enet = netif->state;
s32_t fb;
u32_t idx, cidx;
cidx = k64f_enet->tx_consume_index;
idx = k64f_enet->tx_produce_index;
/* Determine number of free buffers */
if (idx == cidx)
fb = ENET_TX_RING_LEN;
else if (cidx > idx)
fb = (ENET_TX_RING_LEN - 1) -
((idx + ENET_TX_RING_LEN) - cidx);
else
fb = (ENET_TX_RING_LEN - 1) - (cidx - idx);
return fb;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_hal_update_txbds
* Description: Update ENET transmit buffer descriptors.
*END*********************************************************************/
void k64f_update_txbds(struct k64f_enetdata *k64f_enet, int idx, uint8_t *buffer, uint16_t length, bool isLast)
{
volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t *)(k64f_enet->tx_desc_start_addr + idx * enet_hal_get_bd_size());
bdPtr->length = HTONS(length); /* Set data length*/
bdPtr->buffer = (uint8_t *)HTONL((uint32_t)buffer); /* Set data buffer*/
if (isLast)
bdPtr->control |= kEnetTxBdLast;
else
bdPtr->control &= ~kEnetTxBdLast;
bdPtr->controlExtend1 |= kEnetTxBdTxInterrupt;
bdPtr->controlExtend2 &= ~TX_DESC_UPDATED_MASK; // descriptor not updated by DMA
bdPtr->control |= kEnetTxBdTransmitCrc | kEnetTxBdReady;
}
/** \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;
u32_t idx;
s32_t dn;
uint8_t *psend = NULL, *dst;
/* Get free TX buffer index */
idx = k64f_enet->tx_produce_index;
/* Check the pbuf chain for payloads that are not 8-byte aligned.
If found, a new properly aligned buffer needs to be allocated
and the data copied there */
for (q = p; q != NULL; q = q->next)
if (((u32_t)q->payload & (TX_BUF_ALIGNMENT - 1)) != 0)
break;
if (q != NULL) {
// Allocate properly aligned buffer
psend = (uint8_t*)malloc(p->tot_len);
if (NULL == psend)
return ERR_MEM;
LWIP_ASSERT("k64f_low_level_output: buffer not properly aligned", ((u32_t)psend & (TX_BUF_ALIGNMENT - 1)) == 0);
for (q = p, dst = psend; q != NULL; q = q->next) {
MEMCPY(dst, q->payload, q->len);
dst += q->len;
}
k64f_enet->txb_aligned[idx] = psend;
dn = 1;
} else {
k64f_enet->txb_aligned[idx] = NULL;
dn = (s32_t) pbuf_clen(p);
pbuf_ref(p);
}
/* Wait until enough descriptors are available for the transfer. */
/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
while (dn > k64f_tx_ready(netif))
osSemaphoreWait(k64f_enet->xTXDCountSem.id, osWaitForever);
/* Get exclusive access */
sys_mutex_lock(&k64f_enet->TXLockMutex);
/* Setup transfers */
q = p;
while (dn > 0) {
dn--;
if (psend != NULL) {
k64f_update_txbds(k64f_enet, idx, psend, p->tot_len, 1);
k64f_enet->txb[idx] = NULL;
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_low_level_output: aligned packet(%p) sent"
" size = %d (index=%d)\n", psend, p->tot_len, idx));
} else {
LWIP_ASSERT("k64f_low_level_output: buffer not properly aligned", ((u32_t)q->payload & 0x07) == 0);
/* Only save pointer to free on last descriptor */
if (dn == 0) {
/* Save size of packet and signal it's ready */
k64f_update_txbds(k64f_enet, idx, q->payload, q->len, 1);
k64f_enet->txb[idx] = p;
}
else {
/* Save size of packet, descriptor is not last */
k64f_update_txbds(k64f_enet, idx, q->payload, q->len, 0);
k64f_enet->txb[idx] = NULL;
}
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_low_level_output: pbuf packet(%p) sent, chain#=%d,"
" size = %d (index=%d)\n", q->payload, dn, q->len, idx));
}
q = q->next;
idx = (idx + 1) % ENET_TX_RING_LEN;
}
k64f_enet->tx_produce_index = idx;
enet_hal_active_txbd(BOARD_DEBUG_ENET_INSTANCE_ADDR);
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;
enet_phy_speed_t speed;
enet_phy_duplex_t duplex;
} PHY_STATE;
int phy_link_status() {
bool connection_status;
enet_dev_if_t * enetIfPtr = (enet_dev_if_t*)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
phy_get_link_status(enetIfPtr, &connection_status);
return (int)connection_status;
}
static void k64f_phy_task(void *data) {
struct netif *netif = (struct netif*)data;
bool connection_status;
enet_dev_if_t * enetIfPtr = (enet_dev_if_t*)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
PHY_STATE crt_state = {STATE_UNKNOWN, (enet_phy_speed_t)STATE_UNKNOWN, (enet_phy_duplex_t)STATE_UNKNOWN};
PHY_STATE prev_state;
prev_state = crt_state;
while (true) {
// Get current status
phy_get_link_status(enetIfPtr, &connection_status);
crt_state.connected = connection_status ? 1 : 0;
phy_get_link_speed(enetIfPtr, &crt_state.speed);
phy_get_link_duplex(enetIfPtr, &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)
BW_ENET_RCR_RMII_10T(enetIfPtr->deviceNumber, crt_state.speed == kEnetSpeed10M ? kEnetCfgSpeed10M : kEnetCfgSpeed100M);
// TODO: duplex change requires disable/enable of Ethernet interface, to be implemented
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) {
enet_hal_config_interrupt(BOARD_DEBUG_ENET_INSTANCE_ADDR, (kEnetTxFrameInterrupt | kEnetRxFrameInterrupt), true);
INT_SYS_EnableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetRxfInt]]);
INT_SYS_EnableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetTxfInt]]);
}
void eth_arch_disable_interrupts(void) {
INT_SYS_DisableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetRxfInt]]);
INT_SYS_DisableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetTxfInt]]);
}
void ENET_Transmit_IRQHandler(void)
{
enet_mac_tx_isr(enetIfHandle);
}
void ENET_Receive_IRQHandler(void)
{
enet_mac_rx_isr(enetIfHandle);
}
#if FSL_FEATURE_ENET_SUPPORT_PTP
void ENET_1588_Timer_IRQHandler(void)
{
enet_mac_ts_isr(enetIfHandle);
}
#endif
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */

View file

@ -0,0 +1,58 @@
/*
* 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__
#define ENET_RX_RING_LEN (16)
#define ENET_TX_RING_LEN (8)
#define ENET_RX_LARGE_BUFFER_NUM (0)
#define ENET_RX_BUFFER_ALIGNMENT (16)
#define ENET_TX_BUFFER_ALIGNMENT (16)
#define ENET_BD_ALIGNMENT (16)
#define ENET_MII_CLOCK (2500000L)
#define RX_BUF_ALIGNMENT (16)
#define TX_BUF_ALIGNMENT (8)
#define BOARD_DEBUG_ENET_INSTANCE (0)
#define BOARD_DEBUG_ENET_INSTANCE_ADDR (ENET_BASE)
#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__

View file

@ -0,0 +1,29 @@
/* 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 + RX_BUF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,661 @@
/**********************************************************************
* $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 ------------------------------ */

View file

@ -0,0 +1,111 @@
/**********************************************************************
* $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 ------------------------------ */

View file

@ -0,0 +1,151 @@
/**********************************************************************
* $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 ------------------------------ */

View file

@ -0,0 +1,438 @@
/**********************************************************************
* $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 ------------------------------ */

View file

@ -0,0 +1,30 @@
/* 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
#endif

View file

@ -0,0 +1,26 @@
/* 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

View file

@ -0,0 +1,192 @@
#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;
struct pbuf *q;
while (1) {
sys_arch_sem_wait(&recv_ready_sem, 0);
recv_size = ethernet_receive();
if (recv_size != 0) {
p = pbuf_alloc(PBUF_RAW, recv_size, PBUF_POOL);
if (p != NULL) {
for (q = p; q != NULL; q = q->next) {
(void)ethernet_read((char *)q->payload, q->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;
}
}
}
}
}
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(&ethcfg);
/* 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);
}

View file

@ -0,0 +1,26 @@
/* 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

View file

@ -0,0 +1,560 @@
#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, &regvalue);
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, &regvalue);
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 ------------------------------ */

View file

@ -0,0 +1,24 @@
#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());
}

View file

@ -0,0 +1,29 @@
#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

View file

@ -0,0 +1,163 @@
#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();
}

View file

@ -0,0 +1,56 @@
#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

View file

@ -0,0 +1,460 @@
/*
* 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

View file

@ -0,0 +1,99 @@
/*
* 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

View file

@ -0,0 +1,133 @@
/*
* 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

View file

@ -0,0 +1,229 @@
/*
* 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

View file

@ -0,0 +1,375 @@
/*
* 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

View file

@ -0,0 +1,105 @@
/*
* 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);
}

View file

@ -0,0 +1,163 @@
/*
* 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

View file

@ -0,0 +1,294 @@
/*
* 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);
}

View file

@ -0,0 +1,67 @@
/*
* 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

View file

@ -0,0 +1,92 @@
/*
* 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;
}

View file

@ -0,0 +1,270 @@
/*
* 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 */

View file

@ -0,0 +1,249 @@
/*
* 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);
}

View file

@ -0,0 +1,565 @@
/*
* 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;
}

View file

@ -0,0 +1,133 @@
#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

View file

@ -0,0 +1,62 @@
#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

View file

@ -0,0 +1,176 @@
/*
* 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

View file

@ -0,0 +1,364 @@
/*
* 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

View file

@ -0,0 +1,480 @@
/*
* 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;
}

View file

@ -0,0 +1,323 @@
/*
* 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

View file

@ -0,0 +1,280 @@
/*
* 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();
}

View file

@ -0,0 +1,45 @@
#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

View file

@ -0,0 +1,194 @@
/*
* 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

View file

@ -0,0 +1,483 @@
/*
* 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

View file

@ -0,0 +1,54 @@
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;

View file

@ -0,0 +1,499 @@
/*
* 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

View file

@ -0,0 +1,304 @@
/*
* 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

View file

@ -0,0 +1,414 @@
/*
* 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 */

View file

@ -0,0 +1,478 @@
/*
* 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

View file

@ -0,0 +1 @@
#define AXTLS_VERSION "1.4.9"

View file

@ -0,0 +1,556 @@
/*
* 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 */

View file

@ -0,0 +1,73 @@
/* 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);
}

View file

@ -0,0 +1,63 @@
/* 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

View file

@ -0,0 +1,91 @@
/* 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;
}

View file

@ -0,0 +1,104 @@
/* 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_ */

View file

@ -0,0 +1,133 @@
/* 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;
}

View file

@ -0,0 +1,81 @@
/* 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 TCPSOCKET_H
#define TCPSOCKET_H
#include "Socket/Socket.h"
#include "Socket/Endpoint.h"
/**
TCP socket connection
*/
class TCPSocketConnection : public Socket, public Endpoint {
friend class TCPSocketServer;
public:
/** TCP socket connection
*/
TCPSocketConnection();
/** 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, const int port);
/** Check if the socket is connected
\return true if connected, false otherwise.
*/
bool is_connected(void);
/** Send data to the remote host.
\param data The buffer to send to the host.
\param length The length of the buffer to send.
\return the number of written bytes on success (>=0) or -1 on failure
*/
int send(char* data, int length);
/** Send all the data to the remote host.
\param data The buffer to send to the host.
\param length The length of the buffer to send.
\return the number of written bytes on success (>=0) or -1 on failure
*/
int send_all(char* data, int length);
/** Receive data from the remote host.
\param data The buffer in which to store the data received from the host.
\param length The maximum length of the buffer.
\return the number of received bytes on success (>=0) or -1 on failure
*/
int receive(char* data, int length);
/** Receive all the data from the remote host.
\param data The buffer in which to store the data received from the host.
\param length The maximum length of the buffer.
\return the number of received bytes on success (>=0) or -1 on failure
*/
int receive_all(char* data, int length);
private:
bool _is_connected;
};
#endif

Some files were not shown because too many files have changed in this diff Show more