/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: routing\netsh\ip\iphandle.c Abstract: Fns to get command options Revision History: Anand Mahalingam 7/10/98 Created --*/ #include "precomp.h" #pragma hdrstop #undef EXTRA_DEBUG #define SHOW_IF_FILTER 0 #define SHOW_INTERFACE 1 #define SHOW_PERSISTENTROUTE 2 extern ULONG g_ulNumTopCmds; extern ULONG g_ulNumGroups; extern CMD_GROUP_ENTRY g_IpCmdGroups[]; extern CMD_ENTRY g_IpCmds[]; DWORD PreHandleCommand( IN LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN TAG_TYPE *pttTags, IN DWORD dwTagCount, IN DWORD dwMinArgs, IN DWORD dwMaxArgs, OUT DWORD *pdwTagType ) { ZeroMemory(pdwTagType, sizeof(DWORD) * dwMaxArgs); return PreprocessCommand(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwTagCount, dwMinArgs, dwMaxArgs, pdwTagType); } DWORD HandleIpUpdate( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Updates IP autostatic routes on an interface Arguments: Return Value: NO_ERROR --*/ { TAG_TYPE rgTags[] = {TOKEN_NAME, TRUE,FALSE}; DWORD dwErr, dwSize, dwTagType = -1; WCHAR rgwcIfName[MAX_INTERFACE_NAME_LEN+1]; if (dwArgCount != 3) { // // Need the name of the interface // return ERROR_INVALID_SYNTAX; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, rgTags, sizeof(rgTags)/sizeof(TAG_TYPE), &dwTagType); if(dwErr isnot NO_ERROR) { if(dwErr is ERROR_INVALID_OPTION_TAG) { return ERROR_INVALID_SYNTAX; } return dwErr; } if(dwTagType isnot 0) { return ERROR_INVALID_SYNTAX; } dwSize = sizeof(rgwcIfName); IpmontrGetIfNameFromFriendlyName(ppwcArguments[dwCurrentIndex], rgwcIfName, &dwSize); dwErr = UpdateAutoStaticRoutes(rgwcIfName); return dwErr; } // (almost) borrowed from netsh\if\utils.c // compares dwAddress against all valid masks (all 33 of them!) till a match BOOL ValidMask(DWORD dwAddress) { DWORD i, dwMask; dwAddress = ntohl(dwAddress); // dwAddress is in network byte order for (i=0, dwMask=0; i<33; (dwMask = ((dwMask>>1) + 0x80000000)), i++) { if (dwAddress == dwMask) return TRUE; } return FALSE; } DWORD IpAddDelIfFilter( PWCHAR *ppwcArguments, DWORD dwCurrentIndex, DWORD dwArgCount, BOOL bAdd ) /*++ Routine Description: Gets options for add/del interface filters Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg bAdd - To add or to delete Return Value: NO_ERROR --*/ { FILTER_INFO fi; DWORD dwBitVector = 0, dwNumParsed = 0; DWORD dwErr = NO_ERROR,dwRes; PDWORD pdwTagType; DWORD dwNumOpt, dwStatus = (DWORD) -1; DWORD dwNumTags = 11, dwNumArg, i, j, dwFilterType; WCHAR wszIfName[MAX_INTERFACE_NAME_LEN + 1] = L"\0"; BOOL bTags = FALSE, bOkay = TRUE; TAG_TYPE pttTags[] = {{TOKEN_NAME,TRUE,FALSE}, {TOKEN_FILTER_TYPE,TRUE,FALSE}, {TOKEN_SOURCE_ADDRESS,TRUE,FALSE}, {TOKEN_SOURCE_MASK,TRUE,FALSE}, {TOKEN_DEST_ADDRESS,TRUE,FALSE}, {TOKEN_DEST_MASK,TRUE,FALSE}, {TOKEN_PROTOCOL,TRUE,FALSE}, {TOKEN_SOURCE_PORT,TRUE,FALSE}, {TOKEN_DEST_PORT,TRUE,FALSE}, {TOKEN_TYPE,TRUE,FALSE}, {TOKEN_CODE,TRUE,FALSE}}; if (dwCurrentIndex >= dwArgCount) { // // No arguments specified // return ERROR_SHOW_USAGE; } ZeroMemory(&fi, sizeof(fi)); dwNumArg = dwArgCount - dwCurrentIndex; pdwTagType = HeapAlloc(GetProcessHeap(), 0, dwNumArg * sizeof(DWORD)); if (pdwTagType is NULL) { DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_NOT_ENOUGH_MEMORY; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwNumTags, pdwTagType); if (dwErr isnot NO_ERROR) { if (dwErr is ERROR_INVALID_OPTION_TAG) { dwErr = ERROR_INVALID_SYNTAX; // show usage } HeapFree(GetProcessHeap(),0,pdwTagType); return dwErr; } bTags = TRUE; for ( i = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case 0 : { DWORD BufLen = sizeof(wszIfName); GetInterfaceName(ppwcArguments[i + dwCurrentIndex], wszIfName, BufLen, &dwNumParsed); // no filters allowed on INTERNAL/LOOPBACK interfaces if (!_wcsicmp(wszIfName, L"internal") or !_wcsicmp(wszIfName, L"loopback")) { DisplayMessage(g_hModule, MSG_IP_BAD_INTERFACE_TYPE, wszIfName); dwErr = ERROR_INVALID_PARAMETER; i = dwNumArg; } break; } case 1: { TOKEN_VALUE rgEnums[] = {{TOKEN_VALUE_INPUT, IP_IN_FILTER_INFO}, {TOKEN_VALUE_OUTPUT, IP_OUT_FILTER_INFO}, {TOKEN_VALUE_DIAL, IP_DEMAND_DIAL_FILTER_INFO}}; // // Tag FILTERTYPE // dwErr = MatchEnumTag(g_hModule, ppwcArguments[i + dwCurrentIndex], sizeof(rgEnums)/sizeof(TOKEN_VALUE), rgEnums, &dwRes); if(dwErr != NO_ERROR) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); DisplayMessage( g_hModule, MSG_IP_BAD_OPTION_ENUMERATION, pttTags[pdwTagType[i]].pwszTag ); for (i=0; i 255)) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); DisplayMessage( g_hModule, MSG_IP_BAD_OPTION_ENUMERATION, pttTags[pdwTagType[i]].pwszTag ); for (i=0; i= dwNumArg) { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } if (bTags && (pdwTagType[i+1] != 7 || pdwTagType[i+2] != 8)) { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } fi.wSrcPort = htons((WORD)wcstoul(ppwcArguments[i + 1 + dwCurrentIndex], NULL, 10)); fi.wDstPort = htons((WORD)wcstoul(ppwcArguments[i + 2 + dwCurrentIndex], NULL, 10)); i += 2; break; case FILTER_PROTO_ICMP : // // Get the src and dst ports too // if (i + 2 >= dwNumArg) { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } // src and dest ports acted upon as type and code if (bTags && (pdwTagType[i+1] != 7 || pdwTagType[i+2] != 8) && (pdwTagType[i+1] != 9 || pdwTagType[i+2] != 10)) { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } fi.wSrcPort = (BYTE)wcstoul(ppwcArguments[i + 1 + dwCurrentIndex], NULL, 10); fi.wDstPort = (BYTE)wcstoul(ppwcArguments[i + 2 + dwCurrentIndex], NULL, 10); i += 2; break; default: { // // any 'other' protocol // fi.wSrcPort = fi.wDstPort = 0; break; } } break; } default: { i = dwNumArg; dwErr = ERROR_INVALID_SYNTAX; break; } } } HeapFree(GetProcessHeap(), 0, pdwTagType); switch(dwErr) { case NO_ERROR : break; default: return dwErr; } if (!bOkay) { return NO_ERROR; } // // Make sure all parameters are present // if ( !pttTags[0].bPresent || !pttTags[1].bPresent || !pttTags[2].bPresent || !pttTags[3].bPresent || !pttTags[4].bPresent || !pttTags[5].bPresent || !pttTags[6].bPresent ) { DisplayMessage(g_hModule, MSG_CANT_FIND_EOPT); return ERROR_INVALID_SYNTAX; } dwErr = AddDelFilterInfo(fi, wszIfName, dwFilterType, bAdd); return dwErr; } DWORD HandleIpAddIfFilter( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Gets options for add interface filters Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { return IpAddDelIfFilter(ppwcArguments, dwCurrentIndex, dwArgCount, TRUE); } DWORD HandleIpDelIfFilter( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Gets options for del interface filters Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { return IpAddDelIfFilter(ppwcArguments, dwCurrentIndex, dwArgCount, FALSE); } DWORD IpAddSetDelRtmRoute( PWCHAR *ppwcArguments, DWORD dwCurrentIndex, DWORD dwArgCount, DWORD dwCommand ) /*++ Routine Description: Gets options for add/del routes over interfaces. These operations are performed directly to RTM and do not involve the registry. As persistence is not involved, we need the router to be running. Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg dwCommand - To add, set, or delete Return Value: NO_ERROR --*/ { INTERFACE_ROUTE_INFO route; DWORD dwNumParsed, dwErr, dwRes; DWORD dwNumOpt, dwStatus = (DWORD) -1; DWORD dwNumArg, i; WCHAR wszIfName[MAX_INTERFACE_NAME_LEN + 1] = L"\0"; TAG_TYPE pttTags[] = {{TOKEN_DEST,TRUE,FALSE}, {TOKEN_MASK,FALSE,FALSE}, {TOKEN_NAMEINDEX,FALSE,FALSE}, {TOKEN_NHOP,FALSE,FALSE}, {TOKEN_PREFERENCE,FALSE,FALSE}, {TOKEN_METRIC,FALSE,FALSE}, {TOKEN_VIEW,FALSE,FALSE}}; enum idx {DEST, MASK, NAMEINDEX, NHOP, PREFERENCE, METRIC, VIEW}; DWORD pdwTagType[sizeof(pttTags)/sizeof(TAG_TYPE)]; DWORD dwMaxArgs; DWORD dwIfClass; DWORD dwFlags; PINTERFACE_ROUTE_INFO pTable = NULL; // // We can add non persistent routes only if router is running // CHECK_ROUTER_RUNNING(); ZeroMemory(&route, sizeof(route)); route.dwRtInfoProto = PROTO_IP_NETMGMT; // default proto route.dwRtInfoPreference = 0; // default preference = protocol default route.dwRtInfoMetric1 = 1; // default metric route.dwRtInfoMetric2 = MIB_IPROUTE_METRIC_UNUSED; route.dwRtInfoMetric3 = MIB_IPROUTE_METRIC_UNUSED; route.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST; // Do generic processing dwErr = PreHandleCommand( ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, sizeof(pttTags)/sizeof(TAG_TYPE), 1, sizeof(pttTags)/sizeof(TAG_TYPE), pdwTagType ); if (dwErr) { return dwErr; } dwNumArg = dwArgCount - dwCurrentIndex; // // At this point, the arg array contains only values (either because // the tags werent present, or because that info has now been split out) // So we go through each of the each of the arguments, look up its tag // type in the tag array, switch on the type of tag it is and then // process accordingly. // for (i = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case DEST: // DEST { dwErr = GetIpPrefix(ppwcArguments[i + dwCurrentIndex], &route.dwRtInfoDest, &route.dwRtInfoMask); break; } case MASK: // MASK { dwErr = GetIpMask(ppwcArguments[i + dwCurrentIndex], &route.dwRtInfoMask); break; } case NAMEINDEX : // INDEX or NAME { PWCHAR endptr = NULL; DWORD BufLen; // // Initially consider the user input to be the friendly name of the // interface // If we fail to get the interface name from this friendly name // then we shall try considering the user as an index // route.dwRtInfoIfIndex = 0; BufLen = sizeof(wszIfName); dwErr = GetInterfaceName(ppwcArguments[i + dwCurrentIndex], wszIfName, BufLen, &dwNumParsed); if (dwErr != NO_ERROR) { // If it starts with '0x', this is a hex index // else if it starts with 0, this is an 0ctal index // else it is decimal or an interface name // if ((ppwcArguments[i + dwCurrentIndex][0] == L'0') && (ppwcArguments[i + dwCurrentIndex][1] == L'x')) { route.dwRtInfoIfIndex = wcstoul(ppwcArguments[i + dwCurrentIndex], &endptr, 16); } else if ( ppwcArguments[i + dwCurrentIndex][0] == L'0') { route.dwRtInfoIfIndex = wcstoul(ppwcArguments[i + dwCurrentIndex], &endptr, 8); } else { route.dwRtInfoIfIndex = wcstoul(ppwcArguments[i + dwCurrentIndex], &endptr, 10); } // // If all the characters in the field were not used while doing the // conversion, then we know that the input was not purely /// numeric, and is thus invalid as an index value // if (*endptr != L'\0') { DisplayMessage(g_hModule, EMSG_CANT_MATCH_NAME); return ERROR_INVALID_PARAMETER; } } break; } case NHOP: // NHOP { dwErr = GetIpAddress(ppwcArguments[i + dwCurrentIndex], &route.dwRtInfoNextHop); break; } case PREFERENCE: { route.dwRtInfoPreference = wcstoul(ppwcArguments[i + dwCurrentIndex], NULL, 10); break; } case METRIC: // METRIC { route.dwRtInfoMetric1 = wcstoul(ppwcArguments[i + dwCurrentIndex], NULL, 10); break; } case VIEW: { TOKEN_VALUE rgMaskEnums[] = { { TOKEN_VALUE_UNICAST, RTM_VIEW_MASK_UCAST }, { TOKEN_VALUE_MULTICAST, RTM_VIEW_MASK_MCAST }, { TOKEN_VALUE_BOTH, RTM_VIEW_MASK_UCAST |RTM_VIEW_MASK_MCAST } }; dwErr = MatchEnumTag( g_hModule, ppwcArguments[i + dwCurrentIndex], sizeof(rgMaskEnums)/sizeof(TOKEN_VALUE), rgMaskEnums, &route.dwRtInfoViewSet); if (dwErr isnot NO_ERROR) { DispTokenErrMsg( g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex] ); i = dwArgCount; return ERROR_INVALID_PARAMETER; } break; } } } if (dwErr) { return dwErr; } if (route.dwRtInfoDest & ~route.dwRtInfoMask) { // Mask contains bits not in address DisplayMessage(g_hModule, EMSG_PREFIX_ERROR); return ERROR_INVALID_PARAMETER; } if (!pttTags[NAMEINDEX].bPresent) { // // Neither NAME nor INDEX - adding with a nexthop // PMIB_IPADDRTABLE AddrTable; PMIB_IPADDRROW AddrEntry; MIB_OPAQUE_QUERY Query; PMIB_OPAQUE_INFO Info; DWORD dwQuerySize; DWORD dwEntrySize; INT iFirstMatch; UINT Count; if (!pttTags[NHOP].bPresent) { DisplayMessage(g_hModule, EMSG_CANT_FIND_NAME_OR_NHOP); return ERROR_INVALID_SYNTAX; } // // Search for the interface that matches nexthop // dwQuerySize = sizeof(MIB_OPAQUE_QUERY) - sizeof(DWORD); Query.dwVarId = IP_ADDRTABLE; dwErr = MibGet(PID_IP, IPRTRMGR_PID, (PVOID) &Query, dwQuerySize, (PVOID *) &Info, &dwEntrySize); if (dwErr != NO_ERROR) { DisplayMessage(g_hModule, MSG_IP_DIM_ERROR, dwErr); return ERROR_SUPPRESS_OUTPUT; } if (Info is NULL) { DisplayMessage(g_hModule, EMSG_CANT_FIND_INDEX); return ERROR_INVALID_PARAMETER; } AddrTable = (PMIB_IPADDRTABLE)Info->rgbyData; iFirstMatch = -1; for (Count = 0; Count < AddrTable->dwNumEntries; Count++) { AddrEntry = &AddrTable->table[Count]; if ((route.dwRtInfoNextHop & AddrEntry->dwMask) == (AddrEntry->dwAddr & AddrEntry->dwMask)) { if (iFirstMatch != -1) { // // We already matched an interface // [Ambiguous next hop description] // MprAdminMIBBufferFree((PVOID)Info); DisplayMessage(g_hModule, EMSG_AMBIGUOUS_INDEX_FROM_NHOP); return ERROR_INVALID_PARAMETER; } iFirstMatch = Count; } } if (iFirstMatch == -1) { // // Could not find the direct nexthop // MprAdminMIBBufferFree((PVOID)Info); DisplayMessage(g_hModule, EMSG_CANT_FIND_INDEX); return ERROR_INVALID_PARAMETER; } // // Found the interface used to reach nexthop // route.dwRtInfoIfIndex = AddrTable->table[iFirstMatch].dwIndex; MprAdminMIBBufferFree((PVOID)Info); } if (route.dwRtInfoIfIndex) { // // Check if this index has a public exported name // dwErr = GetGuidFromIfIndex(g_hMIBServer, route.dwRtInfoIfIndex, wszIfName, MAX_INTERFACE_NAME_LEN); if ( dwErr != NO_ERROR ) { DisplayMessage(g_hModule, EMSG_CANT_FIND_INDEX); return ERROR_INVALID_PARAMETER; } } if (wszIfName[0] != L'\0') { // // NAME specified, or derived from INDEX above // dwErr = GetInterfaceClass(wszIfName, &dwIfClass); // // If we get an error, we will skip remaining // checks which will be performed by iprtrmgr // if (dwErr == NO_ERROR) { if (dwIfClass is IFCLASS_LOOPBACK) { return ERROR_INVALID_SYNTAX; } if (!pttTags[NHOP].bPresent) { // Make sure interface is p2p if (dwIfClass isnot IFCLASS_P2P) { DisplayMessage(g_hModule, EMSG_NEED_NHOP); return ERROR_INVALID_PARAMETER; } } } } else { DisplayMessage(g_hModule, EMSG_CANT_MATCH_NAME); return ERROR_INVALID_PARAMETER; } // // If it is a set, we should not overwrite things not specified // dwFlags = ALL_FIELDS_SPECIFIED; if (dwCommand == SET_COMMAND) { if (!pttTags[PREFERENCE].bPresent) dwFlags |= PREF_NOT_SPECIFIED; if (!pttTags[METRIC].bPresent) dwFlags |= METRIC_NOT_SPECIFIED; if (!pttTags[VIEW].bPresent) dwFlags |= VIEW_NOT_SPECIFIED; } return AddSetDelRtmRouteInfo(&route, wszIfName, dwCommand, dwFlags); } DWORD HandleIpAddRtmRoute( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) { return IpAddSetDelRtmRoute(ppwcArguments, dwCurrentIndex, dwArgCount, ADD_COMMAND); } DWORD HandleIpDelRtmRoute( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) { return IpAddSetDelRtmRoute(ppwcArguments, dwCurrentIndex, dwArgCount, DELETE_COMMAND); } DWORD HandleIpSetRtmRoute( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) { return IpAddSetDelRtmRoute(ppwcArguments, dwCurrentIndex, dwArgCount, SET_COMMAND); } DWORD IpAddSetDelPersistentRoute( PWCHAR *ppwcArguments, DWORD dwCurrentIndex, DWORD dwArgCount, DWORD dwCommand ) /*++ Routine Description: Gets options for add/del routes over interfaces. These operations are performed directly to the registry and so these routes are persistent. If the router is running, they go into the RTM too. Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg dwCommand - To add, set, or delete Return Value: NO_ERROR --*/ { INTERFACE_ROUTE_INFO route; DWORD dwNumParsed, dwErr, dwRes; DWORD dwNumOpt, dwStatus = (DWORD) -1; DWORD dwNumArg, i; WCHAR wszIfName[MAX_INTERFACE_NAME_LEN + 1] = L"\0"; WCHAR *pwszIfNameOnCmdLine = NULL; TAG_TYPE pttTags[] = {{TOKEN_DEST,TRUE,FALSE}, {TOKEN_MASK,FALSE,FALSE}, {TOKEN_NAME,FALSE,FALSE}, {TOKEN_NHOP,FALSE,FALSE}, {TOKEN_PROTOCOL,FALSE,FALSE}, {TOKEN_PREFERENCE,FALSE,FALSE}, {TOKEN_METRIC,FALSE,FALSE}, {TOKEN_VIEW,FALSE,FALSE}}; enum idx {DEST, MASK, NAME, NHOP, PROTO, PREFERENCE, METRIC, VIEW}; DWORD pdwTagType[sizeof(pttTags)/sizeof(TAG_TYPE)]; DWORD dwMaxArgs; DWORD dwIfClass; DWORD dwFlags; PINTERFACE_ROUTE_INFO pTable = NULL; ZeroMemory(&route, sizeof(route)); route.dwRtInfoProto = PROTO_IP_NT_STATIC_NON_DOD; // default proto route.dwRtInfoPreference = 0; // default preference = protocol default route.dwRtInfoMetric1 = 1; // default metric route.dwRtInfoMetric2 = MIB_IPROUTE_METRIC_UNUSED; route.dwRtInfoMetric3 = MIB_IPROUTE_METRIC_UNUSED; route.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST; // Do generic processing dwErr = PreHandleCommand( ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, sizeof(pttTags)/sizeof(TAG_TYPE), 1, sizeof(pttTags)/sizeof(TAG_TYPE), pdwTagType ); if (dwErr) { return dwErr; } dwNumArg = dwArgCount - dwCurrentIndex; // // At this point, the arg array contains only values (either because // the tags werent present, or because that info has now been split out) // So we go through each of the each of the arguments, look up its tag // type in the tag array, switch on the type of tag it is and then // process accordingly. // for (i = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case DEST: // DEST { dwErr = GetIpPrefix(ppwcArguments[i + dwCurrentIndex], &route.dwRtInfoDest, &route.dwRtInfoMask); break; } case MASK: // MASK { dwErr = GetIpMask(ppwcArguments[i + dwCurrentIndex], &route.dwRtInfoMask); break; } case NAME : // NAME { DWORD BufLen = sizeof(wszIfName); pwszIfNameOnCmdLine = ppwcArguments[i + dwCurrentIndex]; GetInterfaceName(ppwcArguments[i + dwCurrentIndex], wszIfName, BufLen, &dwNumParsed); break; } case NHOP: // NHOP { dwErr = GetIpAddress(ppwcArguments[i + dwCurrentIndex], &route.dwRtInfoNextHop); break; } case PROTO : // PROTO { TOKEN_VALUE rgEnums[] = {/*{TOKEN_VALUE_AUTOSTATIC, PROTO_IP_NT_AUTOSTATIC},*/ {TOKEN_VALUE_STATIC, PROTO_IP_NT_STATIC}, {TOKEN_VALUE_NONDOD, PROTO_IP_NT_STATIC_NON_DOD}}; dwErr = MatchEnumTag(g_hModule, ppwcArguments[i + dwCurrentIndex], sizeof(rgEnums)/sizeof(TOKEN_VALUE), rgEnums, &dwRes); if (dwErr != NO_ERROR) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); DisplayMessage( g_hModule, MSG_IP_BAD_OPTION_ENUMERATION, pttTags[pdwTagType[i]].pwszTag ); for (i=0; i= dwArgCount) { // // No arguments specified // return ERROR_SHOW_USAGE; } dwNumArg = dwArgCount - dwCurrentIndex; pdwTagType = HeapAlloc(GetProcessHeap(), 0, dwNumArg * sizeof(DWORD)); if (pdwTagType is NULL) { DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_NOT_ENOUGH_MEMORY; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwNumTags, pdwTagType); if (dwErr isnot NO_ERROR) { HeapFree(GetProcessHeap(),0,pdwTagType); if (dwErr is ERROR_INVALID_OPTION_TAG) { dwErr = ERROR_INVALID_SYNTAX; // show usage } return dwErr; } dwNumPref = dwNumArg / 2 + dwNumArg % 2; ppm = HeapAlloc(GetProcessHeap(), 0, dwNumPref * sizeof(PROTOCOL_METRIC)); if (ppm is NULL) { HeapFree(GetProcessHeap(),0,pdwTagType); DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_SUPPRESS_OUTPUT; } for ( i = 0, dwPrefIndex = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case 0: { // // TAG = PROTOCOL // dwRes = MatchRoutingProtoTag(ppwcArguments[i + dwCurrentIndex]); if (dwRes == (DWORD) -1) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); i = dwNumArg; dwErr = ERROR_SUPPRESS_OUTPUT; break; } ppm[dwPrefIndex].dwProtocolId = dwRes; // // Get the metric too // if (pdwTagType[i+1] == 1) { ppm[dwPrefIndex].dwMetric = wcstoul(ppwcArguments[i + 1 +dwCurrentIndex],NULL,10); if (ppm[dwPrefIndex].dwMetric==0 && wcscmp(ppwcArguments[i + 1 +dwCurrentIndex], L"0")!=0) { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } i++; dwPrefIndex++; } else { // // the range is not an addr mask pair. // So ignore the addr (i.e. don't increment dwRangeIndex) // dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } break; } default : { i = dwNumArg; dwErr = ERROR_INVALID_SYNTAX; break; } } } HeapFree(GetProcessHeap(), 0, pdwTagType); switch(dwErr) { case NO_ERROR : break; default: return dwErr; } if (dwPrefIndex) { // // Add route pref // dwRes = AddDeleteRoutePrefLevel(ppm, dwPrefIndex, TRUE); } HeapFree(GetProcessHeap(), 0, ppm); return dwErr; } DWORD HandleIpDelRoutePref( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Gets options for deleting route preferences Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { PPROTOCOL_METRIC ppm; DWORD dwBitVector = 0, dwNumPref,dwPrefIndex; DWORD dwErr = NO_ERROR,dwRes; TAG_TYPE pttTags[] = {{TOKEN_PROTOCOL,TRUE,FALSE}}; PDWORD pdwTagType; DWORD dwNumTags = 1, dwNumArg, i, dwAddr; if (dwCurrentIndex >= dwArgCount) { // // No arguments specified // return ERROR_SHOW_USAGE; } dwNumArg = dwArgCount - dwCurrentIndex; pdwTagType = HeapAlloc(GetProcessHeap(), 0, dwNumArg * sizeof(DWORD)); if (pdwTagType is NULL) { DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_SUPPRESS_OUTPUT; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwNumTags, pdwTagType); if (dwErr isnot NO_ERROR) { HeapFree(GetProcessHeap(),0,pdwTagType); if (dwErr is ERROR_INVALID_OPTION_TAG) { dwErr = ERROR_INVALID_SYNTAX; // show usage } return dwErr; } dwNumPref = dwNumArg; ppm = HeapAlloc(GetProcessHeap(), 0, dwNumPref * sizeof(PROTOCOL_METRIC)); if (ppm is NULL) { HeapFree(GetProcessHeap(),0,pdwTagType); DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_SUPPRESS_OUTPUT; } for ( i = 0, dwPrefIndex = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case 0: { // // TAG = PROTOCOL // dwRes = MatchRoutingProtoTag(ppwcArguments[i + dwCurrentIndex]); if (dwRes == (DWORD) -1) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); i = dwNumArg; dwErr = ERROR_SUPPRESS_OUTPUT; break; } ppm[dwPrefIndex++].dwProtocolId = dwRes; break; } default : { i = dwNumArg; dwErr = ERROR_INVALID_SYNTAX; break; } } } HeapFree(GetProcessHeap(), 0, pdwTagType); switch(dwErr) { case NO_ERROR : break; default: return dwErr; } if (dwPrefIndex) { // // Add route pref // dwRes = AddDeleteRoutePrefLevel(ppm, dwPrefIndex, FALSE); } HeapFree(GetProcessHeap(), 0, ppm); return dwErr; } DWORD HandleIpSetRoutePref( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Gets options for setting route preferences Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { PROTOCOL_METRIC pm; DWORD dwBitVector = 0, dwNumPref,dwPrefIndex; DWORD dwErr = NO_ERROR,dwRes; TAG_TYPE pttTags[] = {{TOKEN_PROTOCOL, TRUE,FALSE}, {TOKEN_PREF_LEVEL, TRUE,FALSE}}; PDWORD pdwTagType; DWORD dwNumTags = 2, dwNumArg, i, dwAddr; if (dwCurrentIndex >= dwArgCount) { // // No arguments specified // return ERROR_SHOW_USAGE; } dwNumArg = dwArgCount - dwCurrentIndex; pdwTagType = HeapAlloc(GetProcessHeap(), 0, dwNumArg * sizeof(DWORD)); if (pdwTagType is NULL) { DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_NOT_ENOUGH_MEMORY; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwNumTags, pdwTagType); if (dwErr isnot NO_ERROR) { HeapFree(GetProcessHeap(),0,pdwTagType); if (dwErr is ERROR_INVALID_OPTION_TAG) { return ERROR_INVALID_SYNTAX; // show usage } return dwErr; } for ( i = 0, dwPrefIndex = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case 0: // PROTOCOL dwRes = MatchRoutingProtoTag(ppwcArguments[i + dwCurrentIndex]); if (dwRes == (DWORD) -1) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); i = dwNumArg; dwErr = ERROR_SUPPRESS_OUTPUT; break; } pm.dwProtocolId = dwRes; // // Get the metric too // if (pdwTagType[i+1] == 1) { pm.dwMetric = wcstoul(ppwcArguments[i + 1 +dwCurrentIndex],NULL,10); if (pm.dwMetric==0 && wcscmp(ppwcArguments[i + 1 +dwCurrentIndex], L"0")!=0) { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } i++; dwPrefIndex++; } else { dwErr = ERROR_INVALID_SYNTAX; i = dwNumArg; break; } break; default : i = dwNumArg; dwErr = ERROR_INVALID_SYNTAX; break; } } HeapFree(GetProcessHeap(), 0, pdwTagType); switch(dwErr) { case NO_ERROR : break; default: return dwErr; } dwErr = SetRoutePrefLevel(pm); return dwErr; } DWORD HandleIpSetLogLevel( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Gets options for setting global parameter namely logging level Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { DWORD dwErr = NO_ERROR; TAG_TYPE pttTags[] = {{TOKEN_LOG_LEVEL,TRUE,FALSE}}; PDWORD pdwTagType; DWORD dwNumTags = 1, dwNumArg, i, dwAddr; DWORD dwLoggingLevel = (DWORD) -1; BOOL bOkay = TRUE; if (dwCurrentIndex >= dwArgCount) { // // No arguments specified // return ERROR_SHOW_USAGE; } dwNumArg = dwArgCount - dwCurrentIndex; pdwTagType = HeapAlloc(GetProcessHeap(), 0, dwNumArg * sizeof(DWORD)); if (pdwTagType is NULL) { DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_SUPPRESS_OUTPUT; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwNumTags, pdwTagType); if (dwErr isnot NO_ERROR) { HeapFree(GetProcessHeap(),0,pdwTagType); if (dwErr is ERROR_INVALID_OPTION_TAG) { return ERROR_INVALID_SYNTAX; } return dwErr; } for ( i = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case 0: // LOGLEVEL { TOKEN_VALUE rgEnums[] = {{TOKEN_VALUE_NONE, IPRTR_LOGGING_NONE}, {TOKEN_VALUE_ERROR, IPRTR_LOGGING_ERROR}, {TOKEN_VALUE_WARN, IPRTR_LOGGING_WARN}, {TOKEN_VALUE_INFO, IPRTR_LOGGING_INFO}}; dwErr = MatchEnumTag(g_hModule, ppwcArguments[i + dwCurrentIndex], sizeof(rgEnums)/sizeof(TOKEN_VALUE), rgEnums, &dwLoggingLevel); if (dwErr != NO_ERROR) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); DisplayMessage( g_hModule, MSG_IP_BAD_OPTION_ENUMERATION, pttTags[pdwTagType[i]].pwszTag ); for (i=0; i<4; i++) { DisplayMessageT( L" %1!s!\n", rgEnums[i].pwszToken ); } i = dwNumArg; dwErr = ERROR_SUPPRESS_OUTPUT; bOkay = FALSE; break; } break; } default : { i = dwNumArg; dwErr = ERROR_INVALID_SYNTAX; break; } } } HeapFree(GetProcessHeap(), 0, pdwTagType); switch(dwErr) { case NO_ERROR : break; default: return dwErr; } if (!bOkay) { return NO_ERROR; } dwErr = SetGlobalConfigInfo(dwLoggingLevel); return dwErr; } DWORD HandleIpSetIfFilter( IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwCurrentIndex, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT BOOL *pbDone ) /*++ Routine Description: Gets options for setting interface filter parameters Arguments: ppwcArguments - Argument array dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg Return Value: NO_ERROR --*/ { DWORD dwNumParsed = 0; DWORD dwErr = NO_ERROR,dwRes; TAG_TYPE pttTags[] = {{TOKEN_NAME,TRUE,FALSE}, {TOKEN_FILTER_TYPE,FALSE,FALSE}, {TOKEN_ACTION,FALSE,FALSE}, {TOKEN_FRAGCHECK,FALSE,FALSE}}; PDWORD pdwTagType; DWORD dwNumOpt; DWORD dwNumTags = 4, dwNumArg, i, j; WCHAR wszIfName[MAX_INTERFACE_NAME_LEN + 1] = L"\0"; DWORD dwFilterType, dwAction; BOOL bFragCheck, bOkay = TRUE; if (dwCurrentIndex >= dwArgCount) { // // No arguments specified // return ERROR_SHOW_USAGE; } dwNumArg = dwArgCount - dwCurrentIndex; pdwTagType = HeapAlloc(GetProcessHeap(), 0, dwNumArg * sizeof(DWORD)); if (pdwTagType is NULL) { DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY); return ERROR_SUPPRESS_OUTPUT; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, pttTags, dwNumTags, pdwTagType); if (dwErr isnot NO_ERROR) { HeapFree(GetProcessHeap(),0,pdwTagType); if (dwErr is ERROR_INVALID_OPTION_TAG) { return ERROR_INVALID_SYNTAX; // show usage } return dwErr; } for ( i = 0; i < dwNumArg; i++) { switch (pdwTagType[i]) { case 0 : { DWORD BufLen = sizeof(wszIfName); GetInterfaceName(ppwcArguments[i + dwCurrentIndex], wszIfName, BufLen, &dwNumParsed); // no filters allowed on INTERNAL/LOOPBACK interfaces if (!_wcsicmp(wszIfName, L"internal") or !_wcsicmp(wszIfName, L"loopback")) { DisplayMessage(g_hModule, MSG_IP_BAD_INTERFACE_TYPE, wszIfName); dwErr = ERROR_SUPPRESS_OUTPUT; i = dwNumArg; } break; } case 1: { TOKEN_VALUE rgEnums[] = {{TOKEN_VALUE_INPUT, IP_IN_FILTER_INFO}, {TOKEN_VALUE_OUTPUT, IP_OUT_FILTER_INFO}, {TOKEN_VALUE_DIAL, IP_DEMAND_DIAL_FILTER_INFO}}; // // Tag TYPE // dwErr = MatchEnumTag(g_hModule, ppwcArguments[i + dwCurrentIndex], sizeof(rgEnums)/sizeof(TOKEN_VALUE), rgEnums, &dwFilterType); if (dwErr != NO_ERROR) { DispTokenErrMsg(g_hModule, MSG_IP_BAD_OPTION_VALUE, pttTags[pdwTagType[i]].pwszTag, ppwcArguments[i + dwCurrentIndex]); DisplayMessage( g_hModule, MSG_IP_BAD_OPTION_ENUMERATION, pttTags[pdwTagType[i]].pwszTag ); for (i=0; i dwArgCount) or (dwNumArgs isnot 4)) { // // No arguments specified // return ERROR_SHOW_USAGE; } dwErr = MatchTagsInCmdLine(g_hModule, ppwcArguments, dwCurrentIndex, dwArgCount, rgTags, sizeof(rgTags)/sizeof(TAG_TYPE), rgdwTagType); if (dwErr isnot NO_ERROR) { if (dwErr is ERROR_INVALID_OPTION_TAG) { return ERROR_INVALID_SYNTAX; } return dwErr; } for(i = 0; i < dwNumArgs; i ++) { switch (rgdwTagType[i]) { case 0 : // NAME { DWORD BufLen = sizeof(rgwcIfName); dwErr = GetInterfaceName(ppwcArguments[i + dwCurrentIndex], rgwcIfName, BufLen, &dwNumParsed); if(bAdd) { if(dwErr is NO_ERROR) { return ERROR_OBJECT_ALREADY_EXISTS; } pwszIfName = ppwcArguments[i + dwCurrentIndex]; } else { if(dwErr isnot NO_ERROR) { return dwErr; } pwszIfName = rgwcIfName; } break; } case 1: { // // Tag for localaddr // dwErr = GetIpAddress(ppwcArguments[i + dwCurrentIndex], &ConfigInfo.dwLocalAddress); break; } case 2: { // // Tag for remoteaddr // dwErr = GetIpAddress(ppwcArguments[i + dwCurrentIndex], &ConfigInfo.dwRemoteAddress); break; } case 3: { // // Tag for ttl // ConfigInfo.byTtl = LOBYTE(LOWORD(wcstoul(ppwcArguments[i + dwCurrentIndex], NULL, 10))); break; } default: { i = dwNumArgs; dwErr = ERROR_INVALID_SYNTAX; break; } } } switch(dwErr) { case NO_ERROR: { break; } default: { return dwErr; } } for(i = 0; i < dwNumArgs; i++) { if(!rgTags[i].bPresent) { DisplayMessage(g_hModule, MSG_CANT_FIND_EOPT); return ERROR_INVALID_SYNTAX; } } dwErr = AddSetIpIpTunnelInfo(pwszIfName, &ConfigInfo); return dwErr; } #endif //KSL_IPINIP DWORD IpDump( IN LPCWSTR pwszRouter, IN LPWSTR *ppwcArguments, IN DWORD dwArgCount, IN LPCVOID pvData ) { DumpIpInformation((HANDLE)-1); return NO_ERROR; } #if 0 DWORD HandleIpInstall( PWCHAR pwszMachine, PWCHAR *ppwcArguments, DWORD dwCurrentIndex, DWORD dwArgCount, DWORD dwFlags, PVOID pvData, BOOL *pbDone ) { // XXX DLLPath, ProtocolId // XXX set default info here // global info block (what is this?) // protocol priority block (no need?) // multicast boundaries block (no need) return NO_ERROR; } DWORD HandleIpUninstall( PWCHAR pwszMachine, PWCHAR *ppwcArguments, DWORD dwCurrentIndex, DWORD dwArgCount, DWORD dwFlags, PVOID pvData, BOOL *pbDone ) { PMPR_INTERFACE_0 pmi0; DWORD dwCount, dwTotal, i, dwErr; // Remove global info // XXX // Remove interface info dwErr = IpmontrInterfaceEnum((PBYTE *) &pmi0, &dwCount, &dwTotal); if (dwErr is NO_ERROR) { for (i=0; iTocEntriesCount; pLocalInfoHdr = MALLOC(dwSize); if (pLocalInfoHdr is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } memcpy(pLocalInfoHdr, pInfoHdr, dwSize); // Set Global and RoutePref info { dwBlkSize = sizeof(GLOBAL_INFO); dwCount = 1; gi.bFilteringOn = FALSE; gi.dwLoggingLevel = IPRTR_LOGGING_ERROR; dwErr = IpmontrSetInfoBlockInGlobalInfo(IP_GLOBAL_INFO, (PBYTE) &gi, dwBlkSize, dwCount); } { // Based on the router version, calculate the number // of protocols etc. // TODO: currently assuming >=NT5. Should find out the router // version somehow dwNumProtocols = sizeof(defaultProtocolMetrics)/sizeof(PROTOCOL_METRIC); pProtocolMetrics = defaultProtocolMetrics; dwBlkSize = SIZEOF_PRIORITY_INFO(dwNumProtocols); dwCount = 1; // Allocate buffer to hold the Priority Information pPriInfo = MALLOC(dwBlkSize); if (pPriInfo is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pPriInfo->dwNumProtocols = dwNumProtocols; memcpy( pPriInfo->ppmProtocolMetric, pProtocolMetrics, dwNumProtocols * sizeof(PROTOCOL_METRIC)); dwErr = IpmontrSetInfoBlockInGlobalInfo(IP_PROT_PRIORITY_INFO, (PBYTE) pPriInfo, dwBlkSize, dwCount); FREE(pPriInfo); } for (i=0; iTocEntriesCount; i++) { switch (pLocalInfoHdr->TocEntry[i].InfoType) { case IP_GLOBAL_INFO: case IP_PROT_PRIORITY_INFO: // already done break; default: IpmontrDeleteInfoBlockFromGlobalInfo( pLocalInfoHdr->TocEntry[i].InfoType ); break; } } FREE(pLocalInfoHdr); } // Delete all interface info dwErr = IpmontrInterfaceEnum((PBYTE *) &pmi0, &dwCount, &dwTotal); if (dwErr is NO_ERROR) { for (i=0; i