static BOOLEAN _MasksFromArgs_HandleEncap(_In_ const OVS_ARGUMENT_GROUP* pMaskGroup, _Inout_ OVS_ARGUMENT* pEncapArg, _Inout_ OVS_ARGUMENT* pEtherTypeArg)
{
    BE16 ethType = 0;
    BE16 vlanTci = 0;
    BOOLEAN ok = TRUE;
    OVS_ARGUMENT* pVlanTciArg = NULL;

    OVS_CHECK(pEncapArg);

    pEncapArg->isDisabled = TRUE;

    if (pEtherTypeArg)
    {
        ethType = GET_ARG_DATA(pEtherTypeArg, BE16);
    }
    else
    {
        DEBUGP(LOG_ERROR, "The eth type argument was not found\n");
        return FALSE;
    }

    if (ethType == OVS_PI_MASK_MATCH_EXACT(UINT16))
    {
        pEtherTypeArg->isDisabled = TRUE;
    }
    else
    {
        DEBUGP(LOG_ERROR, "The vlan frame must have an exact match for ethType. Mask value: %x.\n", RtlUshortByteSwap(ethType));
        return FALSE;
    }

    pVlanTciArg = FindArgument(pMaskGroup, OVS_ARGTYPE_PI_VLAN_TCI);

    if (pVlanTciArg)
    {
        vlanTci = GET_ARG_DATA(pVlanTciArg, BE16);
    }
    else
    {
        DEBUGP(LOG_ERROR, "vlan tci arg not given");
        return FALSE;
    }

    if (!(vlanTci & RtlUshortByteSwap(OVS_VLAN_TAG_PRESENT)))
    {
        DEBUGP(LOG_ERROR, "The vlan field 'tag present' bit must be exact match! Mask value: %x.\n", RtlUshortByteSwap(vlanTci));
        return FALSE;
    }

    return ok;
}
static BOOLEAN _GetPIFromArg_EthType(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT* pEthTypeArg, _In_ BOOLEAN isMask)
{
    BE16 ethType = GET_ARG_DATA(pEthTypeArg, BE16);

    if (isMask)
    {
        ethType = OVS_PI_MASK_MATCH_EXACT(UINT16);
    }

    if (!isMask)
    {
        EXPECT(RtlUshortByteSwap(ethType) >= OVS_ETHERTYPE_802_3_MIN);
    }

    OVS_PI_UPDATE_ETHINFO_FIELD(pPacketInfo, pPiRange, pEthTypeArg, BE16, type);

    return TRUE;
}
static BOOLEAN _PIFromArg_DatapathInPort(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT* pArg, BOOLEAN isMask)
{
    UINT16 inPort = (UINT16)GET_ARG_DATA(pArg, UINT32);

    if (isMask)
    {
        inPort = OVS_PI_MASK_MATCH_EXACT(UINT16);
    }

    if (!isMask)
    {
        EXPECT(inPort < OVS_MAX_PORTS);
    }

    OVS_PI_UPDATE_PHYSICAL_FIELD_VALUE(pPacketInfo, pPiRange, ofInPort, inPort);

    return TRUE;
}
static BOOLEAN _PIFromArgs_HandleEncap(_In_ const OVS_ARGUMENT_GROUP* pPIGroup, _Inout_ OVS_ARGUMENT* pEthTypeArg, _Out_ BOOLEAN* pEncapValid)
{
    BE16 vlanTci = 0;

    OVS_ARGUMENT* pVlanTciArg = NULL, *pEncapArg = NULL;

    OVS_CHECK(pEncapValid);
    OVS_CHECK(pEthTypeArg);

    *pEncapValid = FALSE;

    pVlanTciArg = FindArgument(pPIGroup, OVS_ARGTYPE_PI_VLAN_TCI);

    pEncapArg = FindArgument(pPIGroup, OVS_ARGTYPE_PI_ENCAP_GROUP);

    if (!pVlanTciArg || !pEncapArg)
    {
        DEBUGP(LOG_ERROR, "the vlan frame is invalid!\n");
        return FALSE;
    }

    pEthTypeArg->isDisabled = TRUE;

    vlanTci = GET_ARG_DATA(pVlanTciArg, BE16);
    pEncapArg->isDisabled = TRUE;

    *pEncapValid = TRUE;

    if (!vlanTci)
    {
        if (pEncapArg->length > 0)
        {
            DEBUGP(LOG_ERROR, "The truncated vlan header has vlan tci != 0!\n");
            return FALSE;
        }
    }
    else
    {
        DEBUGP(LOG_ERROR, "Tried to set encapsulation data to a non-vlan frame!\n");
        return FALSE;
    }

    return TRUE;
}
BOOLEAN GetFlowMatchFromArguments(_Inout_ OVS_FLOW_MATCH* pFlowMatch, _In_ const OVS_ARGUMENT_GROUP* pPIGroup, const OVS_ARGUMENT_GROUP* pPIMaskGroup)
{
    BOOLEAN encapIsValid = FALSE;
    BOOLEAN ok = TRUE;
    OVS_ARGUMENT* pEthTypeArg = NULL, *pEthAddrArg = NULL;
    OVS_PI_RANGE* pPiRange = NULL;
    OVS_OFPACKET_INFO* pPacketInfo = NULL;

    OVS_CHECK(pFlowMatch);

    if (!pFlowMatch)
    {
        return FALSE;
    }

    pEthTypeArg = FindArgument(pPIGroup, OVS_ARGTYPE_PI_ETH_TYPE);
#if OVS_VERSION == OVS_VERSION_1_11
    EXPECT(pEthAddrArg);
#endif

    pEthAddrArg = FindArgument(pPIGroup, OVS_ARGTYPE_PI_ETH_ADDRESS);
    EXPECT(pEthAddrArg);

    if (pEthTypeArg && RtlUshortByteSwap(OVS_ETHERTYPE_QTAG) == GET_ARG_DATA(pEthTypeArg, BE16))
    {
        if (!_PIFromArgs_HandleEncap(pPIGroup, pEthAddrArg, &encapIsValid))
        {
            return FALSE;
        }
    }

    pPiRange = &pFlowMatch->piRange;
    pPacketInfo = pFlowMatch->pPacketInfo;

    ok = GetPacketInfoFromArguments(pPacketInfo, pPiRange, pPIGroup, /*isMask*/ FALSE);
    if (!ok)
    {
        return FALSE;
    }

    if (!pPIMaskGroup)
    {
        if (pFlowMatch->pFlowMask)
        {
            UINT8* pStart = (UINT8*)&pFlowMatch->pFlowMask->packetInfo + pPiRange->startRange;
            UINT16 range = (UINT16)(pPiRange->endRange - pPiRange->startRange);

            pFlowMatch->pFlowMask->piRange = *pPiRange;
            memset(pStart, OVS_PI_MASK_MATCH_EXACT(UINT8), range);
        }
    }
    else
    {
        OVS_ARGUMENT* pEncapArg = NULL;

        pEncapArg = FindArgument(pPIMaskGroup, OVS_ARGTYPE_PI_ENCAP_GROUP);

        if (pEncapArg)
        {
            if (!encapIsValid)
            {
                DEBUGP(LOG_ERROR, "Tryed to set encapsulation to non-vlan frame!\n");
                return FALSE;
            }

            if (!pEthTypeArg || !_MasksFromArgs_HandleEncap(pPIMaskGroup, pEncapArg, pEthTypeArg))
            {
                return FALSE;
            }
        }

        OVS_CHECK(pFlowMatch->pFlowMask);
        pPiRange = &pFlowMatch->pFlowMask->piRange;
        pPacketInfo = &pFlowMatch->pFlowMask->packetInfo;

        ok = GetPacketInfoFromArguments(pPacketInfo, pPiRange, pPIMaskGroup, /*is mask*/TRUE);
        if (!ok)
        {
            return FALSE;
        }
    }

    //if the userspace gives us bad / unexpected args, we cannot simply deny the flow:
    //a) this might not be a bug (i.e. the userspace intends to set flows like this)
    //b) if it is a bug, we can do little in the kernel to help it.
#if __VERIFY_MASKS
    if (!_VerifyMasks(pFlowMatch, pPIGroup, pPIMaskGroup))
    {
        return FALSE;
    }
#endif

    return TRUE;
}
BOOLEAN GetPacketInfoFromArguments(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT_GROUP* pPIGroup, _In_ BOOLEAN isMask)
{
    BOOLEAN haveIpv4 = FALSE;
    OVS_ARGUMENT* pVlanTciArg = NULL, *pEthTypeArg = NULL, *pDatapathInPortArg = NULL;

    OVS_CHECK(pPacketInfo);
    OVS_CHECK(pPiRange);

    for (UINT i = 0; i < pPIGroup->count; ++i)
    {
        OVS_ARGUMENT* pArg = pPIGroup->args + i;
        OVS_ARGTYPE argType = pArg->type;

        switch (argType)
        {
        case OVS_ARGTYPE_PI_DATAPATH_HASH:
            OVS_PI_UPDATE_MAIN_FIELD(pPacketInfo, pPiRange, pArg, UINT32, flowHash);
            break;

        case OVS_ARGTYPE_PI_DATAPATH_RECIRCULATION_ID:
            OVS_PI_UPDATE_MAIN_FIELD(pPacketInfo, pPiRange, pArg, UINT32, recirculationId);
            break;

        case OVS_ARGTYPE_PI_PACKET_PRIORITY:
            OVS_PI_UPDATE_PHYSICAL_FIELD(pPacketInfo, pPiRange, pArg, UINT32, packetPriority);
            break;

        case OVS_ARGTYPE_PI_DP_INPUT_PORT:
            pDatapathInPortArg = pArg;
            EXPECT(_PIFromArg_DatapathInPort(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_PACKET_MARK:
            OVS_PI_UPDATE_PHYSICAL_FIELD(pPacketInfo, pPiRange, pArg, UINT32, packetMark);
            break;

        case OVS_ARGTYPE_PI_TUNNEL_GROUP:
            OVS_CHECK(IsArgTypeGroup(pArg->type));
            EXPECT(_PIFromArg_Tunnel(pArg->data, pPacketInfo, pPiRange, isMask));
            break;

        case OVS_ARGTYPE_PI_ETH_ADDRESS:
        {
            const OVS_PI_ETH_ADDRESS* pEthAddressPI = pArg->data;

            OVS_PI_UPDATE_ETHINFO_ADDRESS(pPacketInfo, pPiRange, source, pEthAddressPI->source);
            OVS_PI_UPDATE_ETHINFO_ADDRESS(pPacketInfo, pPiRange, destination, pEthAddressPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_VLAN_TCI:
            pVlanTciArg = pArg;
            {
                BE16 tci = GET_ARG_DATA(pVlanTciArg, BE16);

                EXPECT(tci & RtlUshortByteSwap(OVS_VLAN_TAG_PRESENT));
                OVS_PI_UPDATE_ETHINFO_FIELD(pPacketInfo, pPiRange, pVlanTciArg, BE16, tci);
            }
            break;

        case OVS_ARGTYPE_PI_ETH_TYPE:
            pEthTypeArg = pArg;
            EXPECT(_GetPIFromArg_EthType(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_IPV4:
            haveIpv4 = TRUE;
            EXPECT(_GetPIFromArg_Ipv4(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_IPV6:
            EXPECT(_GetPIFromArg_Ipv6(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_ARP:
            EXPECT(_GetPIFromArg_Arp(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_MPLS:
        {
            const OVS_PI_MPLS* pMplsPI = pArg->data;

            OVS_PI_UPDATE_NETINFO_FIELD_VALUE(pPacketInfo, pPiRange, mplsTopLabelStackEntry, pMplsPI->mplsLse);
        }
            break;

        case OVS_ARGTYPE_PI_TCP:
        {
            const OVS_PI_TCP* pTcpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pTcpPI->source);
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pTcpPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_TCP_FLAGS:
            OVS_PI_UPDATE_TPINFO_FIELD(pPacketInfo, pPiRange, pArg, BE16, tcpFlags);
            break;

        case OVS_ARGTYPE_PI_UDP:
        {
            const OVS_PI_UDP* pUdpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pUdpPI->source);
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pUdpPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_SCTP:
        {
            const OVS_PI_SCTP* pSctpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pSctpPI->source);
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pSctpPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_ICMP:
        {
            const OVS_PI_ICMP* pIcmpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, RtlUshortByteSwap(pIcmpPI->type));
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, RtlUshortByteSwap(pIcmpPI->code));
        }
            break;

        case OVS_ARGTYPE_PI_ICMP6:
        {
            const OVS_PI_ICMP6* pIcmpv6PI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, RtlUshortByteSwap(pIcmpv6PI->type));
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, RtlUshortByteSwap(pIcmpv6PI->code));
        }
            break;

        case OVS_ARGTYPE_PI_NEIGHBOR_DISCOVERY:
            _GetPIFromArg_NeighborDiscovery(pPacketInfo, pPiRange, pArg);
            break;

        default:
            DEBUGP(LOG_ERROR, __FUNCTION__ " unexpected key / mask arg type: %u\n", pArg->type);
            return FALSE;
        }
    }

    if (!pDatapathInPortArg && !isMask)
    {
        OVS_PI_UPDATE_PHYSICAL_FIELD_VALUE(pPacketInfo, pPiRange, packetMark, OVS_INVALID_PORT_NUMBER);
    }

    if (!pVlanTciArg)
    {
        if (!isMask)
        {
            //TODO: we should normally set vlan tci to 0xFFFF in this case.
            //but it used to work with 0 only
            OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, tci, 0);
        }
    }

    if (!pEthTypeArg)
    {
        if (isMask)
        {
            OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, type, OVS_PI_MASK_MATCH_EXACT(UINT16));
        }
        else
        {
            OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, type, RtlUshortByteSwap(OVS_ETHERTYPE_802_2));
        }
    }

    return TRUE;
}