blob: 9669f0bbcc6f2038912aa3a77807cfc62ec84eea [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 fortiss GmbH.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ben Schneider - Initial contribution; vlan and prio configuration to support tsn for pub/sub
*******************************************************************************/
#include <sys/socket.h>
#include <net/if.h>
#include "tsn_layer.h"
#include "../../arch/devlog.h"
#include "commfb.h"
#include <stdio.h>
#include "parameterParser.h"
#include "string_utils.h"
using namespace forte::com_infra;
CTSNLayer::CTSNLayer(CComLayer* paUpperLayer, CBaseCommFB* paBaseCommFB) :
CIPComLayer(paUpperLayer, paBaseCommFB){
}
CTSNLayer::~CTSNLayer(){
}
EComResponse CTSNLayer::openConnection(char *paLayerParameter){
EComResponse eRetVal = e_InitInvalidId;
// complete ID for publisher: fbdk[].tsn[<ip>:<port>:<vlan_id>:<prio>] e.g., fbdk[].tsn[239.1.0.1:48401:3:5]
CParameterParser parser(paLayerParameter, ':', scmNumParameters);
if(scmNumParameters != parser.parseParameters()){
DEVLOG_ERROR("[TSN Layer] Wrong parameters (%s)\n", paLayerParameter);
}
else{
unsigned int vlanPriority = static_cast<unsigned int>(forte::core::util::strtoul(parser[3], 0, 10));
char * dstIPAddress = const_cast<char*>(parser[0]);
TForteUInt16 nPort = static_cast<TForteUInt16>(forte::core::util::strtoul(parser[1], 0, 10));
CIPComSocketHandler::TSocketDescriptor nSockDes = CIPComSocketHandler::scmInvalidSocketDescriptor;
m_eConnectionState = e_Connected;
switch (m_poFb->getComServiceType()){
case e_Server:
DEVLOG_ERROR("[TSN LAYER] TSN layer does not support server FBs. Use the default "
"ip layer without vlan parameters instead.\n");
break;
case e_Client:
DEVLOG_ERROR("[TSN LAYER] TSN layer does not support client FBs. Use the default "
"ip layer without vlan parameters instead.\n");
break;
case e_Publisher:
nSockDes = mSocketID = CIPComSocketHandler::openUDPSendPort(dstIPAddress, nPort, &mDestAddr);
eRetVal = setVLANIDForSocket(parser[2]);
if(e_InitOk == eRetVal){
eRetVal = setVLANPriorityForSocket(vlanPriority);
}
break;
case e_Subscriber:
DEVLOG_ERROR("[TSN LAYER] TSN layer does not support subscriber FBs. Use the default "
"ip layer without vlan parameters instead.\n");
break;
}
if(CIPComSocketHandler::scmInvalidSocketDescriptor != nSockDes && e_InitOk == eRetVal){
if(e_Publisher != m_poFb->getComServiceType()){
//Publishers should not be registered for receiving data
getExtEvHandler<CIPComSocketHandler>().addComCallback(nSockDes, this);
}
eRetVal = e_InitOk;
}
else{
m_eConnectionState = e_Disconnected;
}
}
return eRetVal;
}
EComResponse CTSNLayer::setVLANPriorityForSocket(unsigned int paVlanPriority){
EComResponse eRetVal = e_InitInvalidId;
if (scmMaxVLANPrio < paVlanPriority){
DEVLOG_ERROR("[TSN Layer] VLAN priority %u out of range (0 - 7)\n", paVlanPriority);
return eRetVal;
}
if(0 == setsockopt(mSocketID, SOL_SOCKET, SO_PRIORITY, &paVlanPriority, sizeof(paVlanPriority))){
eRetVal = e_InitOk;
}
else{
DEVLOG_ERROR("[TSN LAYER] Setting user space priority %u of socket not possible \n", paVlanPriority);
}
return eRetVal;
}
EComResponse CTSNLayer::setVLANIDForSocket(const char* paId){
EComResponse eRetVal = e_InitInvalidId;
unsigned int id = static_cast<unsigned int>(forte::core::util::strtoul(paId, 0, 10));
if(scmMinVLANID <= id && scmMaxVLANID >= id){
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
CIEC_STRING interfaceName = "eth0.";
interfaceName.append(paId);
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), interfaceName.getValue());
if(0 == setsockopt(mSocketID, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr, sizeof(ifr))){
eRetVal = e_InitOk;
}
else{
DEVLOG_ERROR("[TSN LAYER] binding to interface %s not possible \n", interfaceName.getValue());
}
}
else{
DEVLOG_ERROR("[TSN Layer] Invalid VLAN ID %u out of range (1 - 4095)\n", id);
}
return eRetVal;
}