summaryrefslogtreecommitdiffstats
path: root/README.md
blob: 042f4b180c2890a05ab0c6a2ab22909424e906af (plain)
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# **README.md for the 'meta-agl' layer**

**See README-AGL.md for general information about Automotive Grade Linux.**

## meta-agl, the core layer for Automotive Grade Linux Distribution

AGL is creating an automotive specific Linux distribution that unifies
the software that has been written in a number of places already,
such as GENIVI and Tizen IVI.

The layer 'meta-agl' provides a minimal set of software
to boot system of AGL Distribution. 'meta-agl' is the minimal
core which is used build AGL profiles on top of it.

Especially there is no reference UI included which is part of 'meta-agl-demo'.

Additional components like the security framework are part of 'meta-agl-extra'.

The AGL community appreciates feedback, ideas, suggestion, bugs and
documentation just as much as code. Please join the irc conversation
at the #automotive channel on irc.freenode.net and our mailing list.

For infomation for subscribing to the mailing list
    [automotive-discussions](http://lists.linuxfoundation.org/mailman/listinfo/automotive-discussions)
For information about AGL Distribution, see the
    [AGL Distribution](https://wiki.automotivelinux.org/agl-distro)
For information abount Getting started with AGL
    [here](https://wiki.automotivelinux.org/start/getting-started)
For information about contributing to the AGL Distro
    [here](https://wiki.automotivelinux.org/agl-distro/contributing)

## Quick start guide

See README-AGL.md

## 'meta-agl' Layer Dependencies

* poky
  > URI: git://git.yoctoproject.org/poky
  > branch         : jethro
  > tested revision: 40376446904ae3529be41737fed9a0b650ed167d

* meta-openembedded
  > URI: git://git.openembedded.org/meta-openembedded
  > layer          : meta-openembedded
  > branch         : jethro
  > tested revision: 8ab04afbffb4bc5184cfe0655049de6f44269990

Specifically out of meta-openembedded these sub-layers are used:

* meta-openembedded/meta-oe
* meta-openembedded/meta-multimedia
* meta-openembedded/meta-networking
* meta-openembedded/meta-python

## Layers

There are 5 layers in top-level `meta-agl`.

* `meta-agl/meta-ivi-common`\
  `meta-ivi-common` is a layer which contains common packages to AGL
  Distribution and other platforms for In-Vehicle Infotainment system.
* `meta-agl/meta-agl`\
  `meta-agl` is a layer which contains AGL common and middleware packages.
* `meta-agl/meta-agl-bsp`\
  `meta-agl-bsp` is a layer which contains required packages to boot AGL
  distribution on an emulated machine(QEMU).
* `meta-agl/meta-netboot`\
  `meta-netboot` contains the netboot initrd support recipes. This is needed
  in case of booting over the network as NFS does not support the securitylabels.

## Packagegroups

AGL package group design:

* packagegroup-agl-image-minimal

        packagegroup-agl-core-automotive.bb
        packagegroup-agl-core-connectivity.bb
        packagegroup-agl-core-graphics.bb
        packagegroup-agl-core-kernel.bb
        packagegroup-agl-core-multimedia.bb
        packagegroup-agl-core-navi-lbs.bb
        packagegroup-agl-core-os-commonlibs.bb
        packagegroup-agl-core-security.bb
        packagegroup-agl-core-speech-services.bb

These are for making image ``agl-image-minimal`` which is small image just
capable of allowing a device to boot.

Subsystem should maintain packagegroup-agl-core-[subsystem].bb which should
hold sufficient packages to build ``agl-image-minimal``.

* packagegroup-agl-image-ivi

        packagegroup-agl-ivi-automotive.bb
        packagegroup-agl-ivi-connectivity.bb
        packagegroup-agl-ivi-graphics.bb
        packagegroup-agl-ivi-kernel.bb
        packagegroup-agl-ivi-multimedia.bb
        packagegroup-agl-ivi-navi-lbs.bb
        packagegroup-agl-ivi-os-commonlibs.bb
        packagegroup-agl-ivi-security.bb
        packagegroup-agl-ivi-speech-services.bb

These are for making image ``agl-image-ivi`` which is baseline for the profiles
of AGL distro. 'Baseline' means Service Layer and Operating System Layer defined
in AGL Spec v1.0.

* packagegroup-agl-test.bb

Additional tools used in QA tests (for agl-image*-qa).

* packagegroup-ivi-common*

        packagegroup-ivi-common-core-automotive.bb
        packagegroup-ivi-common-core.bb
        packagegroup-ivi-common-core-connectivity.bb
        packagegroup-ivi-common-core-graphics.bb
        packagegroup-ivi-common-core-kernel.bb
        packagegroup-ivi-common-core-multimedia.bb
        packagegroup-ivi-common-core-navi-lbs.bb
        packagegroup-ivi-common-core-os-commonlibs.bb
        packagegroup-ivi-common-core-security.bb
        packagegroup-ivi-common-core-speech-services.bb
        packagegroup-ivi-common-test.bb

These are for picking up some packages from upstreams like GENIVI/Tizen/Others.
The layer of ``meta-ivi-common`` has no image to build, all packagegroups are
aggregated to ``packagegroup-ivi-common-core' and it is included by images,
``agl-image-ivi.bb`` and ``agl-demo-platform.bb``.

## Supported Machines

See [docs.automotivelinux.org](http://docs.automotivelinux.org)
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
/*
 * Video On Demand Samples
 *
 * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You may also obtain this software under a propriety license from Microchip.
 * Please contact Microchip for further information.
 *
 */

#include <stdint.h>
#include <stddef.h>
#include "SafeVector.h"
#include "Network.h"
#include "NetworkDevice.h"
#include "DriverConfiguration.h"
#include "MacAddr.h"
#include "Board.h"
#include "Console.h"
#include "NodeDatabase.h"

#define PRINT_ALL_INFOS()
#define MAX_MOST_DEVICES		4

void CNetwork::DestroyAllResources( CNetworkDevice *device, uint16_t nodeAddress )
{
    if( NULL == device )
        return;

    CNodeEntry *node = CNodeEntry::GetNodeEntry( device->GetDeviceIndex(), nodeAddress );
    if( NULL == node )
        return;

    sem_wait( &vodXmlMutex );
    uint32_t apiVer = vodXml->GetDeviceApi( node->deviceType );
    sem_post( &vodXmlMutex );
    if( 1 == apiVer )
    {
        for( int i = 0; i < node->GetAmountOfConnections(); i++ )
        {
            CNodeConnectionEntry *connection = node->GetConnectionByIndex( i );
            if( NULL == connection || NULL == connection->channelConfig )
                continue;

            uint32_t inHandle = connection->inHandle;
            uint32_t outHandle = connection->outHandle;
            uint32_t conHandle = connection->connectHandle;
            NodeConnectionState_t inState = connection->inSocketState;
            NodeConnectionState_t outState = connection->outSocketState;
            NodeConnectionState_t conState = connection->connectedSocketState;
            uint32_t channelId = connection->channelConfig->channelId;
            connection->deviceName[0] = '\0';
            connection->mostConnectionLabel = 0xFFFFFFFF;
            connection->inHandle = 0xFFFFFFFF;
            connection->outHandle = 0xFFFFFFFF;
            connection->connectHandle = 0xFFFFFFFF;
            connection->inSocketState = NodeConnection_NotUsed;
            connection->outSocketState = NodeConnection_NotUsed;
            connection->connectedSocketState = NodeConnection_NotUsed;
            if( NodeConnection_NotUsed != conState && 0xFFFFFFFF != conHandle )
            {
                device->DisconnectSocketsV1( nodeAddress, conHandle, channelId );
            }
            if( NodeConnection_NotUsed != inState && 0xFFFFFFFF != inHandle )
            {
                device->DestroySocketV1( nodeAddress, inHandle, channelId );
            }
            if( NodeConnection_NotUsed != outState && 0xFFFFFFFF != outHandle )
            {
                device->DestroySocketV1( nodeAddress, outHandle, channelId );
            }
            RaiseUnavailable( connection );
        }
    }
    else if( 2 == apiVer || 3 == apiVer )
    {
        uint8_t amount;
#define MAX_DESTROY_ELEMENTS 10
        uint16_t handles[MAX_DESTROY_ELEMENTS];

        //Start to destroy the connections first:
        do
        {
            amount = 0;
            for( int i = 0; amount < MAX_DESTROY_ELEMENTS && i < node->GetAmountOfConnections(); i++ )
            {
                CNodeConnectionEntry *connection = node->GetConnectionByIndex( i );
                if( NULL == connection || NULL == connection->channelConfig )
                    continue;
                if( NodeConnection_NotUsed != connection->connectedSocketState )
                {
                    handles[amount++] = connection->connectHandle;
                    connection->connectHandle = 0xFFFFFFFF;
                    connection->connectedSocketState = NodeConnection_NotUsed;
                }
            }
            if( amount != 0 )
            {
                device->ResourceDestroyV3( nodeAddress, amount, handles, 0 );
            }
        }
        while( amount != 0 );

        do
        {
            amount = 0;
            //Continue to destroy the In and Out sockets:
            for( int i = 0; amount < MAX_DESTROY_ELEMENTS && i < node->GetAmountOfConnections(); i++ )
            {
                CNodeConnectionEntry *connection = node->GetConnectionByIndex( i );
                if( NULL == connection || NULL == connection->channelConfig )
                    continue;
                if( ( NodeConnection_NotUsed != connection->inSocketState )
                    && ( 0xFFFFFFFF != connection->inHandle ) )
                {
                    handles[amount++] = connection->inHandle;
                    for( int j = 0; j < node->GetAmountOfConnections(); j++ )
                    {
                        if( i == j )
                            continue;
                        CNodeConnectionEntry *otherConn = node->GetConnectionByIndex( j );
                        if( ( otherConn != NULL ) && ( otherConn->inHandle == connection->inHandle ) )
                        {
                            otherConn->inHandle = 0xFFFFFFFF;
                            otherConn->inSocketState = NodeConnection_NotUsed;
                        }
                    }
                    connection->inHandle = 0xFFFFFFFF;
                    connection->inSocketState = NodeConnection_NotUsed;
                }
                if( amount < MAX_DESTROY_ELEMENTS &&
                    ( NodeConnection_NotUsed != connection->outSocketState )
                    && ( 0xFFFFFFFF != connection->outHandle ) )
                {
                    handles[amount++] = connection->outHandle;
                    for( int j = 0; j < node->GetAmountOfConnections(); j++ )
                    {
                        if( i == j )
                            continue;
                        CNodeConnectionEntry *otherConn = node->GetConnectionByIndex( j );
                        if( ( otherConn != NULL ) && ( otherConn->outHandle == connection->outHandle ) )
                        {
                            otherConn->outHandle = 0xFFFFFFFF;
                            otherConn->outSocketState = NodeConnection_NotUsed;
                        }
                    }
                    connection->outHandle = 0xFFFFFFFF;
                    connection->outSocketState = NodeConnection_NotUsed;
                    RaiseUnavailable( connection );
                }

            }
            if( amount != 0 )
            {
                device->ResourceDestroyV3( nodeAddress, amount, handles, 0 );
            }
        }
        while( amount != 0 );

        //Last step destroy Splitter / Combiner input / output
        do
        {
            amount = 0;
            for( int i = 0; i < node->GetAmountOfConnections(); i++ )
            {
                CNodeConnectionEntry *connection = node->GetConnectionByIndex( i );
                if( NULL == connection || NULL == connection->channelConfig )
                    continue;
                if( 0xFFFFFFFF != connection->splittedSourceHandle )
                {
                    handles[amount++] = connection->splittedSourceHandle;
                    for( int j = 0; j < node->GetAmountOfConnections(); j++ )
                    {
                        if( i == j )
                            continue;
                        CNodeConnectionEntry *otherConn = node->GetConnectionByIndex( j );
                        if( ( otherConn != NULL ) && ( otherConn->splittedSourceHandle == connection->
                            splittedSourceHandle ) )
                        {
                            otherConn->splittedSourceHandle = 0xFFFFFFFF;
                        }
                    }
                    connection->splittedSourceHandle = 0xFFFFFFFF;
                }
            }
            if( amount != 0 )
            {
                device->ResourceDestroyV3( nodeAddress, amount, handles, 0 );
            }
        }
        while( amount != 0 );
    }
}

void CNetwork::DestroyAllResources()
{
    CNetworkDevice *device;
    uint16_t nodeAmount = CNodeEntry::GetAmountOfNodeEntries();
    for( int i = 0; i < nodeAmount; i++ )
    {
        CNodeEntry *node = CNodeEntry::GetNodeEntry( i );
        if( NULL == node )
            continue;
        CNetworkDevice *device = GetNetworkDevice( node->deviceInstance );
        uint16_t nodeAddress = node->nodeAddress;
        DestroyAllResources( device, nodeAddress );
    }
    for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
    {
        device = allNetworkDevices[i];
        if( NULL != device )
        {
            sem_wait( &vodXmlMutex );
            if( NULL != vodXml )
            {
                sem_post( &vodXmlMutex );
                if( device->IsTimingMaster() )
                {
                    ConsolePrintf( PRIO_MEDIUM, "DestroyAllResources, Performing MOST Shutdown index: %d\n",
                        device->GetDeviceIndex() );
                    device->ToggleNotOk();
                    device->SetNetstate( NetworkState_ShutdownInProgress );
                    device->MostNetworkShutdownV3();
                }
            }
            else
                sem_post( &vodXmlMutex );
        }
    }
    PRINT_ALL_INFOS();
}

void CNetwork::CloseAllNetworkDevices()
{
    DestroyAllResources();
    CNetworkDevice *device;
    for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
    {
        device = allNetworkDevices[i];
        if( NULL != device )
        {
            ConsolePrintf( PRIO_MEDIUM, "CloseAllNetworkDevices, Closing device index: %d\n",
                device->GetDeviceIndex() );
            device->Close();
        }
    }
    allNetworkDevices.RemoveAll(true);
    connectionBitMask = 0;
}

void CNetwork::FindNewNetworkDevices()
{
    sem_wait( &vodXmlMutex );
    if( NULL == vodXml )
    {
        sem_post( &vodXmlMutex );
        return;
    }
    bool success = false;
    bool infoQueried = false;
    uint8_t *controlRxAddress = NULL;
    uint8_t *controlTxAddress = NULL;
    uint32_t *apiVersion = NULL;
    SocketPort_t *hwPort = NULL;
    bool *isTimingMaster = NULL;
    uint32_t *asyncBW = NULL;
    uint8_t serverNum = 0;
    for( uint8_t devInstance = 0; devInstance < MAX_MOST_DEVICES; devInstance++ )
    {
        if( 0 != ( connectionBitMask & ( 1 << devInstance ) ) )
            continue;

        if( !infoQueried )
            infoQueried = vodXml->GetLocalInicConfigurations( &controlRxAddress, &controlTxAddress, &apiVersion,
                &hwPort, &isTimingMaster, &asyncBW, &serverNum );

        if( !infoQueried )
        {
            ConsolePrintf( PRIO_ERROR, RED"Can not parse XML file to configure server device"RESETCOLOR"\n" );
            sem_post( &vodXmlMutex );
            return;
        }
        for( uint8_t conIndex = 0; conIndex < serverNum; conIndex++ )
        {
            if( ( ( PORT_MLB == hwPort[conIndex] ) && ExistsMlbDeviceInstance( devInstance ) )
                || ( ( PORT_USB == hwPort[conIndex] ) && ExistsUsbDeviceInstance( devInstance ) ) )
            {
                connectionBitMask += ( 1 << devInstance );
                ConsolePrintf( PRIO_MEDIUM, "=======Server %d device uses %s, INIC API V%d=======\n",
                    devInstance, ( PORT_USB == hwPort[conIndex] ? "USB" : PORT_MLB == hwPort[conIndex] ? "MLB" :
                    "UNKNOWN" ), apiVersion[conIndex] );
                ConsolePrintf( PRIO_MEDIUM, "Opening device instance %d\n", devInstance );
                CNetworkDevice *newDevice = new CNetworkDevice( devInstance,
                    apiVersion[conIndex], isTimingMaster[conIndex], asyncBW[conIndex], promiscuous );
                switch( hwPort[conIndex] )
                {
                case PORT_USB:
                    success = newDevice->OpenUsb( controlRxAddress[conIndex], controlTxAddress[conIndex] );
                    break;
                case PORT_MLB:
                    success = newDevice->OpenMlb( controlRxAddress[conIndex], controlTxAddress[conIndex] );
                    break;
                default:
                    success = false;
                    break;
                }
                if( success )
                {
                    allNetworkDevices.PushBack( newDevice );
                    newDevice->AddListener( this );
                }
                else
                {
                    if( ( PORT_USB == hwPort[conIndex] ) && ( apiVersion[conIndex] < 3 ) )
                        ConsolePrintf( PRIO_ERROR, RED"Failed to open device instance %d"\
                        RESETCOLOR"\n", devInstance );
                    delete newDevice;
                }
            }
        }
    }
    if( NULL != controlRxAddress )
        free( controlRxAddress );
    if( NULL != controlTxAddress )
        free( controlTxAddress );
    if( NULL != apiVersion )
        free( apiVersion );
    if( NULL != hwPort )
        free( hwPort );
    sem_post( &vodXmlMutex );
}

void CNetwork::TryToCreateRoute( uint32_t devInstance, bool mostIsTx, void *e, void *t )
{
    if( NULL == e || NULL == t )
        return;
    CNodeEntry *entry = ( CNodeEntry * )e;
    CRouteTerminal *terminal = ( CRouteTerminal * )t;
    CSafeVector<CRouteTerminal *> connectedTerminals;

    sem_wait( &vodXmlMutex );
    bool found = vodXml->GetRouteTerminals( terminal, connectedTerminals );
    sem_post( &vodXmlMutex );
    if( !found )
        return;
    CNodeEntry *oppositeEntry = NULL;
    for( uint32_t i = 0; i < connectedTerminals.Size(); i++ )
    {
        if( NULL != ( oppositeEntry = CNodeEntry::GetNodeEntry( devInstance, connectedTerminals[i]->deviceType,
            connectedTerminals[i]->instance ) ) )
        {
            if( mostIsTx )
                ConnectSourceToSink( entry, oppositeEntry, terminal->channelId, connectedTerminals[i]->channelId );
            else
                ConnectSourceToSink( oppositeEntry, entry, connectedTerminals[i]->channelId, terminal->channelId );
        }
        delete connectedTerminals[i];
    }
}

void CNetwork::TryToConnectSockets( uint32_t devInstance, uint16_t nodeAddr, uint32_t channelId )
{
    CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr );
    if( NULL != entry )
    {
        CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( channelId, true );
        CNetworkDevice *device = GetNetworkDevice( devInstance );
        CChannelConfiguration *config = connection->channelConfig;
        sem_wait( &vodXmlMutex );
        uint32_t deviceApi = vodXml->GetDeviceApi( connection->channelConfig->deviceType );
        sem_post( &vodXmlMutex );
        if( ( NULL != connection ) && ( NULL != device ) && ( NULL != config ) )
        {
            CRouteTerminal terminal;
            terminal.channelId = channelId;
            terminal.deviceType = entry->deviceType;
            terminal.instance = CNodeEntry::GetTerminalInstance( devInstance, nodeAddr, entry->deviceType );

            if( ( NodeConnection_Used == connection->inSocketState )
                && ( NodeConnection_Used == connection->outSocketState )
                && ( NodeConnection_NotUsed == connection->connectedSocketState ) )
            {
                if( deviceApi > 3 )
                {
                    ConsolePrintf(
                        PRIO_ERROR, RED"TryToConnectSockets found unknown device API version: %d"RESETCOLOR"\n",
                        deviceApi );
                    return;
                }
                connection->connectedSocketState = NodeConnection_Pending_Up;
                if( 1 == deviceApi )
                {
                    device->ConnectSocketsV1( nodeAddr, connection->inHandle, connection->outHandle, channelId );
                }
                else if( ( 2 == deviceApi ) || ( 3 == deviceApi ) )
                {
                    uint32_t offset = config->inSocket.splittedOffset;
                    if( 0xFFFFFFFF == offset )
                    {
                        offset = config->outSocket.splittedOffset;
                        if( 0xFFFFFFFF == offset )
                            offset = 0;
                    }
                    device->ConnectSocketsV3( nodeAddr, config->outSocket.type, connection->inHandle,
                        connection->outHandle, offset, channelId );
                }
                TryToCreateRoute( devInstance, true, entry, &terminal );
            }
            else if( ( NodeConnection_NotUsed == connection->inSocketState )
                && ( NodeConnection_Used == connection->outSocketState )
                && ( PORT_MOST == config->inSocket.port ) )
            {
                TryToCreateRoute( devInstance, false, entry, &terminal );
            }
        }
    }
    PRINT_ALL_INFOS();
}

void CNetwork::TryToCloseExistingMostConnection( void *inNode, uint32_t inChannelId, void *outNode,
    uint32_t outChannelId )
{
    if( ( NULL == inNode ) || ( NULL == outNode ) )
        return;

    for( uint8_t i = 0; i < 2; i++ )
    {
        CNodeConnectionEntry *closeEntry = NULL;
        switch( i )
        {
        case 0:
            closeEntry = ( ( CNodeEntry * )outNode )->GetConnectionByChannelId( outChannelId, false );
            break;
        case 1:
            closeEntry = ( ( CNodeEntry * )inNode )->GetConflictingConnection( inChannelId,
                ( ( CNodeEntry * )outNode ) );
            break;
        }
        if( NULL == closeEntry || NULL == closeEntry->channelConfig
            || NULL == closeEntry->parentNode )
            continue;

        if( ( NodeConnection_Used == closeEntry->inSocketState ) &&
            ( NodeConnection_Used == closeEntry->connectedSocketState ) &&
            ( PORT_MOST == closeEntry->channelConfig->inSocket.port ) )
        {
            uint8_t oppInst = closeEntry->parentNode->deviceInstance;
            CNetworkDevice *oppDevice = GetNetworkDevice( oppInst );
            if( NULL != oppDevice )
            {
                uint16_t oppNodeAddress = closeEntry->parentNode->nodeAddress;
                uint32_t oppApiVer = closeEntry->parentNode->deviceType;
                uint32_t oppConHandle = closeEntry->connectHandle;
                uint32_t oppInHandle = closeEntry->inHandle;
                uint32_t oppChannelId = closeEntry->channelId;

                closeEntry->connectedSocketState = NodeConnection_Pending_Down;
                closeEntry->inSocketState = NodeConnection_Pending_Down;

                if( 1 == oppApiVer )
                {
                    oppDevice->DisconnectSocketsV1( oppNodeAddress, oppConHandle, oppChannelId );
                    oppDevice->DestroySocketV1( oppNodeAddress, oppInHandle, oppChannelId );
                }
                else if( 2 == oppApiVer || 3 == oppApiVer )
                {
                    uint16_t a[2];
                    a[0] = oppConHandle;
                    a[1] = oppInHandle;
                    oppDevice->ResourceDestroyV3( oppNodeAddress, 2, a, oppChannelId );
                }
            }
        }
    }
    PRINT_ALL_INFOS();
}

void CNetwork::RaiseAvailable( void *con )
{
    CNodeConnectionEntry *connection = ( CNodeConnectionEntry * )con;
    if( ( NULL != connection )
        && ( NULL != connection->parentNode )
        && ( NULL != connection->channelConfig )
        )
    {
        uint32_t blockWidth = connection->channelConfig->outSocket.blockWidth;
        if( 0xFFFFFFFF == blockWidth )
            blockWidth = connection->channelConfig->inSocket.blockWidth;
        
        uint16_t xact = 0;
        if ( PORT_USB == connection->channelConfig->inSocket.port )
            xact = connection->channelConfig->inSocket.packetsPerTransaction;
        else if ( PORT_USB == connection->channelConfig->outSocket.port )
            xact = connection->channelConfig->outSocket.packetsPerTransaction;

        uint32_t devInst = CNodeEntry::GetTerminalInstance( connection->parentNode->deviceInstance,
            connection->parentNode->nodeAddress, connection->parentNode->deviceType );
        for( uint32_t i = 0; i < allListeners.Size(); i++ )
        {
            int offset = -1;
            int maxBW = -1;
            if( 0xFFFFFFFF != connection->channelConfig->inSocket.splittedOffset )
            {
                offset = connection->channelConfig->inSocket.splittedOffset;
                maxBW = connection->channelConfig->inSocket.subbufferSize;
            }
            else if( 0xFFFFFFFF != connection->channelConfig->outSocket.splittedOffset )
            {
                offset = connection->channelConfig->outSocket.splittedOffset;
                maxBW = connection->channelConfig->outSocket.subbufferSize;
            }
            allListeners[i]->OnChannelAvailable( connection->parentNode->macAddress,
                connection->parentNode->deviceType, devInst, connection->channelId,
                connection->parentNode->deviceInstance, connection->channelConfig->outSocket.type,
                blockWidth, ( PORT_MOST == connection->channelConfig->outSocket.port ), ( NodeConnection_Used ==
                connection->inSocketState ), ( NodeConnection_Used == connection->outSocketState ),
                ( NodeConnection_Used == connection->connectedSocketState ), connection->bufferSize,
                connection->mostConnectionLabel, offset, maxBW, xact, connection->deviceName );
        }
    }
}

void CNetwork::RaiseUnavailable( void *con )
{
    CNodeConnectionEntry *connection = ( CNodeConnectionEntry * )con;
    if( ( NULL != connection )
        && ( NULL != connection->parentNode )
        && ( NULL != connection->channelConfig )
        && ( NULL != connection->parentNode->macAddress )
        )
    {
        for( uint32_t i = 0; i < allListeners.Size(); i++ )
        {
            allListeners[i]->OnChannelUnavailable( connection->parentNode->macAddress, connection->channelId,
                connection->parentNode->deviceInstance );
        }
    }
}

CNetworkDevice *CNetwork::GetNetworkDevice( uint32_t devInstance )
{
    CNetworkDevice *device = NULL;
    for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
    {
        if( devInstance == allNetworkDevices[i]->GetDeviceIndex() )
        {
            device = allNetworkDevices[i];
            break;
        }
    }
    return device;
}

CMacAddr *CNetwork::SetMacAddress( CNetworkDevice *device, uint32_t devInstance, uint16_t nodeAddress,
    uint8_t inicApiVersion )
{
    if( NULL == device )
        return NULL;
    CMacAddr *mac = new CMacAddr( devInstance, nodeAddress );
    if( NULL == mac )
    {
        ConsolePrintf( PRIO_ERROR, RED"Failed to instance CMacAddr object"RESETCOLOR"\n" );
        return NULL;
    }
    ConsolePrintf( PRIO_MEDIUM,
        "Creating local MAC for deviceInstance:%d: nodeAddress:0x%X, MAC-Address:%02X-%02X-%02X-%02X-%02X-%02X)\n",
        devInstance, nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4], ( *mac )[5] );

    switch( inicApiVersion )
    {
    case 1:
        device->SetMostMacAddressV1( nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4],
            ( *mac )[5], false );
        break;
    case 2:
        device->SetMostMacAddressV3( nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4],
            ( *mac )[5] );
        break;
    case 3:
        device->SetMostMacAddressV3( nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4],
            ( *mac )[5] );
        break;
    default:
        ConsolePrintf(
            PRIO_ERROR, RED"Can not set local MAC, because device API version (%d) is unknown"RESETCOLOR"\n",
            inicApiVersion );
        delete mac;
        mac = NULL;
        break;
    }
    return mac;
}

