2025-11-28 00:35:46 +09:00

1160 lines
29 KiB
C

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
TCSample.c
Abstract:
This program implements a simple tool which plumbs in a TC Flow and Filter
based on the user input
Environment:
User-Mode only
------------------------------------------------------------------------------*/
#pragma warning(disable:4995) // Traffic Control was deprecated in Vista timeframe
#pragma warning(disable:4127) // conditional expression is constant
#pragma warning(disable:4201) // nameless struct/union
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <ntddndis.h>
#include <traffic.h>
//******************************************************************************
// Forward declarations
//******************************************************************************
VOID
help();
//******************************************************************************
// Global defines
//******************************************************************************
#define NOT_SPECIFIED 0xFFFF
typedef struct ifc_info
{
HANDLE hIfc;
HANDLE hFlow;
HANDLE hFilter;
} IFC_INFO, *PIFC_INFO;
typedef struct ifc_list
{
ULONG IfcCount;
PIFC_INFO pIfcInfo;
} IFC_LIST, *PIFC_LIST;
//******************************************************************************
// Global variables
//******************************************************************************
TCI_CLIENT_FUNC_LIST ClientHandlerList;
HANDLE hEvent;
//******************************************************************************
// Routine:
// Control_C_Handler
//
// Description:
// Handles the ctrl-c event and sets the gbRunning flag to false
// this indicates the app to exit
//
//******************************************************************************
BOOL
Control_C_Handler(DWORD dwCtrlType)
{
UNREFERENCED_PARAMETER(dwCtrlType);
printf("**Got ^C event**\n");
SetEvent(hEvent);
return TRUE;
}
//******************************************************************************
// Routine:
// ClNotifyHandler
//
// Description:
// Empty notification handler
//
//******************************************************************************
void
ClNotifyHandler(HANDLE ClRegCtx, HANDLE ClIfcCtx, ULONG Event, HANDLE SubCode, ULONG BufSize, PVOID Buffer)
{
UNREFERENCED_PARAMETER(ClRegCtx);
UNREFERENCED_PARAMETER(ClIfcCtx);
//
// Notification was unexpected
//
printf("Unexpected notification: Event=%d, SubCode=%p, BufSize=%d, Buffer=%p", (int)Event, (void *)SubCode, (int)BufSize, Buffer);
}
//******************************************************************************
// Routine:
// AddTcFlows
//
// Description:
// Add Tc Flow in pTcFlow to each interface in IfcList
//
//******************************************************************************
BOOL
AddTcFlows(IFC_LIST IfcList, PTC_GEN_FLOW pTcFlow)
{
UINT i;
ULONG err;
BOOL status = FALSE;
PIFC_INFO pCurrentIfcInfo = IfcList.pIfcInfo;
//
// For each interface in the list, add a TC flow
//
for (i = 0; i < IfcList.IfcCount; i++)
{
HANDLE hFlow;
err = TcAddFlow(pCurrentIfcInfo->hIfc,
0,
0,
pTcFlow,
&hFlow);
if (err != NO_ERROR)
{
printf("TcAddFlow Failed %d\n", err);
goto Exit;
}
pCurrentIfcInfo->hFlow = hFlow;
pCurrentIfcInfo++;
}
status = TRUE;
Exit:
return status;
}
//******************************************************************************
// Routine:
// AddTcFilters
//
// Description:
// Add Tc Filter in pTcFilter to each interface in IfcList
//
//******************************************************************************
BOOL
AddTcFilters(IFC_LIST IfcList, PTC_GEN_FILTER pTcFilter)
{
UINT i;
ULONG err;
BOOL status = FALSE;
PIFC_INFO pCurrentIfcInfo = IfcList.pIfcInfo;
//
// For each interface in the list, add TC filter on the corresponding TcFlow
//
for (i = 0; i < IfcList.IfcCount; i++)
{
HANDLE hFilter;
err = TcAddFilter(pCurrentIfcInfo->hFlow,
pTcFilter,
&hFilter);
if (err != NO_ERROR)
{
printf("TcAddFilter Failed %d\n", err);
goto Exit;
}
pCurrentIfcInfo->hFilter = hFilter;
pCurrentIfcInfo++;
}
status = TRUE;
Exit:
return status;
}
//******************************************************************************
// Routine:
// ClearIfcList
//
// Description:
// Clears the IfcList and its member variables
//
//******************************************************************************
BOOL
ClearIfcList(PIFC_LIST pIfcList)
{
ULONG i;
if (!pIfcList)
{
return TRUE;
}
if (pIfcList->pIfcInfo)
{
//
// Delete filter, flow and interface
//
PIFC_INFO pCurrentIfcInfo = pIfcList->pIfcInfo;
for (i = 0; i < pIfcList->IfcCount; i++)
{
if (pCurrentIfcInfo->hFilter)
{
TcDeleteFilter(pCurrentIfcInfo->hFilter);
}
if (pCurrentIfcInfo->hFlow)
{
TcDeleteFlow(pCurrentIfcInfo->hFlow);
}
if (pCurrentIfcInfo->hIfc)
{
TcCloseInterface(pCurrentIfcInfo->hIfc);
}
pCurrentIfcInfo++;
}
free(pIfcList->pIfcInfo);
}
ZeroMemory(pIfcList, sizeof(IFC_LIST));
return TRUE;
}
//******************************************************************************
// Routine:
// MakeIfcList
//
// Arguments:
// hClient - Handle returned by TcRegisterClient
// pIfcList - ptr to IfcList structure which will be populated by the function
//
// Description:
// The function enumerates all TC enabled interfaces.
// opens each TC enabled interface and stores each ifc handle in IFC_LIST struct
// pointed to by pIfcList
//
//******************************************************************************
BOOL
MakeIfcList(HANDLE hClient, PIFC_LIST pIfcList)
{
BOOL status = FALSE;
ULONG err = ERROR_INVALID_PARAMETER;
ULONG BufferSize = 1, ActualBufferSize, RemainingBufferSize = 0;
PTC_IFC_DESCRIPTOR pIfcBuffer = NULL, pCurrentIfc;
PIFC_INFO pIfcInfo = NULL, pCurrentIfcInfo;
ULONG nIfcs = 0;
//
// Enumerate the TC enabled interfaces
//
while (TRUE)
{
ActualBufferSize = BufferSize;
pIfcBuffer = (PTC_IFC_DESCRIPTOR)malloc(ActualBufferSize);
if (pIfcBuffer == NULL)
{
break;
}
err = TcEnumerateInterfaces(hClient,
&ActualBufferSize,
pIfcBuffer);
if (err == ERROR_INSUFFICIENT_BUFFER)
{
free(pIfcBuffer);
BufferSize *= 2;
}
else
{
break;
}
}
if (err != NO_ERROR)
{
goto Exit;
}
//
// Count the number of interfaces
//
pCurrentIfc = pIfcBuffer;
RemainingBufferSize = ActualBufferSize;
while(RemainingBufferSize)
{
nIfcs++;
RemainingBufferSize -= pCurrentIfc->Length;
pCurrentIfc = (PTC_IFC_DESCRIPTOR)(((PBYTE)pCurrentIfc) + pCurrentIfc->Length);
}
if (nIfcs == 0)
{
goto Exit;
}
//
// Allocate memory for the size(IFC_INFO) X nIfcs
//
pIfcInfo = (PIFC_INFO)malloc(sizeof(IFC_INFO) * nIfcs);
if (!pIfcInfo)
{
goto Exit;
}
ZeroMemory(pIfcInfo, sizeof(IFC_INFO) * nIfcs);
ClearIfcList(pIfcList);
pIfcList->IfcCount = nIfcs;
pIfcList->pIfcInfo = pIfcInfo;
//
// Open Each interface and store the ifc handle in ifcList
//
pCurrentIfc = pIfcBuffer;
pCurrentIfcInfo = pIfcInfo;
RemainingBufferSize = ActualBufferSize;
while (RemainingBufferSize)
{
HANDLE hIfc;
err = TcOpenInterfaceW(pCurrentIfc->pInterfaceName,
hClient,
0,
&hIfc);
if (err != NO_ERROR)
{
printf("TcOpenInterface Failed %d\n", err);
break;
}
pCurrentIfcInfo->hIfc = hIfc;
RemainingBufferSize -= pCurrentIfc->Length;
pCurrentIfc = (PTC_IFC_DESCRIPTOR)(((PBYTE)pCurrentIfc) + pCurrentIfc->Length);
pCurrentIfcInfo++;
}
if (err != NO_ERROR)
{
goto Exit;
}
status = TRUE;
Exit:
if (!status)
{
ClearIfcList(pIfcList);
}
//
// Cleanup the IfcBuffer
//
if (pIfcBuffer)
{
free(pIfcBuffer);
}
return status;
}
//******************************************************************************
// Routine:
// DeleteFlow
//
// Description:
// Deletes the flow and its member variables
//
//******************************************************************************
BOOL
DeleteFlow(PTC_GEN_FLOW *pFlow)
{
if (pFlow == NULL || *pFlow == NULL)
{
return TRUE;
}
free(*pFlow);
*pFlow = NULL;
return TRUE;
}
//******************************************************************************
// Routine:
// CreateFlow
//
// Arguments:
// ppTcFlowObj - double ptr to Flow struct in which the function returns the flow
// DSCPValue - dscp value for the flow
// OnePValue - 802.1p value for the flow
// ThrottleRate - throttle rate for the flow
//
// Description:
// The function returns a tc flow in ppTcFlowObj on success
//
//******************************************************************************
BOOL
CreateFlow(PTC_GEN_FLOW *_ppTcFlowObj, USHORT DSCPValue, USHORT OnePValue, ULONG ThrottleRate)
{
BOOL status = FALSE;
//
// Flow Parameters
//
ULONG TokenRate = QOS_NOT_SPECIFIED;
ULONG TokenBucketSize = QOS_NOT_SPECIFIED;
ULONG PeakBandwidth = QOS_NOT_SPECIFIED;
ULONG Latency = QOS_NOT_SPECIFIED;
ULONG DelayVariation = QOS_NOT_SPECIFIED;
SERVICETYPE ServiceType = SERVICETYPE_BESTEFFORT;
ULONG MaxSduSize = QOS_NOT_SPECIFIED;
ULONG MinimumPolicedSize = QOS_NOT_SPECIFIED;
PVOID pCurrentObject;
PTC_GEN_FLOW _pTcFlowObj = NULL;
int Length = 0;
//
// Calculate the memory size required for the optional TC objects
//
Length += (OnePValue == NOT_SPECIFIED ? 0 : sizeof(QOS_TRAFFIC_CLASS)) +
(DSCPValue == NOT_SPECIFIED ? 0 : sizeof(QOS_DS_CLASS));
//
// Print the Flow parameters
//
printf("Flow Parameters:\n");
DSCPValue == NOT_SPECIFIED ? printf("\tDSCP: *\n"):printf("\tDSCP: %u\n", DSCPValue);
OnePValue == NOT_SPECIFIED ? printf("\t802.1p: *\n"):printf("\t802.1p: %u\n", OnePValue);
if (ThrottleRate == QOS_NOT_SPECIFIED)
{
printf("\tThrottleRate: *\n");
printf("\tServiceType: Best effort\n");
}
else
{
printf("\tThrottleRate: %u\n", ThrottleRate);
printf("\tServiceType: Guaranteed\n");
ServiceType = SERVICETYPE_GUARANTEED;
}
TokenRate = TokenBucketSize = ThrottleRate;
//
// Allocate the flow descriptor
//
_pTcFlowObj = (PTC_GEN_FLOW)malloc(FIELD_OFFSET(TC_GEN_FLOW, TcObjects) + Length);
if (!_pTcFlowObj)
{
printf("Flow Allocation Failed\n");
goto Exit;
}
_pTcFlowObj->SendingFlowspec.TokenRate = TokenRate;
_pTcFlowObj->SendingFlowspec.TokenBucketSize = TokenBucketSize;
_pTcFlowObj->SendingFlowspec.PeakBandwidth = PeakBandwidth;
_pTcFlowObj->SendingFlowspec.Latency = Latency;
_pTcFlowObj->SendingFlowspec.DelayVariation = DelayVariation;
_pTcFlowObj->SendingFlowspec.ServiceType = ServiceType;
_pTcFlowObj->SendingFlowspec.MaxSduSize = MaxSduSize;
_pTcFlowObj->SendingFlowspec.MinimumPolicedSize = MinimumPolicedSize;
memcpy(&(_pTcFlowObj->ReceivingFlowspec), &(_pTcFlowObj->SendingFlowspec), sizeof(_pTcFlowObj->ReceivingFlowspec));
_pTcFlowObj->TcObjectsLength = Length;
//
// Add any requested objects
//
pCurrentObject = (PVOID)_pTcFlowObj->TcObjects;
if (OnePValue != NOT_SPECIFIED)
{
QOS_TRAFFIC_CLASS *pTClassObject = (QOS_TRAFFIC_CLASS*)pCurrentObject;
pTClassObject->ObjectHdr.ObjectType = QOS_OBJECT_TRAFFIC_CLASS;
pTClassObject->ObjectHdr.ObjectLength = sizeof(QOS_TRAFFIC_CLASS);
pTClassObject->TrafficClass = OnePValue; //802.1p tag to be used
pCurrentObject = (PVOID)(pTClassObject + 1);
}
if (DSCPValue != NOT_SPECIFIED)
{
QOS_DS_CLASS *pDSClassObject = (QOS_DS_CLASS*)pCurrentObject;
pDSClassObject->ObjectHdr.ObjectType = QOS_OBJECT_DS_CLASS;
pDSClassObject->ObjectHdr.ObjectLength = sizeof(QOS_DS_CLASS);
pDSClassObject->DSField = DSCPValue; //Services Type
}
DeleteFlow(_ppTcFlowObj);
*_ppTcFlowObj = _pTcFlowObj;
status = TRUE;
Exit:
if (!status)
{
printf("Flow Creation Failed\n");
DeleteFlow(&_pTcFlowObj);
}
else
{
printf("Flow Creation Succeeded\n");
}
return status;
}
//******************************************************************************
// Routine:
// DeleteFilter
//
// Description:
// Deletes the filter and its member variables
//
//******************************************************************************
BOOL
DeleteFilter(PTC_GEN_FILTER *ppFilter)
{
PTC_GEN_FILTER pFilter;
if (ppFilter == NULL || *ppFilter == NULL)
{
return TRUE;
}
pFilter = (*ppFilter);
if (pFilter->Pattern)
{
free(pFilter->Pattern);
}
if (pFilter->Mask)
{
free(pFilter->Mask);
}
*ppFilter = NULL;
return TRUE;
}
//******************************************************************************
// Routine:
// PrintAddress
//
// Description:
// The function prints out the address contained in the SOCKADDR_STORAGE
//
//******************************************************************************
VOID
PrintAddress(PSOCKADDR_STORAGE pSocketAddress)
{
DWORD cbBuffer = 2000;
WCHAR buffer[2000];
SOCKADDR_STORAGE socketAddress;
ULONG Length;
if (!pSocketAddress)
{
return;
}
ZeroMemory(buffer, sizeof(buffer));
ZeroMemory(&socketAddress, sizeof(socketAddress));
//
// If the address is empty, print *
//
if (!memcmp(((PBYTE)&socketAddress) + sizeof(USHORT),
((PBYTE)pSocketAddress) + sizeof(USHORT),
sizeof(socketAddress) - sizeof(USHORT)))
{
printf("\tAddress: *\n");
return;
}
Length = (pSocketAddress->ss_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6));
if (SOCKET_ERROR == WSAAddressToStringW((LPSOCKADDR)(pSocketAddress),
Length,
NULL,
buffer,
&cbBuffer))
{
printf("WSAAddressToStringW() failed with 0x%x\n", WSAGetLastError());
buffer[0] = L'\0';
}
printf("\tAddress: %S\n", buffer);
}
//******************************************************************************
// Routine:
// CreateFilter
//
// Arguments:
// ppFilter - double ptr to Filter struct in which the function returns the filter
// Address - destination address of the outgoing packets of interest.
// Port - destination port of the outgoing packets of interest.
// ProtocolId - protocol of the outgoing packets of interest.
//
// Description:
// The function returns a tc filter in ppFilter on success
//
//******************************************************************************
BOOL
CreateFilter(PTC_GEN_FILTER *ppFilter, SOCKADDR_STORAGE Address, USHORT Port, UCHAR ProtocolId)
{
BOOL status = FALSE;
USHORT AddressFamily = Address.ss_family;
PTC_GEN_FILTER pFilter = NULL;
PIP_PATTERN pPattern = NULL;
PIP_PATTERN pMask = NULL;
//
// Print out the Filter Parameters
//
printf("Filter Parameters:\n");
PrintAddress(&Address);
printf("\tDest Port: %u\n", Port);
printf("\tProtocol: ");
switch (ProtocolId)
{
case IPPROTO_IP:
{
printf("IP\n");
break;
}
case IPPROTO_TCP:
{
printf("TCP\n");
break;
}
case IPPROTO_UDP:
{
printf("UDP\n");
break;
}
default:
{
printf("Invalid Protocol\n");
break;
}
};
if (AddressFamily != AF_INET)
{
goto Exit;
}
//
// Allocate memory for the filter
//
pFilter = (PTC_GEN_FILTER)malloc(sizeof(TC_GEN_FILTER));
if (!pFilter)
{
printf("Error, No memory for filter\n");
goto Exit;
}
ZeroMemory(pFilter, sizeof(TC_GEN_FILTER));
//
// Allocate memory for the pattern and mask
//
pPattern = (PIP_PATTERN)malloc(sizeof(IP_PATTERN));
pMask = (PIP_PATTERN)malloc(sizeof(IP_PATTERN));
if (!pPattern || !pMask)
{
goto Exit;
}
memset(pPattern, 0, sizeof(IP_PATTERN));
pPattern->DstAddr = ((SOCKADDR_IN *)&Address)->sin_addr.s_addr;
pPattern->tcDstPort = htons(Port);
pPattern->ProtocolId = ProtocolId;
memset(pMask, (ULONG)-1, sizeof(IP_PATTERN));
//
// Set the source address and port to wildcard
// 0 -> wildcard, 0xFF-> exact match
//
pMask->SrcAddr = 0;
pMask->tcSrcPort = 0;
//
// If the user specified 0 for dest port, dest address or protocol
// set the appropriate mask as wildcard
// 0 -> wildcard, 0xFF-> exact match
//
if (pPattern->tcDstPort == 0)
{
pMask->tcDstPort = 0;
}
if (pPattern->ProtocolId == 0)
{
pMask->ProtocolId = 0;
}
if (pPattern->DstAddr == 0)
{
pMask->DstAddr = 0;
}
pFilter->AddressType = NDIS_PROTOCOL_ID_TCP_IP;
pFilter->PatternSize = sizeof(IP_PATTERN);
pFilter->Pattern = pPattern;
pFilter->Mask = pMask;
//
// Delete any previous instances of the Filter
//
DeleteFilter(ppFilter);
*ppFilter = pFilter;
status = TRUE;
Exit:
if (!status)
{
printf("Filter Creation Failed\n");
DeleteFilter(&pFilter);
}
else
{
printf("Filter Creation Succeeded\n");
}
return status;
}
//******************************************************************************
// Routine:
// GetSockAddrFromString
//
// Arguments:
// strAddress - Address in the String format
// pSocketAddress - Pointer to SOCKADDR_STORAGE structure where the
// address is returned
//
// Description:
// Takes a string format address and returns a pointer to
// SOCKADDR_STORAGE structure containing the address.
// Only resolves numeric addresses
//******************************************************************************
BOOL
GetSockAddrFromString(const WCHAR *strAddress, PSOCKADDR_STORAGE pSocketAddress)
{
BOOL result = FALSE;
ADDRINFOW *pAddress = NULL;
int wsaResult = 0;
ADDRINFOW hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
// Resolve the address
wsaResult = GetAddrInfoW(strAddress, NULL, &hints, &pAddress);
if (0 != wsaResult)
{
printf("Failed to resolve \"%S\". GetAddrInfoW() failed with 0x%x\n", strAddress, wsaResult);
goto Exit;
}
// Make sure the address resolved to only one entry
if (NULL != pAddress->ai_next)
{
printf("%S Resolved to more than one address. Please use a numeric Address\n", strAddress);
goto Exit;
}
// Copy the address to the storage
CopyMemory(pSocketAddress, pAddress->ai_addr, pAddress->ai_addrlen);
result = TRUE;
Exit:
// Cleanup
if (NULL != pAddress)
{
FreeAddrInfoW(pAddress);
}
return result;
}
//******************************************************************************
// Routine:
// ParseCommandline
//
// Arguments:
// argv - Commandline Parameters
// pTcFlow - Pointer to PTC_GEN_FLOW structure.
// pTcFilter - Pointer to PTC_GEN_FILTER structure.
//
// Description:
// Parses the commandline and populates creates TC_GEN_FLOW and
// TC_GEN_FILTER structures with the appropriate values.
//******************************************************************************
BOOL
ParseCommandLine(WCHAR **argv, PTC_GEN_FLOW *pTcFlow, PTC_GEN_FILTER *pTcFilter)
{
BOOL status = FALSE;
UCHAR ProtocolId = 0;
USHORT Port = 0;
USHORT DSCPValue = NOT_SPECIFIED, OnePValue = NOT_SPECIFIED;
ULONG ThrottleRate = QOS_NOT_SPECIFIED;
PWCHAR strAddress = L"0";
SOCKADDR_STORAGE Address = { 0 };
Address.ss_family = AF_INET;
//
// Extract commandline parameters and do some basic validation
//
argv++;
while (*argv)
{
if (!_wcsicmp(*argv, L"-proto"))
{
argv++;
if (!(*argv))
{
goto Exit;
}
if (!_wcsicmp(*(argv), L"tcp"))
{
ProtocolId = IPPROTO_TCP;
}
else if (!_wcsicmp(*(argv), L"udp"))
{
ProtocolId = IPPROTO_UDP;
}
else if (!_wcsicmp(*(argv), L"ip"))
{
ProtocolId = IPPROTO_IP;
}
else
{
printf("Invalid Protocol\n");
goto Exit;
}
}
else if (!_wcsicmp(*argv, L"-destip"))
{
argv++;
if (!(*argv))
{
goto Exit;
}
strAddress = (*argv);
}
else if (!_wcsicmp(*argv, L"-destport"))
{
argv++;
if (!(*argv))
{
goto Exit;
}
Port = (USHORT)_wtoi(*(argv));
}
else if (!_wcsicmp(*argv, L"-dscp"))
{
argv++;
if (!(*argv))
{
goto Exit;
}
DSCPValue = (USHORT)_wtoi(*(argv));
if (DSCPValue < 0 || DSCPValue > 63)
{
printf("Invalid DSCP Value\n");
goto Exit;
}
}
else if (!_wcsicmp(*argv, L"-onep"))
{
argv++;
if (!(*argv))
{
goto Exit;
}
OnePValue = (USHORT)_wtoi(*(argv));
if (OnePValue < 0 || OnePValue > 7)
{
printf("Invalid 802.1p Value\n");
goto Exit;
}
}
else if (!_wcsicmp(*argv, L"-throttle"))
{
argv++;
if (!(*argv))
{
goto Exit;
}
ThrottleRate = (ULONG)_wtoi(*(argv));
}
else
{
goto Exit;
}
argv++;
}
//
// if dest addr is not specified or specified as zero
// treat it as wildcard, dont try to resolve it
//
if (_wtoi(strAddress) != 0)
{
if (!GetSockAddrFromString(strAddress, &Address))
{
goto Exit;
}
}
//
// Create the TC Flow with the parameters
//
if (!CreateFlow(pTcFlow, DSCPValue, OnePValue, ThrottleRate))
{
goto Exit;
}
//
// Create the TC Filter with the parameters
//
if (!CreateFilter(pTcFilter, Address, Port, ProtocolId))
{
goto Exit;
}
status = TRUE;
Exit:
if (!status)
{
printf("Invalid Argument(s)\n");
}
return status;
}
//******************************************************************************
// Routine:
// main
//
// Description:
// Entry point. Parses the commandline and calls CreateFilter and CreateFlow
// with appropriate parameters.
//******************************************************************************
int _cdecl wmain(int argc, WCHAR *argv[])
{
BOOL status = FALSE;
ULONG err;
int wsaResult;
//
// TC Structures
//
PTC_GEN_FLOW pTcFlow = NULL;
PTC_GEN_FILTER pTcFilter = NULL;
HANDLE hClient = TC_INVALID_HANDLE;
IFC_LIST IfcList = { 0 };
WSADATA wsaData;
UNREFERENCED_PARAMETER(argc);
#if !defined (_WIN64) && _WIN32_WINNT >= 0x0600
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
#endif
//
// Start Winsock
//
wsaResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsaResult != 0)
{
printf("Winsock Startup Failed\n");
help();
return 0;
}
//
// Parse the Commandline and populate the TC_GEN_FILTER and TC_GEN_FLOW structures
//
if (!ParseCommandLine(argv, &pTcFlow, &pTcFilter))
{
goto Exit;
}
//
// Register TC client
//
memset(&ClientHandlerList, 0, sizeof(ClientHandlerList));
ClientHandlerList.ClNotifyHandler = (TCI_NOTIFY_HANDLER)ClNotifyHandler;
err = TcRegisterClient(CURRENT_TCI_VERSION,
0,
&ClientHandlerList,
&hClient);
if (err != NO_ERROR)
{
printf("TcRegisterClient Failed %d\n", err);
if (err == ERROR_OPEN_FAILED)
{
printf("Please make sure you are running with admin credentials\n");
}
goto Exit;
}
//
// Enumerate All TC enabled Interfaces and
// store the information in IfcList
//
if (!MakeIfcList(hClient, &IfcList))
{
printf("Error reading interface list, make sure QoS Packet Scheduler is active for this interface\n");
goto Exit;
}
printf("Interface list created...\n");
//
// Add pTcFlow on all the Ifcs in the IfcList
//
if (!AddTcFlows(IfcList, pTcFlow))
{
printf("Error adding flows\n");
goto Exit;
}
printf("Flows added...\n");
//
// Add pTcFilter to all the corresponding TcFlows
// on all the Ifcs in the IfcList
//
if (!AddTcFilters(IfcList, pTcFilter))
{
printf("Error adding filter...\n");
goto Exit;
}
printf("Filter added...\n");
//
// Enable the Ctrl-C handler
//
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!hEvent)
{
printf("Failed to create event\n");
goto Exit;
}
printf("**Hit ^C to Exit**\n");
SetConsoleCtrlHandler((PHANDLER_ROUTINE)Control_C_Handler, TRUE);
WaitForSingleObject(hEvent, INFINITE);
SetConsoleCtrlHandler((PHANDLER_ROUTINE)Control_C_Handler, FALSE);
status = TRUE;
Exit:
if (!status)
{
help();
}
//
// Cleanup
//
ClearIfcList(&IfcList);
DeleteFilter(&pTcFilter);
DeleteFlow(&pTcFlow);
TcDeregisterClient(hClient);
WSACleanup();
if (hEvent)
{
CloseHandle(hEvent);
}
return 0;
}
//******************************************************************************
// Routine:
// help
//
// Description:
// This routine prints out the usage information for the program
//
//******************************************************************************
VOID
help()
{
printf("\nUsage: tcsample <optional parameters>\n");
printf("\t-proto : protocol(tcp/udp/ip) (Default: All IP Protocols)\n");
printf("\t-destip : destination IP Address (Default: All IP Addresses)\n");
printf("\t-destport: destination port number (Default: All Ports)\n");
printf("\t-dscp : dscp value to tag matching packets (Default: No DSCP Override)\n");
printf("\t-onep : 802.1p value to tag matching packets (Default: No 802.1p Override)\n");
printf("\t-throttle: throttle rate(Bps) to throttle matching packets (Default: No Throttling)\n");
printf("\nExample: tcsample -destip 192.168.1.10 -proto ip -dscp 40\n");
printf("will result in all outgoing IP Packets destined to\n");
printf("192.168.1.10 to be marked with DSCP value 40\n");
}