SoAd - Socket Adaptor Overview
As you probably know, TCP / IP is the most established technology for telecommunication with ethernet. Its extensive suite of protocols covers addressing for applications, logical addressing of endpoints and physical addressing, having dynamic configuration and routing at its core. In contrast, we are used in Autosar to have static configuration of communication between source and sink, and intransigent / predictable run-time behaviour. Both are not compatible.
Therefore, Socket Adaptor was created, to act as a middle layer in between both communication paradigms. It defines a static communication configuration, with the information required by the Autosar stack and leaves open points that can be updated during runtime, while also abstracting the callback architecture of socket-based communication typically found in TCP / IP. This is achieved by providing an interface between the Autosar communication services, governed by I-PDUs (you can learn about I-PDUs in our posts COM - Demystifying I-PDU Transmission Modes (opens in a new tab) and other ones we have on our website), and the socket communication of TCP / IP, mapping I-PDU IDs to socket connections and vice-versa.
SoAd implements the following features:
-
Maps socket connections to one or more I-PDUs (depending on if the optional PDU header is present or not).
-
Opens socket connections manually (via requests from the upper layers) or automatically.
-
Specifies a policy for socket recovery and disconnection.
-
Defines a message acceptance policy, specifying which messages from remote nodes via TCP connections or UDP datagrams are accepted.
-
Provides the concept of PDU routing groups, which allow the upper layers to enable or disable the routing of PDU sets to and from socket connections.
-
Allows the transmission and reception of PDUs to upper layers by through both its IF-APIs and TP-APIs.
-
Enables PDU fan-out, the acts of distributing an IF-PDU to multiple socket connections or a received message from a socket into multiple IF-PDUs that can be used by different upper layers.
Socket Adaptor - Dependencies With Other Modules
As you can see in the figure below (where I-PDU communication exchanges are in blue), the upper layers that interact with SoAd all communicate via I-PDUs with it. These are the PduR (which you can learn more about in this post Demystifying Autosar PDU Router. A Comprehensive Guide to Routing, Handling, and Buffering (opens in a new tab)), DoIP, Sd, UDP NM and Xcp (learn about it in our post What is XCP (opens in a new tab)). These are then connected via SoAd with the Autosar TCP / IP stack (TcpIp), which implements the main TCP / IP protocols. Lastly, the EthSM is used to control the state of SoAd, and the IdsM is used to report security events to the SoAd:
Dependencies between the Socket Adaptor (SoAd) and other BSW modules
Socket Adaptor Limitations
Of course, there are some limitations that SoAd has addressed, or it just cannot fulfil. The most obvious is the overhead: TCP / IP data adds around 60 bytes of overhead. If you are transmitting small amounts of data, it is just unacceptable, unless you group multiple I-PDUs and send them all in one go. This is made possible through the addition of a PDU header, comprised of an ID and length. This way, multiple PDUs are sent via a single socket connection.
Moreover, assignment of TCP and UDP port numbers is the responsibility of the implementation, just as the management of IP addresses. These are static or handled dynamically through DHCP or a similar protocol. It also does not specify a physical layer or data rate.
Laslty, SOME / IP protocol and interface versions are not checked by SoAd, even though they should be, as described in the SOME / IP specification. Although, the service and method IDs are checked, and if they are not valid the error SOAD_E_INV_PDUHEADER_ID
will be set.
Opening and Closing Socket Connections
One important feature of the Socket Adapter is socket handling, as sockets are the backbone of the communication via TCP / IP. Depending on the usage of UDP or TCP, these provide connectionless or connection-oriented communication, respectively. Two stations can establish one or more socket connections, where on each side a socket will be comprised of an address and a port, and their combination will be a connection.
SoAd adds to each socket connection some parameters, such as the transport protocol and its own parameters, the presence or absence of a PDU header, buffer needs, connection setup, among other things. Each socket connection within SoAd has a unique identifier, named SoConId
. It is also possible to group multiple socket connections with similar parameters into socket connection groups.
The upper layers can request SoAd to open a socket through the API SoAd_OpenSoCon
, and request to close it via SoAd_CloseSoCon
. These APIs will set a flag to signal the request, and it will be handled within the cyclic SoAd_MainFunction
.
The remote address of a socket connection can be modified via the API SoAd_SetRemoteAddr
, but only if none of the conditions apply:
-
The TCP socket connection is not in the
SOAD_SOCON_OFFLINE
state. -
Active reception of IF-PDUs or pending reception of TP-PDUs.
-
Active or pending transmission.
A socket connection is eligible to be opened in the main function if all the following points are met:
-
There is no TcpIp socket associated with the connection you are trying to open.
-
No explicit request to open the socket connection via
SoAd_OpenSoCon
is in progress (has not been revoked bySoAd_CloseSoCon
), or implicitly via setting the parameterSoAdSocketAutomaticSoConSetup
to true. -
The local IP address has been assigned, which can be done through an API call to
SoAd_LocalIpAddrAssignmentChg
with theLocalAddrId
set to the local IP address and the State parameter set toTCPIP_IPADDR_STATE_ASSIGNED
.
Regarding socket connection closing, it will also occur within the SoAd_MainFunction
, when a request to close the socket is issued via the API SoAd_CloseSoCon
and no upper layer requested to keep the socket open, through SoAd_OpenSoCon
, or if the parameter within SoAd_CloseSoCon
is set to true.
If the socket closed through the SoAd_CloseSoCon
API call, the state of the socket connection will be set to SOAD_SOCON_OFFLINE
. If it is closed for some other reason, the socket will transition to the state SOAD_SOCON_RECONNECT
. Lastly, while the socket is being closed, all active TP sessions are terminated and a notification is issued to the upper layers involved, via an API call to <Upper_layer>_[SoAd][Tp]RxIndication
(delivering E_OK
if all the received data has been delivered to the upper layer), further transmissions and receptions are discarded and the related TcpIp sockets are closed.
There is a bit more to this. As for socket connection opening, closing and the SoAd state machine, we will cover them more extensively in a future post, so stay tuned for that.
Message Transmission and Confirmation via IF and TP API
For transmission of PDUs via TCP or UDP sockets, the Socket Adaptor defines a PDU route, which links a PDU to a socket connection. It defines, through either of the parameters SoAdPduRoute
or SoAdPduRouteDest
the route of a PDU from an upper layer to the socket on the TcpIp stack depicted in the socket connection, SoAdSocketConnection
, or socket connection group SoAdSocketConnectionGroup
. The upper layer can use the IF-API or the TP-API for the transmission request and to provide the necessary data for it to take place.
When using the IF API, after the upper layers signals its request to transmit data, via an API call to SoAd_IfTransmit
, the Socket Adaptor verifies the respective socket connection through the parameter TxPduId
and calls the necessary TcpIp API to transmit the PDU if the PDU provided is not empty or the configuration parameter SoAdPduHeaderEnable
is set to true, otherwise, it will stop the process and return E_NOT_OK
.
Moreover, for UDP sockets, SoAd will use the TcpIp_UdpTransmit
API to transmit the PDU, specifying the SocketId
and the remote address (it will be needed as there are no preliminary connection steps like in TCP) contained in the SocketConnection
, and the length of the PDU.
For TCP, the underlying TcpIp API is TcpIp_TcpTransmit
, including the parameters SocketId
, PDU length and ForceRetrieve
(set to true). Inside both APIs, the TcpIp module will use the API SoAd_CopyTxData
to retrieve the data for the PDU transmission. If the PDU buffer pointer from the upper layer (or SDU), PduInfoPtr->SduDataPtr
, came into the Socket Adaptor set to NULL_PTR
, it will retrieve the PDU data from the upper layer through an API call to <Upper_layer>[SoAd][If]TriggerTransmit
.
For the confirmation of messages, the Socket Adaptor will call the API <Upper_layer>[SoAd][If]TxConfirmation
, in case of a UDP socket connection, within the next SoAd_MainFunction
call after the TcpIp_UdpTransmit
has returned successfully. As for TCP, the same API will be called when all transmit requests have been confirmed by the receiver. Even when multiple requests are issued in succession, TCP will only confirm when the last request is completed.
Another option for the transmission of messages is through SoAd_IfRoutingGroupTransmit
. This API will store a transmission request for each SoAdPduRouteDest
referenced by a routing group through the id
parameter, to be processed within the SoAd_MainFunction
. Another variant of this API is SoAd_IfSpecificRoutingGroupTransmit
, that specifies a socket connection SoConId
, from which the PDUs shall be transmitted.
Within the SoAd_MainFunction
call, the data to be transmitted will be gathered from the upper layers via the API <Upper_layer>[SoAd][If]TriggerTransmit
into the PduInfoType.SduDataPtr
and PduInfoType.SduDataLength
and transmitted via the respective socket connection.
The last option for transmission is the TP-API. When an upper layer requests a transmission through it, the SoAd checks the length of the message (and discards it if the length is set to zero), checks the parameter TxPduId
provided via the API call to SoAd_TpTransmit
, to select the correct SoAdPduRoute
(which contains one or more SoAdPduRouteDest
values that will provide the SoAdSocketConnection
to where the PDU should be transmitted) and stores the TP transmission request to be processed within the SoAd_MainFunction
.
The API <Upper_layer>[SoAd][Tp]CopyTxData
will be called repeatedly to retrieve the data and its length to be transmitted (where the value of the argument AvailableDataPtr
gets incremented in each call to the length value retrieved in the former API call, starting with zero, and the data is stored into the buffer provided in BufPtr
), to then, depending on the connection get data itself and forward it to the TcpIp module with the correct transmission API.
When a UDP socket is in use, the TcpIp_UdpTransmit
will be called when all the data has been retrieved through one or more main function calls. If the <Upper_layer>[SoAd][Tp]CopyTxData
API fails with the return value BUFREQ_E_NOT_OK
, then the process is aborted, and the upper layer is notified via the API <Upper_layer>_[SoAd][Tp]TxConfirmation
with the status E_NOT_OK
. The failure will not affect the socket connection state.
For a TCP socket, the same will be used to retrieve the data and its length, with the argument ForceRetrieve
set to false. The particularity with a TCP socket is that in case the API call to <Upper_layer>[SoAd][Tp]CopyTxData
fails with BUFREQ_E_NOT_OK
, the TCP socket connection will be closed within the next SoAd_MainFunction
, and the new transmission requests and receptions will be discarded.
Moreover, when the multiple respective TcpIp_UdpTransmit
or TcpIp_TcpTransmit
return, the Socket Adaptor will forward this status via the <Upper_layer>_[SoAd][Tp]TxConfirmation
callback.
Additionally, the TCP will forward the confirmation only once, when all the TP PDU data has been transmitted, if the parameter SoAdSocketTcpImmediateTpTxConfirmation
is set to false, or one for each transmission via the aforementioned APIs if the parameter value is set to true, which is the behaviour for UDP socket connections.
Lastly, a new SoAd_TpTransmit
call can be performed within the confirmation API for the same PDU, creating a new TP session.
There are some more variations, depending upon the parameters and the nPdu
feature. Today we will not go over them, for the sake of keeping this article short and sweet, but these topics will be covered in future posts.
Message Reception
Regarding the message reception from TCP and UDP sockets, the Socket Adaptor specified a socket route that is related to a socket connection. This route, specified by either of the parameters SoAdSocketRoute
or SoAdSocketRouteDest
, defines the route from a socket of the TcpIp module to the upper layer. The upper layer can then use the IF-API or TP-API to receive the PDU.
The reception process for both socket types starts with checking the socket connection and routes to be involved, through the SocketId
parameter received in the SoAd_RxIndication
. Then, the messages are filtered according to the message acceptance policy and converted into a PDU.
After this conversion, if the PDU length is zero and PDU header mode is not enabled and the upper layer is not TP, the PDU is discarded. Otherwise, the corresponding reception functions for the upper layer specified in the parameter SoAdRxUpperLayerType
within the socket destination route SocketRouteDest
get called.
Looking specifically at UDP sockets, these can contain more than one socket connection belonging to a socket connection group, which in this case all of the socket connections in the group share the same socket, and the socket connection is to be chosen according to the best match algorithm.
Concerning message reception on TCP sockets, the Socket Adaptor has to confirm all data forwarded to the upper layers or discarded internally, via an API call to SoAd_RxIndication
, taking place within SoAd_RxIndication
or SoAd_MainFunction
.
When it comes to the behaviour of both the IF and TP-PDUs, these have to be processed independently and according to their type and time of arrival, per socket connection. When using a reception buffer, the order of the data is also to be preserved, and if the size of the received data is larger than the available space in the reception buffer, the error SOAD_E_BUFS
is raised. Moreover, when a PDU is discarded, the optional configuration parameter SoAdGetAndResetMeasurementDataApi
can be selected, enabling SoAd to increment the measurement data upon each discard occurrence.
Upon SoAd_RxIndication, the reception of a PDU and its forwarding to an upper layer via the IF-API is resumed in the following steps:
-
If PDU header is used and the PDU is fragmented into multiple messages, the data of the first fragmented PDU is placed into an internal Socket Adaptor reception buffer. Since UDP cannot guarantee the order of the messages received, and TCP will treat individual messages as different PDUs, fragmented IF-PDUs can only be used by TCP and with header mode enabled.
-
The
<Upper_Layer>_[SoAd][If]RxIndication
API is called for the upper layer to receive the assembled PDU. -
The process is repeated for each PDU, if the header mode is enabled.
As for the reception of PDUs with the TP-API without PDU header mode, it will also take place within SoAd_RxIndication
. There are two different possibilities for it.
In the first one, if a TP reception is already taking place on the relevant socket connection and SoAd reception buffer can store all the received data from TcpIp, all the data will be copied into the buffer, for later processing within the SoAd_MainFunction
.
For the second case, the SoAd reception buffer is empty. In regard to the TP data for this socket connection:
-
The amount of available buffer space in the upper layer is checked, via an API call to
<Upper_layer>[SoAd][Tp]CopyRxData
with the parameterinfo->SduLength
to zero. If the header mode is enabled, its size is processed and the API<Upper_Layer>[SoAd][Tp]StartOfReception
is called. -
Forward the PDU data to the upper layer, via an API call to
<Upper_layer>_[SoAd][Tp]CopyRxData
. If the API does not returnBUFREQ_OK
, the data will be discarded, the TP session will be terminated and the<Upper_layer>_[SoAd][Tp]RxIndication
API will returnE_NOT_OK
. -
If the PDU was completely forwarded to the upper layer, the
<Upper_layer>_[SoAd][Tp]RxIndication
API will signal that to the upper layer. Otherwise, the SoAd reception buffer will copy the data that could not fit into the upper layer reception buffer and process it in theSoAd_MainFunction
. -
Within the main function, the space available in the upper layer reception buffer is queried, via the
<Upper_layer>[SoAd][Tp]CopyRxData
API, with the same technique as stated before, and the steps 2 and 3 are repeated. -
If there are more TP-PDUs received in the message (PDU header mode active), the process repeats for each of them.
As a side note, you can cancel transmission and reception of TP sessions via the APIs SoAd_TpCancelReceive
and SoAd_TpCancelTransmit
. Doing so will make the SoAd_MainFunction
close the socket connection.
The PDU header configuration has implications on the overall reception behavior. We did not forget about this, let us cover it in another article, where we will take a deeper dive.
Closing Thoughts
As you could verify, we have barely scratched the surface and there is already a gigantic flow of information in this post. Truth is, the very basics are covered. But there is more, such as nPDU feature, configuration parameters, best match algorithm, acceptance policy, header mode, routing groups and security event reporting to cover. These will come in soon in future posts, so stay tuned!
If you like this sort of longer content, get in line for the waiting list on the upcoming eBook about Classic Autosar!
Author: Micael Coutinho (opens in a new tab)
References:
© AutosarToday —@LinkedIn