bool CNetwork::ConnectSourceToSink( void *mostTxNode, void *mostRxNode, uint32_t sourceChannelId,
    uint32_t sinkChannelId )
{
    bool success = false;
    PRINT_ALL_INFOS();
    if( ( NULL != mostTxNode ) && ( NULL != mostRxNode ) )
    {
        CNodeEntry *txNode = ( CNodeEntry * )mostTxNode;
        CNodeEntry *rxNode = ( CNodeEntry * )mostRxNode;
        CNodeConnectionEntry *inConnection = txNode->GetConnectionByChannelId( sourceChannelId, false );
        CNodeConnectionEntry *outConnection = rxNode->GetConnectionByChannelId( sinkChannelId, false );
        CNetworkDevice *outDevice = GetNetworkDevice( rxNode->deviceInstance );
        if( ( NULL != inConnection ) && ( NULL != outConnection ) && ( NULL != outDevice )
            && ( NULL != outConnection->channelConfig ) && ( 0xFFFFFFFF != inConnection->mostConnectionLabel ) )
        {
            if( ( NodeConnection_Used == inConnection->outSocketState )
                && ( NodeConnection_NotUsed == outConnection->inSocketState ) )
            {
                uint32_t connectionLabel = inConnection->mostConnectionLabel;
                sem_wait( &vodXmlMutex );
                uint32_t inApiVer = vodXml->GetDeviceApi( txNode->deviceType );
                uint32_t outApiVer = vodXml->GetDeviceApi( rxNode->deviceType );
                sem_post( &vodXmlMutex );
                ConsolePrintf( PRIO_MEDIUM,
                    BLUE"CNetwork::ConnectSourceToSink Connection Label:0x%X, IN-API-Ver:%d, OUT-API-Ver:%d, devIndex:%d, address:0x%X"RESETCOLOR"\n",
                    connectionLabel, inApiVer, outApiVer, rxNode->deviceInstance,
                    rxNode->nodeAddress );
                TryToCloseExistingMostConnection( txNode, sourceChannelId, rxNode, sinkChannelId );
                if( 1 == outApiVer )
                {
                    outDevice->CreateMostSocketV1( rxNode->nodeAddress, outConnection->channelConfig->inSocket.type,
                        EPDIR_IN, connectionLabel, outConnection->channelConfig->inSocket.blockWidth, sinkChannelId );
                    success = true;
                }
                else if( 2 == outApiVer || 3 == outApiVer )
                {
                    outDevice->CreateMostSocketV3( rxNode->nodeAddress, outConnection->channelConfig->inSocket.type,
                        EPDIR_IN, connectionLabel, outConnection->channelConfig->inSocket.blockWidth, sinkChannelId );
                    success = true;
                }
                if( success )
                {
                    outConnection->inSocketState = NodeConnection_Pending_Up;
                    outConnection->mostConnectionLabel = connectionLabel;
                }
            }
        }
    }
    else
    {
        ConsolePrintf(
            PRIO_ERROR, RED"CNetwork::SetSinkToChannel failed to resolve given MAC addresses"RESETCOLOR"\n" );
    }
    PRINT_ALL_INFOS();
    return success;
}

void CNetwork::RaiseUknownConnection( uint32_t devInstance, uint16_t nodeAddress, EPDataType_t dType )
{
    CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddress );
    CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( 0xFF, true );
    entry->macAddress = new CMacAddr( devInstance, nodeAddress );
    connection->channelConfig = new CChannelConfiguration();
    connection->channelConfig->inSocket.type = dType;
    connection->channelConfig->outSocket.type = dType;
    RaiseAvailable( connection );
}

void CNetwork::ShutdownMost( CNetworkDevice *device )
{
     if( NULL == device )
        return;
    device->ClearAllPendingActions();
    device->SetNetstate( NetworkState_ShutdownInProgress );
    device->MostNetworkShutdownV3();
}

void CNetwork::ShutdownMostBecauseOfErrors( CNetworkDevice *device )
{
    if (retryCounter < 5)
    {
        retryExecTime = GetTickCount();
        retryCounter++;
        ConsolePrintf(
            PRIO_ERROR, RED"Restart MOST because of resources allocation /"\
            " configuration problems, retry count=%d"RESETCOLOR"\n", retryCounter );
        ShutdownMost( device );
    }
}