Changing Route Table, Iphlpapi.dll and P/Invoke: How?

C

cyberco

Thanks to help from this group I got a long way towards changing the
route table on my WM5 PPC (.Net CF) device (TyTN). It seems that
Iphlpapi.dll is what I should use. Unfortunately I'm inexperienced in
using p/invoke from within a C# application. Say I want to invoke
GetIpForwardTable from Iphlpapi.dll as described here:
http://msdn.microsoft.com/library/d...cecomm5/html/wce50lrfcreateipforwardentry.asp

=========== Iphlpapi.dll ===============
DWORD GetIpForwardTable(
PMIB_IPFORWARDTABLE pIpForwardTable,
PULONG pdwSize,
BOOL bOrder
);
==================================

This uses MIB_IPFORWARDTABLE, which is described here:
http://msdn.microsoft.com/library/d...s/wcecomm5/html/wce50lrfmibipforwardtable.asp

=========== Iphlpapi.dll ===============
typedef struct _MIB_IPFORWARDTABLE {
DWORD dwNumEntries;
MIB_IPFORWARDROW table[ANY_SIZE];
} MIB_IPFORWARDTABLE, *PMIB_IPFORWARDTABLE;
===================================

In C# I declare

============ C# =====================
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IPFORWARDTABLE {
public int dwNumEntries;
public MIB_IPFORWARDROW[] table;
}
====================================

It usess MIB_IPFORWARDROW as well, which is described here:
http://msdn.microsoft.com/library/d...-us/wcecomm5/html/wce50lrfmibipforwardrow.asp

============ C# =====================
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IPFORWARDROW {
public UInt32 dwForwardDest;
public UInt32 dwForwardMask;
public UInt32 dwForwardPolicy;
public UInt32 dwForwardNextHop;
public UInt32 dwForwardIfIndex;
public UInt32 dwForwardType;
public UInt32 dwForwardProto;
public UInt32 dwForwardAge;
public UInt32 dwForwardNextHopAS;
public UInt32 dwForwardMetric1;
public UInt32 dwForwardMetric2;
public UInt32 dwForwardMetric3;
public UInt32 dwForwardMetric4;
public UInt32 dwForwardMetric5;
}
====================================

Now, what I wonder is how I declare 'GetIpForwardTable'? My guess is as
follows, but I have no idea what for types to use for the parameters
etc.

