LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - SdOptionParser.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 79.1 % 115 91
Test Date: 2026-09-11 12:05:06 Functions: 88.9 % 9 8

            Line data    Source code
       1              : /********************************************************************************
       2              :  * Copyright (c) 2026 Accenture
       3              :  *
       4              :  * This program and the accompanying materials are made available under the
       5              :  * terms of the Apache License Version 2.0 which is available at
       6              :  * https://www.apache.org/licenses/LICENSE-2.0
       7              :  *
       8              :  * SPDX-License-Identifier: Apache-2.0
       9              :  ********************************************************************************/
      10              : 
      11              : #include "someip/SdOptionParser.h"
      12              : 
      13              : #include "someip/SdConstants.h"
      14              : #include "someip/SdOptions.h"
      15              : #include "someip/SomeIpConstants.h"
      16              : #include "someip/logger.h"
      17              : 
      18              : #include <ip/IPAddress.h>
      19              : 
      20              : #include <etl/unaligned_type.h>
      21              : 
      22              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      23              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      24              : 
      25              : namespace someip
      26              : {
      27              : using ::util::logger::SOMEIP;
      28              : 
      29              : namespace
      30              : {
      31              : enum class OptionCategory : uint8_t
      32              : {
      33              :     IpEndpointOption,
      34              :     IpMulticastOption
      35              : };
      36              : 
      37           25 : bool isOptionCategory(OptionCategory const category, uint8_t const type)
      38              : {
      39           25 :     if (OptionCategory::IpEndpointOption == category)
      40              :     {
      41              :         return (type == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP4_ENDPOINT))
      42           23 :                || (type
      43           23 :                    == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP6_ENDPOINT));
      44              :     }
      45            2 :     if (OptionCategory::IpMulticastOption == category)
      46              :     {
      47              :         return (type == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP4_MULTICAST))
      48            2 :                || (type
      49            2 :                    == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP6_MULTICAST));
      50              :     }
      51            0 :     return false;
      52              : }
      53              : 
      54           39 : bool isIp4OptionType(uint8_t const type)
      55              : {
      56              :     return (type == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP4_ENDPOINT))
      57           39 :            || (type == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP4_MULTICAST));
      58              : }
      59              : 
      60            0 : bool isIp6OptionType(uint8_t const type)
      61              : {
      62              :     return (type == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP6_ENDPOINT))
      63            0 :            || (type == static_cast<uint8_t>(ServiceDiscoveryOptionType::OPTION_TYPE_IP6_MULTICAST));
      64              : }
      65              : 
      66              : SdEndpoint
      67           19 : parseIpOptionType(::etl::span<uint8_t const> const buffer, uint16_t offset, uint8_t const type)
      68              : {
      69           19 :     offset += static_cast<uint16_t>(static_cast<uint16_t>(SdConstants::SD_OPTION_ADDRESS_OFFSET));
      70              : 
      71           19 :     ::ip::IPAddress ipAddr{};
      72           19 :     if (isIp4OptionType(type))
      73              :     {
      74           19 :         ipAddr = ::ip::make_ip4(
      75           19 :             ::etl::span<uint8_t const>(buffer).subspan(offset).first(::ip::IPAddress::IP4LENGTH));
      76           19 :         offset += ::ip::IPAddress::IP4LENGTH;
      77              :     }
      78              : #ifdef PLATFORM_SUPPORT_IPV6
      79              :     else if (isIp6OptionType(type))
      80              :     {
      81              :         ipAddr = ::ip::make_ip6(
      82              :             ::etl::span<uint8_t const>(buffer).subspan(offset).first(::ip::IPAddress::IP6LENGTH));
      83              :         offset += ::ip::IPAddress::IP6LENGTH;
      84              :     }
      85              : #endif
      86              :     else
      87              :     {
      88            0 :         return SdOptionParser::INVALID_ENDPOINT;
      89              :     }
      90              : 
      91           19 :     offset++; // reserved
      92              : 
      93           19 :     uint8_t const proto = buffer[offset];
      94           19 :     offset++;
      95           19 :     uint16_t const port = ::etl::be_uint16_t(buffer.data() + offset);
      96              : 
      97           19 :     return SdEndpoint(ipAddr, port, proto);
      98              : }
      99              : 
     100           43 : bool goToOption(
     101              :     uint32_t const targetOptionsIndex, /* in */
     102              :     uint8_t const*& option,            /* inout */
     103              :     uint32_t const optionsLength,      /* in */
     104              :     uint8_t& optionCounter,            /* inout */
     105              :     uint32_t& offset)                  /* inout */
     106              : {
     107           48 :     while (optionCounter < targetOptionsIndex)
     108              :     {
     109            5 :         if ((optionsLength - offset)
     110              :             < static_cast<uint32_t>(SdConstants::SD_OPTION_LENGTH_FIELD_LENGTH))
     111              :         {
     112            0 :             return false;
     113              :         }
     114            5 :         uint16_t const optionLength = ::etl::be_uint16_t(option);
     115            5 :         if ((optionsLength - offset)
     116            5 :             < (static_cast<uint32_t>(optionLength)
     117              :                + static_cast<uint32_t>(SdConstants::SD_OPTION_LENGTH_FIELD_LENGTH)
     118            5 :                + 1U)) // +1 because length does not cover type field
     119              :         {
     120            0 :             return false;
     121              :         }
     122            5 :         offset += static_cast<uint32_t>(optionLength) + 3U;
     123            5 :         option += static_cast<uint8_t>(optionLength + 3U);
     124            5 :         ++optionCounter;
     125              :     }
     126           43 :     return true;
     127              : }
     128              : 
     129           43 : bool searchOptions(
     130              :     OptionCategory const& optionCategory, /* in */
     131              :     uint8_t const*& option,               /* inout */
     132              :     uint32_t const optionsLength,         /* in */
     133              :     uint8_t const numAvailableOptions,    /* in */
     134              :     uint8_t& optionCounter,               /* inout */
     135              :     uint32_t& offset,                     /* inout */
     136              :     uint8_t const*& foundOption,          /* out */
     137              :     uint8_t& foundOptionType,             /* out */
     138              :     uint8_t& numUdpOptions,               /* out */
     139              :     uint8_t& numTcpOptions)               /* out */
     140              : {
     141           68 :     for (uint8_t i = 0U; i < numAvailableOptions; ++i)
     142              :     {
     143           26 :         if ((optionsLength - offset)
     144              :             < static_cast<uint32_t>(SdConstants::SD_OPTION_LENGTH_FIELD_LENGTH))
     145              :         {
     146            1 :             return false;
     147              :         }
     148              : 
     149           25 :         uint16_t const optionLength = ::etl::be_uint16_t(option);
     150           25 :         if ((optionsLength - offset)
     151           25 :             < (static_cast<uint32_t>(optionLength)
     152              :                + static_cast<uint32_t>(SdConstants::SD_OPTION_LENGTH_FIELD_LENGTH)
     153           25 :                + 1U)) // +1 because length does not cover type field
     154              :         {
     155            0 :             return false;
     156              :         }
     157              : 
     158           25 :         uint8_t const optionType
     159           25 :             = option[static_cast<uint16_t>(SdConstants::SD_OPTION_TYPE_OFFSET)];
     160           25 :         if (!isOptionCategory(optionCategory, optionType))
     161              :         {
     162            5 :             offset += static_cast<uint32_t>(optionLength) + 3U;
     163            5 :             option += static_cast<uint8_t>(optionLength + 3U);
     164            5 :             ++optionCounter;
     165            5 :             continue; // not the one we are looking for
     166              :         }
     167              : 
     168              :         uint16_t payloadLength;
     169              :         uint16_t protoOffset;
     170              : 
     171           20 :         if (isIp4OptionType(optionType))
     172              :         {
     173           20 :             payloadLength = static_cast<uint16_t>(SdConstants::SD_IP4_OPTION_LENGTH);
     174           20 :             protoOffset   = static_cast<uint16_t>(
     175              :                 static_cast<uint16_t>(SdConstants::SD_OPTION_ADDRESS_OFFSET)
     176              :                 + ::ip::IPAddress::IP4LENGTH + 1U);
     177              :         }
     178            0 :         else if (isIp6OptionType(optionType))
     179              :         {
     180            0 :             payloadLength = static_cast<uint16_t>(SdConstants::SD_IP6_OPTION_LENGTH);
     181            0 :             protoOffset   = static_cast<uint16_t>(
     182              :                 static_cast<uint16_t>(SdConstants::SD_OPTION_ADDRESS_OFFSET)
     183              :                 + ::ip::IPAddress::IP6LENGTH + 1U);
     184              :         }
     185              :         else
     186              :         {
     187            0 :             WARN_LOG(SOMEIP, "SdOptionParser::searchOptions(type: %d) invalid type", optionType);
     188            0 :             return false;
     189              :         }
     190              : 
     191           20 :         if ((optionLength + 3U) != payloadLength)
     192              :         {
     193            0 :             WARN_LOG(
     194              :                 SOMEIP,
     195              :                 "SdOptionParser::searchOptions(type: %d, length: %d) invalid payload",
     196              :                 optionType,
     197              :                 payloadLength);
     198            0 :             return false;
     199              :         }
     200              : 
     201           20 :         if (proto::SD_L4_PROTO_UDP == option[protoOffset])
     202              :         {
     203           20 :             ++numUdpOptions;
     204           20 :             if ((numUdpOptions + numTcpOptions) == 1U)
     205              :             { // use first found option
     206           19 :                 foundOption     = option;
     207           19 :                 foundOptionType = optionType;
     208              :             }
     209              :         }
     210            0 :         else if (proto::SD_L4_PROTO_TCP == option[protoOffset])
     211              :         {
     212            0 :             ++numTcpOptions;
     213            0 :             if ((numUdpOptions + numTcpOptions) == 1U)
     214              :             { // use first found option
     215            0 :                 foundOption     = option;
     216            0 :                 foundOptionType = optionType;
     217              :             }
     218              :         }
     219              :         else
     220              :         {
     221            0 :             WARN_LOG(
     222              :                 SOMEIP,
     223              :                 "SdOptionParser::searchOptions(type: %d, proto: 0x%X) invalid proto",
     224              :                 optionType,
     225              :                 option[protoOffset]);
     226            0 :             return false;
     227              :         }
     228              : 
     229           20 :         offset += static_cast<uint32_t>(optionLength) + 3U;
     230           20 :         option += static_cast<uint8_t>(optionLength + 3U);
     231           20 :         ++optionCounter;
     232              :     }
     233              : 
     234           42 :     return true;
     235              : }
     236              : 
     237           22 : SdEndpoint parseIpOption(
     238              :     OptionCategory const& optionCategory,
     239              :     SdOptions const& options,
     240              :     uint8_t& numUdpOptions,
     241              :     uint8_t& numTcpOptions)
     242              : {
     243           22 :     ::etl::span<uint8_t const> const buffer = options.getOptionsData();
     244              : 
     245           22 :     uint8_t const* foundOption = nullptr;
     246           22 :     uint8_t foundOptionType    = 0U;
     247              : 
     248              :     {
     249           22 :         uint8_t const* option = buffer.data();
     250           22 :         uint8_t optionCounter = 0U;
     251           22 :         uint32_t offset       = 0U;
     252              : 
     253              :         // go to options1
     254           22 :         if (!goToOption(
     255           22 :                 options.getOptions1Index(),
     256              :                 option,
     257           22 :                 static_cast<uint32_t>(buffer.size()),
     258              :                 optionCounter,
     259              :                 offset))
     260              :         {
     261            0 :             return SdOptionParser::INVALID_ENDPOINT;
     262              :         }
     263              : 
     264              :         // look at options1
     265           22 :         if (!searchOptions(
     266              :                 optionCategory,
     267              :                 option,
     268           22 :                 static_cast<uint32_t>(buffer.size()),
     269           22 :                 options.getOptions1Num(),
     270              :                 optionCounter,
     271              :                 offset,
     272              :                 foundOption,
     273              :                 foundOptionType,
     274              :                 numUdpOptions,
     275              :                 numTcpOptions))
     276              :         {
     277            1 :             return SdOptionParser::INVALID_ENDPOINT;
     278              :         }
     279              :     }
     280              : 
     281              :     {
     282           21 :         uint8_t const* option = buffer.data();
     283           21 :         uint8_t optionCounter = 0U;
     284           21 :         uint32_t offset       = 0U;
     285              : 
     286              :         // go to options2
     287           21 :         if (!goToOption(
     288           21 :                 options.getOptions2Index(),
     289              :                 option,
     290           21 :                 static_cast<uint32_t>(buffer.size()),
     291              :                 optionCounter,
     292              :                 offset))
     293              :         {
     294            0 :             return SdOptionParser::INVALID_ENDPOINT;
     295              :         }
     296              : 
     297              :         // look at options2
     298           21 :         if (!searchOptions(
     299              :                 optionCategory,
     300              :                 option,
     301           21 :                 static_cast<uint32_t>(buffer.size()),
     302           21 :                 options.getOptions2Num(),
     303              :                 optionCounter,
     304              :                 offset,
     305              :                 foundOption,
     306              :                 foundOptionType,
     307              :                 numUdpOptions,
     308              :                 numTcpOptions))
     309              :         {
     310            0 :             return SdOptionParser::INVALID_ENDPOINT;
     311              :         }
     312              :     }
     313              : 
     314           21 :     if (foundOption == nullptr)
     315              :     {
     316            2 :         return SdOptionParser::INVALID_ENDPOINT;
     317              :     }
     318              : 
     319           19 :     return parseIpOptionType(
     320           19 :         buffer, static_cast<uint16_t>(foundOption - buffer.data()), foundOptionType);
     321              : }
     322              : } // namespace
     323              : 
     324              : // NOLINTNEXTLINE(cert-err58-cpp): Fine, since default value shall be used.
     325              : SdEndpoint const SdOptionParser::INVALID_ENDPOINT;
     326              : 
     327           20 : SdEndpoint SdOptionParser::parseIpEndpointOption(
     328              :     SdOptions const& options, uint8_t& numUdpOptions, uint8_t& numTcpOptions)
     329              : {
     330           40 :     return parseIpOption(OptionCategory::IpEndpointOption, options, numUdpOptions, numTcpOptions);
     331              : }
     332              : 
     333            2 : SdEndpoint SdOptionParser::parseIpMulticastOption(
     334              :     SdOptions const& options, uint8_t& numUdpOptions, uint8_t& numTcpOptions)
     335              : {
     336            4 :     return parseIpOption(OptionCategory::IpMulticastOption, options, numUdpOptions, numTcpOptions);
     337              : }
     338              : 
     339              : } // namespace someip
     340              : 
     341              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1