============ C# =====================
[DllImport("Iphlpapi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern int GetIpForwardTable(ref MIB_IPFORWARDTABLE
pIpForwardTable, UInt32 pdwSize, bool bOrder);
====================================

So my questions are:
1. What are my the C# types to use?
2. How do I invoke the method
3. What return types can I expect?
4. Where are the returntypes specified?

Ultimately I want to be able to add and remove IPFORWARDROWs to the
route table. At this moment I keep getting a return value of 87, but I
don't know what that means or what I'm doing wrong.

Thanks in advance for any help.
 
P

Paul G. Tobey [eMVP]

You can look up most errors in winerror.h from the device SDK. As I recall,
87 is invalid parameter.

You can't do it that way. You'll have to make the MIB_IPFORWARDTABLE as a
simple array of bytes and use methods of the class to access its data.
Refer to the code in OpenNETCF's SDF. We do this all over the place for
complex types with arrays of data in them.

Paul T.

cyberco said:
Thanks to help from this group I got a long way towards changing the
route table on my WM5 PPC (.Net CF) device (TyTN). It seems that
Iphlpapi.dll is what I should use. Unfortunately I'm inexperienced in
using p/invoke from within a C# application. Say I want to invoke
GetIpForwardTable from Iphlpapi.dll as described here:
http://msdn.microsoft.com/library/d...cecomm5/html/wce50lrfcreateipforwardentry.asp

=========== Iphlpapi.dll ===============
DWORD GetIpForwardTable(
PMIB_IPFORWARDTABLE pIpForwardTable,
PULONG pdwSize,
BOOL bOrder
);
==================================

This uses MIB_IPFORWARDTABLE, which is described here:
http://msdn.microsoft.com/library/d...s/wcecomm5/html/wce50lrfmibipforwardtable.asp

=========== Iphlpapi.dll ===============
typedef struct _MIB_IPFORWARDTABLE {
DWORD dwNumEntries;
MIB_IPFORWARDROW table[ANY_SIZE];
} MIB_IPFORWARDTABLE, *PMIB_IPFORWARDTABLE;
===================================

In C# I declare

============ C# =====================
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IPFORWARDTABLE {
public int dwNumEntries;
public MIB_IPFORWARDROW[] table;
}
====================================

It usess MIB_IPFORWARDROW as well, which is described here:
http://msdn.microsoft.com/library/d...-us/wcecomm5/html/wce50lrfmibipforwardrow.asp

============ C# =====================
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IPFORWARDROW {
public UInt32 dwForwardDest;
public UInt32 dwForwardMask;
public UInt32 dwForwardPolicy;
public UInt32 dwForwardNextHop;
public UInt32 dwForwardIfIndex;
public UInt32 dwForwardType;
public UInt32 dwForwardProto;
public UInt32 dwForwardAge;
public UInt32 dwForwardNextHopAS;
public UInt32 dwForwardMetric1;
public UInt32 dwForwardMetric2;
public UInt32 dwForwardMetric3;
public UInt32 dwForwardMetric4;
public UInt32 dwForwardMetric5;
}
====================================

Now, what I wonder is how I declare 'GetIpForwardTable'? My guess is as
follows, but I have no idea what for types to use for the parameters
etc.

============ C# =====================
[DllImport("Iphlpapi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern int GetIpForwardTable(ref MIB_IPFORWARDTABLE
pIpForwardTable, UInt32 pdwSize, bool bOrder);
====================================

So my questions are:
1. What are my the C# types to use?
2. How do I invoke the method
3. What return types can I expect?
4. Where are the returntypes specified?

Ultimately I want to be able to add and remove IPFORWARDROWs to the
route table. At this moment I keep getting a return value of 87, but I
don't know what that means or what I'm doing wrong.

Thanks in advance for any help.
 
P

Paul G. Tobey [eMVP]

There should be a source package, a ZIP file or something, to get all of the
source. The AccessPointCollection.cs file is copied below. It's not a
particularly great example of coding, but it shows one way that you might
use to send an array of bytes to a native function and then interpret the
result in such a way that managed code can use it cleanly.

Paul T.

-----

using System;
using System.Collections;
using OpenNETCF.Win32;
using OpenNETCF.IO;
using OpenNETCF.Runtime.InteropServices;

namespace OpenNETCF.Net
{
#region -------------- Internal-only Classes --------------

/// <summary>
/// This class represents the data returned by the
/// WZCQueryInterface() call to WZC. There are several
/// values in the INTF_ENTRY struct returned by that
/// query, including a couple of SSID lists (those SSID
/// values currently 'audible' to the adapter and the
/// preferred list). This type is how those lists are
/// returned.
/// </summary>
internal class WZC_WLAN_CONFIG_LIST
{
RAW_DATA data;

// The memory layout of this structure is:
// ULONG NumberOfItems; // number of elements in the array
below
// ULONG Index; // [start] index in the array below
// WZC_WLAN_CONFIG Config[1]; // array of WZC_WLAN_CONFIGs

static int NumberOfItemsOffset = 0;
static int BaseIndexOffset = 4;
static int ConfigOffset = 8;

public WZC_WLAN_CONFIG_LIST( RAW_DATA rd )
{
data = rd;
}

public WZC_WLAN_CONFIG_LIST( uint itemCount )
{
// We are creating a new list and the caller
// wants it to contain itemCount items.
int elemSize = WZC_WLAN_CONFIG.SizeOf;
byte[] d = new byte[ ConfigOffset + elemSize * itemCount ];
data = new RAW_DATA( d );

// Set the list up.
this.NumberOfItems = itemCount;
this.BaseIndex = 0;

// Set the size of each element in the array.
for ( int i = 0; i < itemCount; i++ )
{
// Set the 32-bit value at the start of each
// WZC_WLAN_CONFIG structure to the size of
// that structure.
byte[] buint = BitConverter.GetBytes(elemSize);
MarshalEx.Copy( buint, 0,
(IntPtr)( (uint)( data.lpDataDirect ) + ConfigOffset + (int)elemSize *
i ),
buint.Length );
}
}

public uint NumberOfItems
{
get
{
if ( data.lpData == null )
return 0;
else
return BitConverter.ToUInt32( data.lpData, NumberOfItemsOffset );
}
set
{
byte[] buint = BitConverter.GetBytes(value);
MarshalEx.Copy( buint, 0,
(IntPtr)( (uint)( data.lpDataDirect ) + NumberOfItemsOffset ),
buint.Length );
}
}

public uint BaseIndex
{
get { return BitConverter.ToUInt32( data.lpData, BaseIndexOffset ); }
set
{
byte[] buint = BitConverter.GetBytes(value);
MarshalEx.Copy( buint, 0,
(IntPtr)( (uint)( data.lpDataDirect ) + BaseIndexOffset ),
buint.Length );
}
}

public WZC_WLAN_CONFIG Item( int index )
{
// ???? check range and throw exception

// Figure out where in the array the indicated
// index is located.
// int actualInd = index + (int)BaseIndex;

// Figure out how big each element in the array
// is. The first 32-bit value in the first element
// of the array is the size of each element.
int elemSize = BitConverter.ToInt32( data.lpData, ConfigOffset );

// Use the actual index to get the indicated element
// in the Config list. Note that we use lpDataDirect,
// so that we're copying from the internal array of our
// data, not cloning it first, then copying from the clone.
WZC_WLAN_CONFIG wlc = new WZC_WLAN_CONFIG();
MarshalEx.Copy( (IntPtr)( (uint)( data.lpDataDirect ) + ConfigOffset +
index * (int)elemSize ),
wlc.Data, 0, elemSize );

return wlc;
}

public void SetItem( int index, WZC_WLAN_CONFIG wlc )
{
// ???? check range and throw exception

// Figure out how big each element in the array
// is.
int elemSize = BitConverter.ToInt32( data.lpData, ConfigOffset );

// Use the actual index to get the indicated element
// in the Config list. Note that we use lpDataDirect,
// so that we're copying to the internal array of our
// data, not cloning it first, then copying to the clone
// (which, of course, has no effect).
MarshalEx.Copy( wlc.Data, 0,
(IntPtr)( (uint)( data.lpDataDirect ) + ConfigOffset + index *
(int)elemSize ),
elemSize );
}

public RAW_DATA rawData
{
get
{
// Return the raw data object that represents
// the list content. This might be used when
// changing a preferred list of SSID values for
// an adapter.
return data;
}
}
}

#endregion

/// <summary>
/// Class that represents a collection of the SSID values
/// that a given network adapter can hear over the
/// airwaves. For each SSID, you can get the signal
/// strength and random other information.
/// </summary>
public class AccessPointCollection : CollectionBase
{
internal Adapter adapter = null;

/// <summary>
/// The Adapter instance with which the SSID instance
/// is associated.
/// </summary>
public Adapter AssociatedAdapter
{
get { return adapter; }
}

internal AccessPointCollection( Adapter a )
{
adapter = a;

this.RefreshList( true );
}

internal AccessPointCollection( Adapter a, bool nearbyOnly )
{
adapter = a;

this.RefreshListPreferred( nearbyOnly );
}

internal unsafe void ClearCache()
{
// Tell the driver to search for any new SSIDs
// and return them on the next OID_802_11_BSSID_LIST
// message.
uint dwBytesReturned = 0;
NDISUIO_QUERY_OID queryOID = new NDISUIO_QUERY_OID( 0 );
IntPtr ndisAccess;
bool retval;

// Attach to NDISUIO.
ndisAccess = FileEx.CreateFile(
NDISUIOPInvokes.NDISUIO_DEVICE_NAME,
FileAccess.All,
FileShare.None,
FileCreateDisposition.OpenExisting,
NDISUIOPInvokes.FILE_ATTRIBUTE_NORMAL |
NDISUIOPInvokes.FILE_FLAG_OVERLAPPED );
if ( (int)ndisAccess == FileEx.InvalidHandle )
{
// The operation failed. Leave us empty.
return;
}

// Send message to driver.
byte[] namestr =
System.Text.Encoding.Unicode.GetBytes(adapter.Name+'\0');
fixed (byte *name = &namestr[ 0 ])
{
// Get Signal strength
queryOID.ptcDeviceName = name;
queryOID.Oid = NDISUIOPInvokes.OID_802_11_BSSID_LIST_SCAN; // 0x0D01011A

retval = NDISUIOPInvokes.DeviceIoControl( ndisAccess,
NDISUIOPInvokes.IOCTL_NDISUIO_SET_OID_VALUE, // 0x120814
queryOID,
queryOID.Size,
queryOID,
queryOID.Size,
ref dwBytesReturned,
IntPtr.Zero);
}

if( retval )
{
// The call went fine. There is no return
// data.
}
else
{
// There was an error.
int err = MarshalEx.GetLastWin32Error();

// ToDo: Additional error processing.
}

queryOID = null;

FileEx.CloseHandle( ndisAccess );
}

internal unsafe void RefreshList( Boolean clearCache )
{
// If we are to clear the driver's cache of SSID
// values, call the appropriate method.
//Console.WriteLine("Entering RefreshList");
if ( clearCache )
{
this.ClearCache();

// This seems to be needed to avoid having
// a list of zero elements returned.
System.Threading.Thread.Sleep( 1000 );
}

this.List.Clear();

// Retrieve a list of NDIS_802_11_BSSID_LIST
// structures from the driver. We'll parse that
// list and populate ourselves based on the data
// that we find there.
uint dwBytesReturned = 0;
NDISUIO_QUERY_OID queryOID = new NDISUIO_QUERY_OID( 6000 /* TESTING JFK
was 2000 */ );
IntPtr ndisAccess;
bool retval;

// Attach to NDISUIO.
ndisAccess = FileEx.CreateFile(
NDISUIOPInvokes.NDISUIO_DEVICE_NAME,
FileAccess.All,
FileShare.None,
FileCreateDisposition.OpenExisting,
NDISUIOPInvokes.FILE_ATTRIBUTE_NORMAL |
NDISUIOPInvokes.FILE_FLAG_OVERLAPPED );
if ( (int)ndisAccess == FileEx.InvalidHandle )
{
Console.WriteLine("Attach to NDISUIO Failed");
// The operation failed. Leave us empty.
return;
}

// Get Signal strength
byte[] namestr =
System.Text.Encoding.Unicode.GetBytes(adapter.Name+'\0');
fixed (byte *name = &namestr[ 0 ])
{
// Get Signal strength
queryOID.ptcDeviceName = name;
queryOID.Oid = NDISUIOPInvokes.OID_802_11_BSSID_LIST; // 0x0D010217

retval = NDISUIOPInvokes.DeviceIoControl( ndisAccess,
NDISUIOPInvokes.IOCTL_NDISUIO_QUERY_OID_VALUE, // 0x00120804
queryOID,
queryOID.Size,
queryOID,
queryOID.Size,
ref dwBytesReturned,
IntPtr.Zero);
}

if( retval )
{
// Now we need to parse the incoming data into
// suitable representations of the SSIDs.

// Figure out how many SSIDs there are.
NDIS_802_11_BSSID_LIST rawlist = new NDIS_802_11_BSSID_LIST(
queryOID.Data );

for ( int i = 0; i < rawlist.NumberOfItems; i++ )
{
// Get the next raw item from the list.
NDIS_WLAN_BSSID bssid = rawlist.Item( i );

// Using the raw item, create a cooked
// SSID item.
AccessPoint ssid = new AccessPoint( bssid );

// Add the new item to this.
this.List.Add( ssid );
}
}
else
{
// We might just need more room.
// For now, we just leave the list empty.
// ToDo: Additional error processing.
Console.WriteLine("ERROR Buffer Too Small");//You'll notice here there
should be some sort of error contol but there isn't.
//We simply don't have enough room.
}

FileEx.CloseHandle( ndisAccess );
}

internal unsafe void RefreshListPreferred( bool nearbyOnly )
{
// If the caller wants only the local preferred APs,
// we check nearby list and, if the AP is not there,
// we don't add it to our own preferred list.
AccessPointCollection apc = null;
if ( nearbyOnly )
{
apc = adapter.NearbyAccessPoints;
}

// First step is to get the INTF_ENTRY for the adapter.
// This includes the list of preferred SSID values.
INTF_ENTRY ie = INTF_ENTRY.GetEntry( this.adapter.Name );

// The field rdStSSIDList is the preferred list. It comes
// in the form of a WZC_802_11_CONFIG_LIST.
RAW_DATA rd = ie.rdStSSIDList;
WZC_WLAN_CONFIG_LIST cl = new WZC_WLAN_CONFIG_LIST( rd );

// Step through the list and add a new AP to the
// collection for each entry.
for ( int i = 0; i < cl.NumberOfItems; i++ )
{
WZC_WLAN_CONFIG c = cl.Item( i );

// Get a NDIS_WLAN_BSSID corresponding to the
// part of the WZC_WLAN_CONFIG entry and use that
// to build an AccessPoint instance for this
// entry.
NDIS_WLAN_BSSID bssid = c.ToBssid();

// If we're only showing those which we can hear,
// see if the current SSID is in the nearby list.
if ( nearbyOnly )
{
// Find the currently active AP with the SSID
// to match the one we're working on.
AccessPoint activeAP = apc.FindBySSID( bssid.SSID );
int ss;

// If the given SSID is not in range, don't add
// an entry to the list.
if ( activeAP != null )
{
// Update signal strength.
ss = activeAP.SignalStrengthInDecibels;

// Copy the signal strength value to the
// NDIS_WLAN_BSSID structure for the
// preferred list entry.
bssid.Rssi = ss;

// Create the AP instance and add it to the
// preferred list.
AccessPoint ap = new AccessPoint( bssid );
this.List.Add( ap );
}
}
else
{
// Create the AP instance and add it to the
// preferred list. The signal strength will
// not necessarily be valid.
AccessPoint ap = new AccessPoint( bssid );
this.List.Add( ap );
}
}
}

/// <summary>
/// Indexer for contained AccessPoints
/// </summary>
public AccessPoint this[int index]
{
get
{
return (AccessPoint)List[ index ];;
}
}

/// <summary>
/// Refresh the list of SSID values, asking the
/// adapter to scan for new ones, also.
/// </summary>
public void Refresh()
{
this.RefreshList( true );
}

/// <summary>
/// Find a given access point in the collection by
/// looking for a matching SSID value.
/// </summary>
/// <param name="ssid">
/// String SSID to search for.
/// </param>
/// <returns>
/// First AccessPoint in the collection with the
/// indicated SSID, or null, if none was found.
/// </returns>
public AccessPoint FindBySSID( String ssid )
{
for ( int i = 0; i < this.Count; i++ )
{
AccessPoint ap = ((AccessPoint)this.List[ i ]);
if ( ap.Name == ssid )
{
return ap;
}
}

return null;
}

}

}
 
C

cyberco

Using: Windows Mobile 5 PPC

Thanks!

In the meanwhile I came up with the following code that enables me to
retrieve the route table. Adding still fails, though (see below).

========================

[StructLayout(LayoutKind.Sequential)]
public struct MIB_IPFORWARDROW {
public UInt32 dwForwardDest; //destination IP address.
public UInt32 dwForwardMask; //Subnet mask of
destination.
public UInt32 dwForwardPolicy; //conditions for multi-path
route. Unused, specify 0.
public UInt32 dwForwardNextHop; //IP address of the next
hop. Own address?
public UInt32 dwForwardIfIndex; //index of interface to use
for reaching the next hop
public UInt32 dwForwardType; //route type
public UInt32 dwForwardProto; //routing protocol. Set to
PROTO_IP_NETMGMT == 3
public UInt32 dwForwardAge; //age of route.
public UInt32 dwForwardNextHopAS; //autonomous system number.
0 if not relevant
public int dwForwardMetric1; //-1 if not used (goes for
all metrics)
public int dwForwardMetric2;
public int dwForwardMetric3;
public int dwForwardMetric4;
public int dwForwardMetric5;
}

[StructLayout(LayoutKind.Sequential)]
public struct MIB_IPFORWARDTABLE {
public int dwNumEntries; //number of route entries
in the table.
public MIB_IPFORWARDROW[] table;
}


[DllImport("Iphlpapi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
public static extern int GetIpForwardTable(byte[]
pIpForwardTable, out int pdwSize, bool bOrder); // Use a byte[] and
instead of a pointer, and 'out' as well.

[DllImport("Iphlpapi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
public static extern int CreateIpForwardEntry(ref
MIB_IPFORWARDROW pRoute);


public void getIpForwardTable() {
int pdwSize = 20000; // Start with 20.000 bytes
byte[] buffer = new byte[pdwSize];
//dummy invoke to determine the buffer size
int ret = IPHlpApiWrapper.GetIpForwardTable(buffer, out
pdwSize, true);
// ERROR codes:
http://www.koders.com/c/fidA3495E2D0228488FC2592A31090BC2EB83A7CA56.aspx
if (ret == 0) {
buffer = new byte[pdwSize];
//have the buffer filled
ret = IPHlpApiWrapper.GetIpForwardTable(buffer, out
pdwSize, true);
if (ret != 0) {
Debug.WriteLine("IPHlpApiHelper: Error on call 2");
return;
}
} else {
Debug.WriteLine("IPHlpApiHelper: Error on call 1");
return;
}
//now we have the buffer filled, create an empty
MIB_IPFORWARDTABLE...
ipForwardTable = new MIB_IPFORWARDTABLE();

// ...and fill the MIB_IPFORWARDTABLE with the bytes from
int nOffset = 0;
// number of rows in the table
ipForwardTable.dwNumEntries =
Convert.ToInt32(buffer[nOffset]);
nOffset += 4;
ipForwardTable.table = new
MIB_IPFORWARDROW[ipForwardTable.dwNumEntries];

for (int i = 0; i < ipForwardTable.dwNumEntries; i++) {
//dwForwardDest

//((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardDest =
Convert.ToUInt32(buffer[nOffset]);

((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardDest =
toIPInt(buffer, nOffset);
nOffset += 4;
//dwForwardMask

((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardMask =
toIPInt(buffer, nOffset);
nOffset += 4;
//dwForwardPolicy

((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardPolicy =
Convert.ToUInt32(buffer[nOffset]);
nOffset += 4;
//dwForwardNextHop

((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardNextHop =
toIPInt(buffer, nOffset);
nOffset += 4;
//dwForwardIfIndex

((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardIfIndex =
Convert.ToUInt32(buffer[nOffset]);
nOffset += 8; //8 since we're skipping the next item
(dwForwardType)
//dwForwardProto

((MIB_IPFORWARDROW)(ipForwardTable.table)).dwForwardProto =
Convert.ToUInt32(buffer[nOffset]);
nOffset += 4;
}
}


private UInt32 toIPInt(byte[] bytes, int startOffset) {
uint ipInt = 0;
for (int i = 3; i >= 0; i--) {
ipInt += (uint) (bytes[startOffset + i] << (8 * i));
}
return Convert.ToUInt32(ipInt);
}


==================================

Creating a new route and adding it to the table still fails though. I
think have all the values set correctly

=================================
//Not necessary to set all:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=454793&SiteID=1
public int createIpForwardEntry(UInt32 destIPAddress, UInt32
destMask,UInt32 nextHopIPAddress, UInt32 ifIndex) {
MIB_IPFORWARDROW mifr = new MIB_IPFORWARDROW();
mifr.dwForwardDest = destIPAddress;
mifr.dwForwardMask = destMask;
mifr.dwForwardPolicy = Convert.ToUInt32(0);
mifr.dwForwardNextHop = nextHopIPAddress;
mifr.dwForwardIfIndex = ifIndex; //?
mifr.dwForwardType = Convert.ToUInt32(4); //next hop !=
final destination (remote route)
mifr.dwForwardProto = Convert.ToUInt32(3);
mifr.dwForwardAge = Convert.ToUInt32(0);
mifr.dwForwardNextHopAS = Convert.ToUInt32(0);
mifr.dwForwardMetric1 = -1;
mifr.dwForwardMetric2 = -1;
mifr.dwForwardMetric3 = -1;
mifr.dwForwardMetric4 = -1;
mifr.dwForwardMetric5 = -1;
return IPHlpApiWrapper.CreateIpForwardEntry(ref mifr);
}

==============================

All IP addresses are added as unsigned ints (double checked whether
they are correct.
I even tried adding a row that I just successfully retrieved (thereby
skipping my own structure). If that gives me an error code 87 (invalid
param). Am I forgetting something with memory or so?

There's one example here that seems much simpler than what I'm doing
right now. I get the feeling it can be done a lot easier.

Thanks.
 
G

Guest

We've recently put in a new server. It's now at vault.opennetcf.com.
SourceGear has the client, and it's free (we pay per license at the server).
 
C

cyberco

Unfortunately I'm still struggling with this, is there anybody here
that has been successful in adding an ipforwardentry to the
ipforwardtable?
A pointer would be greatly appreciated.
Thanks.
 
P

Paul G. Tobey [eMVP]

Since no one seems to have done this, forget about managed code for a few
minutes and verify that you can do this from C. If so, then you know that
the problem is your managed code wrapper, not the OS itself...

Paul T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top