[Xorp-hackers] [PATCH] xorp/contrib/win32/xorprtm SVN Rev 11384

Victor Miasnikov vvm at tut.by
Wed Mar 14 07:10:06 PDT 2012


From: Victor Miasnikov <vvm at tut.by>

xorp/contrib/win32/xorprtm SVN Rev 11384


Signed-off-by: Victor Miasnikov <vvm at tut.by>
---
 xorp/contrib/xorprtm/BUGS                          |   80 +
 xorp/contrib/xorprtm/BUILD_NOTES                   |    2 +
 xorp/contrib/xorprtm/README                        |   12 +
 xorp/contrib/xorprtm/TODO                          |   22 +
 xorp/contrib/xorprtm/xorprtm/bsdroute.h            |  285 +++
 xorp/contrib/xorprtm/xorprtm/defs.h                |   93 +
 xorp/contrib/xorprtm/xorprtm/list.h                |  175 ++
 xorp/contrib/xorprtm/xorprtm/loadprotocol.c        |  365 ++++
 xorp/contrib/xorprtm/xorprtm/mibmgr.c              |  124 ++
 xorp/contrib/xorprtm/xorprtm/mibmgr.h              |   50 +
 xorp/contrib/xorprtm/xorprtm/pchsample.h           |   64 +
 xorp/contrib/xorprtm/xorprtm/print_rtmsg.c         |  737 ++++++++
 xorp/contrib/xorprtm/xorprtm/rmapi.c               |  752 ++++++++
 xorp/contrib/xorprtm/xorprtm/rmapi.h               |   35 +
 xorp/contrib/xorprtm/xorprtm/sync.c                |  101 +
 xorp/contrib/xorprtm/xorprtm/sync.h                |  145 ++
 xorp/contrib/xorprtm/xorprtm/test_monitor.c        |   98 +
 xorp/contrib/xorprtm/xorprtm/test_routeadd.c       |  126 ++
 xorp/contrib/xorprtm/xorprtm/test_routeadddelete.c |  199 ++
 xorp/contrib/xorprtm/xorprtm/test_routeaddwait.c   |  138 ++
 xorp/contrib/xorprtm/xorprtm/utils.c               |   93 +
 xorp/contrib/xorprtm/xorprtm/utils.h               |   41 +
 xorp/contrib/xorprtm/xorprtm/xorprtm.c             | 1905 ++++++++++++++++++++
 xorp/contrib/xorprtm/xorprtm/xorprtm.h             |   32 +
 xorp/contrib/xorprtm/xorprtm/xorprtm_internal.h    |  175 ++
 xorp/contrib/xorprtm/xorprtm4/xorprtm4.def         |    4 +
 xorp/contrib/xorprtm/xorprtm6/xorprtm6.def         |    4 +
 27 files changed, 5857 insertions(+), 0 deletions(-)
 create mode 100644 xorp/contrib/xorprtm/BUGS
 create mode 100644 xorp/contrib/xorprtm/BUILD_NOTES
 create mode 100644 xorp/contrib/xorprtm/README
 create mode 100644 xorp/contrib/xorprtm/TODO
 create mode 100644 xorp/contrib/xorprtm/xorprtm/bsdroute.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/defs.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/list.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/loadprotocol.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/mibmgr.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/mibmgr.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/pchsample.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/print_rtmsg.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/rmapi.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/rmapi.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/sync.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/sync.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/test_monitor.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/test_routeadd.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/test_routeadddelete.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/test_routeaddwait.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/utils.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/utils.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/xorprtm.c
 create mode 100644 xorp/contrib/xorprtm/xorprtm/xorprtm.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm/xorprtm_internal.h
 create mode 100644 xorp/contrib/xorprtm/xorprtm4/xorprtm4.def
 create mode 100644 xorp/contrib/xorprtm/xorprtm6/xorprtm6.def

diff --git a/xorp/contrib/xorprtm/BUGS b/xorp/contrib/xorprtm/BUGS
new file mode 100644
index 0000000..9bb3157
--- /dev/null
+++ b/xorp/contrib/xorprtm/BUGS
@@ -0,0 +1,80 @@
+Known issues:
+
+ - Routes appear in the RTM routing table but do not propagate to
+   the FIB.
+   This can be verified by comparing the output of 'route print'
+   with that of 'netsh routing ip show rtmroutes'.
+
+ * Feedback from Microsoft is needed to fix this issue.
+
+ - We use WriteFile() to broadcast data to multiple clients.
+   If one of the clients does not read the data, then the server thread
+   will hang as a result.
+   The alternative is to use overlapped I/O, but this means
+   recording lots of state for each write.
+
+ * Therefore, clients MUST read from the pipe after issuing commands.
+   This should not affect XORP, as we do not rely on the SO_USELOOPBACK
+   socket option when dealing with routing sockets, and the socket is
+   polled for input as part of the FEA's event loop.
+
+ - The use of the BSD routing socket message format is not completely
+   identical.
+
+ * We only accept a DST, GATEWAY and NETMASK for RTM_ADD.
+ * We only accept a DST and a NETMASK for RTM_DELETE.
+ * Any other combinations are not acceptable.
+
+ * RTM_IFANNOUNCE messages DO NOT contain the interface name for deletions.
+   Microsoft's Router Manager does not provide this, only the index.
+
+ * The InterfaceStatus() callback does not get called when link sense
+   changes on the media, therefore, RTM_IFINFO messages are not sent
+   when carrier is dropped or regained.
+
+ * RTM_NEWADDR messages are sent whenever the interface address list
+   changes. This is incomplete and the semantics are not the same as
+   that of the BSD routing socket; it would be necessary to record all
+   the state to just send the deltas, as InterfaceStatus() has the
+   entire address list for each interface passed to it on a change.
+
+ - The regression tests read the first 'reply' which is actually
+   the echo of the command they sent. The next 'reply' is the kernel's.
+
+ * PF_ROUTE is a broadcast domain in BSD, with specific semantics.
+   The DLL does not always broadcast the client's inbound command message first.
+   It should do so, and do it separately, following by broadcasting
+   the and separately; followed by the kernel's reply. This maintains POLA.
+
+   On BSD, the option SO_USELOOPBACK can be used to squelch the inbound
+   command message from being echoed to the process which is sending it,
+   thus maintaining the assumption of 'write once, read twice'.
+
+   Given that the DLL can block if client's don't read, this is particularly
+   important!
+
+ - Routing and Remote Access will signal that all interfaces are going
+   away when it shuts down. Client processes will see these notifications.
+
+ - Currently we squelch notifications about all-1s broadcast and multicast
+   destinations. This is because they show up as equal-cost multihop
+   rules in the table, although this doesn't tell the whole story.
+
+ * Separate DLLs for IPv4 and IPv6 shim support are needed because of
+   how DLLs are loaded. The image is loaded once into the MS Router Manager.
+   There is no copy-on-write for data sections because everything runs in
+   a single NT process. A common global instance variable is needed. We
+   can't use thread-local storage because we may be reentered by multiple
+   pool threads, and we can't tell them apart usefully at initialization.
+
+ * XXX: The following identifiers seem to be missing from the Windows SDK
+   build 5284 headers:
+ IPV6_ADDRESS_LEN_IN_BYTES
+ ConvertAddressAndLengthToNetAddress()
+ ConvertNetAddressToAddressAndLength()
+   referenced by:
+ RTM_IPV6_SET_ADDR_AND_LEN()
+ RTM_IPV6_GET_ADDR_AND_LEN()
+   There also seems to be no RTM_IPV6_MASK_FROM_LEN() function, which
+   we'd need for converting our IPv6 prefix lengths to socket address
+   structures for the modified BSD message format we currently use.
diff --git a/xorp/contrib/xorprtm/BUILD_NOTES b/xorp/contrib/xorprtm/BUILD_NOTES
new file mode 100644
index 0000000..093d222
--- /dev/null
+++ b/xorp/contrib/xorprtm/BUILD_NOTES
@@ -0,0 +1,2 @@
+Building this code requires the use of FreeType Jam 2.5.2, the
+Microsoft Visual C++ Toolkit 2003, and the latest Windows SDK.
diff --git a/xorp/contrib/xorprtm/README b/xorp/contrib/xorprtm/README
new file mode 100644
index 0000000..4aafae8
--- /dev/null
+++ b/xorp/contrib/xorprtm/README
@@ -0,0 +1,12 @@
+#
+# $XORP$
+#
+
+This is XORPRTM; a loadable protocol DLL for Microsoft's Routing and
+Remote Access Service. XORPRTM implements a named pipe server with
+asynchronous I/O which translates Router Manager V2 events into
+BSD routing socket messages, and vice versa.
+
+Using this mechanism, XORP is able to participate fully in the exchange
+of routes as part of Microsoft's Routing and Remote Access Server on
+Windows Server 2003 and Windows 'Longhorn' Server.
diff --git a/xorp/contrib/xorprtm/TODO b/xorp/contrib/xorprtm/TODO
new file mode 100644
index 0000000..ef19da1
--- /dev/null
+++ b/xorp/contrib/xorprtm/TODO
@@ -0,0 +1,22 @@
+#
+# $XORP$
+#
+
+Clean up the code.
+ Push header inclusion down to individual files.
+ Sort the functions in xorprtm.c somewhat.
+ Do a final pass to clean up function names and style.
+ Do a final indent pass.
+
+Write a GNU makefile for this code.
+Check it into the main repository.
+
+Make 'restart rras' a command line option for loadprotocol.
+Make 'unload protocol' a command line option for loadprotocol.
+
+Tasks depending on Microsoft feedback:
+ Fix route adds so they are pushed to the FIB.
+  Blocked awaiting feedback.
+ Refine and test IPv6 support.
+  Blocked on missing defines in SDK.
+  Blocked awaiting feedback.
diff --git a/xorp/contrib/xorprtm/xorprtm/bsdroute.h b/xorp/contrib/xorprtm/xorprtm/bsdroute.h
new file mode 100644
index 0000000..87e6972
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/bsdroute.h
@@ -0,0 +1,285 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/bsdroute.h,v 1.7 2008/10/02 21:56:40 bms Exp $
+ */
+
+/*-
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)route.h 8.4 (Berkeley) 1/9/95
+ * $FreeBSD: src/sys/net/route.h,v 1.63.2.1 2006/04/04 20:07:23 andre Exp $
+ */
+
+#ifndef _BSDROUTE_H_
+#define _BSDROUTE_H_
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define XORPRTM4_PIPENAME "\\\\.\\pipe\\XorpRtm4"
+#define XORPRTM4_LOGNAME "XORPRTM4"
+
+#define XORPRTM6_PIPENAME "\\\\.\\pipe\\XorpRtm6"
+#define XORPRTM6_LOGNAME "XORPRTM6"
+
+#ifdef IPV6_DLL
+#define XORPRTM_PIPENAME XORPRTM6_PIPENAME
+#define XORPRTM_LOGNAME  XORPRTM6_LOGNAME
+#define XORPRTM_TRACENAME XORPRTM6_LOGNAME
+#else
+#define XORPRTM_PIPENAME XORPRTM4_PIPENAME
+#define XORPRTM_LOGNAME  XORPRTM4_LOGNAME
+#define XORPRTM_TRACENAME XORPRTM4_LOGNAME
+#endif
+
+/*
+ * Router Manager V2 IDs for XORP
+ */
+
+#define PROTO_IP_XORPRTM PROTO_IP_HELLO
+#define XORPRTM_PROTOCOL_ID    \
+ PROTOCOL_ID(PROTO_TYPE_UCAST, PROTO_VENDOR_MS0, PROTO_IP_XORPRTM)
+
+#define XORPRTM_GLOBAL_CONFIG_ID       1
+
+/*
+ * MS Router Manager info structures
+ */
+
+typedef struct _XORPRTM_GLOBAL_CONFIG {
+    DWORD       dummy;
+} XORPRTM_GLOBAL_CONFIG, *PXORPRTM_GLOBAL_CONFIG;
+
+typedef struct _XORPRTM_MIB_SET_INPUT_DATA {
+    DWORD       IMSID_TypeID;
+    DWORD       IMSID_IfIndex;
+    DWORD       IMSID_BufferSize;
+    BYTE        IMSID_Buffer[0];
+} XORPRTM_MIB_SET_INPUT_DATA, *PXORPRTM_MIB_SET_INPUT_DATA;
+
+typedef struct _XORPRTM_MIB_GET_INPUT_DATA {
+    DWORD   IMGID_TypeID;
+    DWORD   IMGID_IfIndex;
+} XORPRTM_MIB_GET_INPUT_DATA, *PXORPRTM_MIB_GET_INPUT_DATA;
+
+typedef struct _XORPRTM_MIB_GET_OUTPUT_DATA {
+    DWORD   IMGOD_TypeID;
+    DWORD   IMGOD_IfIndex;
+    BYTE    IMGOD_Buffer[0];
+} XORPRTM_MIB_GET_OUTPUT_DATA, *PXORPRTM_MIB_GET_OUTPUT_DATA;
+
+/*
+ * BSD routing socket interface
+ */
+
+#define RTF_UP  0x1  /* route usable */
+#define RTF_GATEWAY 0x2  /* destination is a gateway */
+#define RTF_HOST 0x4  /* host entry (net otherwise) */
+#define RTF_REJECT 0x8  /* host or net unreachable */
+#define RTF_DYNAMIC 0x10  /* created dynamically (by redirect) */
+#define RTF_MODIFIED 0x20  /* modified dynamically (by redirect) */
+#define RTF_DONE 0x40  /* message confirmed */
+/*   0x80     unused, was RTF_DELCLONE */
+#define RTF_CLONING 0x100  /* generate new routes on use */
+#define RTF_XRESOLVE 0x200  /* external daemon resolves name */
+#define RTF_LLINFO 0x400  /* generated by link layer (e.g. ARP) */
+#define RTF_STATIC 0x800  /* manually added */
+#define RTF_BLACKHOLE 0x1000  /* just discard pkts (during updates) */
+#define RTF_PROTO2 0x4000  /* protocol specific routing flag */
+#define RTF_PROTO1 0x8000  /* protocol specific routing flag */
+
+#define RTF_WASCLONED 0x20000  /* route generated through cloning */
+#define RTF_PROTO3 0x40000  /* protocol specific routing flag */
+/*   0x80000     unused */
+#define RTF_PINNED 0x100000 /* future use */
+#define RTF_LOCAL 0x200000  /* route represents a local address */
+#define RTF_BROADCAST 0x400000 /* route represents a bcast address */
+#define RTF_MULTICAST 0x800000 /* route represents a mcast address */
+     /* 0x1000000 and up unassigned */
+
+/* Mask of RTF flags that are allowed to be modified by RTM_CHANGE. */
+#define RTF_FMASK \
+ (RTF_PROTO1 | RTF_PROTO2 | RTF_PROTO3 | RTF_BLACKHOLE | \
+  RTF_REJECT | RTF_STATIC)
+
+struct rt_metrics {
+    DWORD rmx_filler[14]; /* Ignore field names but pad in same way */
+};
+
+/*
+ * Structures for routing messages.
+ */
+struct rt_msghdr {
+ USHORT rtm_msglen; /* to skip over non-understood messages */
+ BYTE rtm_version; /* future binary compatibility */
+ BYTE rtm_type; /* message type */
+ USHORT rtm_index; /* index for associated ifp */
+ DWORD rtm_flags; /* flags, incl. kern & message, e.g. DONE */
+ DWORD rtm_addrs; /* bitmask identifying sockaddrs in msg */
+ LONG rtm_pid; /* identify sender */
+ LONG rtm_seq; /* for sender to identify action */
+ DWORD rtm_errno; /* why failed */
+ DWORD rtm_fmask; /* bitmask used in RTM_CHANGE message */
+#define rtm_use rtm_fmask /* deprecated, use rtm_rmx->rmx_pksent */
+ DWORD rtm_inits; /* which metrics we are initializing */
+ struct rt_metrics rtm_rmx; /* metrics themselves */
+};
+
+#define RTM_VERSION 66 /* Unique to XORP/Win32 */
+
+/*
+ * Message types.
+ * Only those supported by the Windows subsystem are provided.
+ */
+#define RTM_ADD  0x1 /* Add Route */
+#define RTM_DELETE 0x2 /* Delete Route */
+#define RTM_CHANGE 0x3 /* Change Metrics or flags */
+#define RTM_NEWADDR 0xc /* address being added to iface */
+#define RTM_DELADDR 0xd /* address being removed from iface */
+#define RTM_IFINFO 0xe /* iface going up/down etc. */
+#define RTM_IFANNOUNCE 0x11 /* iface arrival/departure */
+
+/*
+ * Bitmask values for rtm_addrs.
+ */
+#define RTA_DST  0x1 /* destination sockaddr present */
+#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
+#define RTA_NETMASK 0x4 /* netmask sockaddr present */
+#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */
+#define RTA_IFP  0x10 /* interface name sockaddr present */
+#define RTA_IFA  0x20 /* interface addr sockaddr present */
+#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
+#define RTA_BRD  0x80 /* for NEWADDR, broadcast or p-p dest addr */
+
+/*
+ * Index offsets for sockaddr array for alternate internal encoding.
+ */
+#define RTAX_DST 0 /* destination sockaddr present */
+#define RTAX_GATEWAY 1 /* gateway sockaddr present */
+#define RTAX_NETMASK 2 /* netmask sockaddr present */
+#define RTAX_GENMASK 3 /* cloning mask sockaddr present */
+#define RTAX_IFP 4 /* interface name sockaddr present */
+#define RTAX_IFA 5 /* interface addr sockaddr present */
+#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */
+#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */
+#define RTAX_MAX 8 /* size of array to allocate */
+
+/*
+ * XXX: The Winsock definition of struct sockaddr does not have
+ * a size value, therefore we use struct sockaddr_storage in its entirety.
+ */
+#define SA_SIZE(sa) sizeof(struct sockaddr_storage)
+
+/*
+ * XXX: The length of IFNAMSIZ must be consistent across the ABI.
+ * It's different from BSDs to allow for arbitrary FriendlyNames,
+ * up to a length of 256 bytes.
+ */
+#ifdef IFNAMSIZ
+#undef IFNAMSIZ
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 256
+#endif
+
+#define IFAN_ARRIVAL    0       /* interface arrival */
+#define IFAN_DEPARTURE  1       /* interface departure */
+
+struct if_announcemsghdr {
+    USHORT  ifan_msglen;
+    BYTE    ifan_version;
+    BYTE    ifan_type;
+    DWORD   ifan_index;      /* XXX: This is now 32-bits wide */
+    BYTE    ifan_name[IFNAMSIZ];    /* FriendlyName in ANSI text. */
+    BYTE    ifan_what;
+};
+
+/*
+ * Values for if_link_state.
+ */
+#define LINK_STATE_UNKNOWN      0       /* link invalid/unknown */
+#define LINK_STATE_DOWN         1       /* link is down */
+#define LINK_STATE_UP           2       /* link is up */
+
+/*
+ * XXX: Most of the fields in the original BSD if_data
+ * structure can't be obtained on Windows from the
+ * RTMv2 interface status callback, therefore this
+ * structure is very minimal.
+ */
+struct if_data {
+    BYTE    ifi_link_state;
+};
+
+struct if_msghdr {
+    USHORT  ifm_msglen;
+    BYTE    ifm_version;
+    BYTE    ifm_type;
+    DWORD   ifm_addrs;
+    DWORD   ifm_flags;
+    DWORD   ifm_index;
+    struct  if_data ifm_data;
+};
+
+struct ifa_msghdr {
+    USHORT  ifam_msglen;
+    BYTE    ifam_version;
+    BYTE    ifam_type;
+    DWORD   ifam_addrs;
+    DWORD   ifam_flags;
+    DWORD   ifam_index;
+    DWORD   ifam_metric;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _BSDROUTE_H_ */
diff --git a/xorp/contrib/xorprtm/xorprtm/defs.h b/xorp/contrib/xorprtm/xorprtm/defs.h
new file mode 100644
index 0000000..9c44ecf
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/defs.h
@@ -0,0 +1,93 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/defs.h,v 1.7 2008/10/02 21:56:40 bms Exp $
+ */
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#ifndef _DEFS_H_
+#define _DEFS_H_
+
+#define GLOBAL_HEAP                 g_ce.hGlobalHeap
+#define TRACEID                     g_ce.dwTraceID
+
+#define ENTER_XORPRTM_API()          EnterSubsystemAPI()
+#define ENTER_XORPRTM_WORKER()       EnterSubsystemWorker()
+#define LEAVE_XORPRTM_API()          LeaveSubsystemWorker()
+#define LEAVE_XORPRTM_WORKER()       LeaveSubsystemWorker()
+
+#define MALLOC(ppPointer, ulSize, pdwErr)                                   \
+{                                                                           \
+    if (*(ppPointer) = HeapAlloc(GLOBAL_HEAP, HEAP_ZERO_MEMORY, (ulSize)))  \
+    {                                                                       \
+        *(pdwErr) = NO_ERROR;                                               \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        *(pdwErr) = ERROR_NOT_ENOUGH_MEMORY;                                \
+        TRACE1(ANY, "Error allocating %u bytes", (ulSize));                 \
+    }                                                                       \
+}
+#define REALLOC(ptr, size)          HeapReAlloc(GLOBAL_HEAP, 0, ptr, size)
+#define FREE(ptr)                                           \
+{                                                           \
+     HeapFree(GLOBAL_HEAP, 0, (ptr));                       \
+     (ptr) = NULL;                                          \
+}
+
+#define XORPRTM_TRACE_ANY             ((DWORD)0xFFFF0000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_ENTER           ((DWORD)0x00010000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_LEAVE           ((DWORD)0x00020000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_DEBUG           ((DWORD)0x00040000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_CONFIGURATION   ((DWORD)0x00100000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_NETWORK         ((DWORD)0x00200000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_PACKET          ((DWORD)0x00400000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_TIMER           ((DWORD)0x00800000 | TRACE_USE_MASK)
+#define XORPRTM_TRACE_MIB             ((DWORD)0x01000000 | TRACE_USE_MASK)
+
+#define TRACE0(l,a)                                                     \
+    if (TRACEID != INVALID_TRACEID)                                     \
+        TracePrintfEx(TRACEID, XORPRTM_TRACE_ ## l, a)
+#define TRACE1(l,a,b)                                                   \
+    if (TRACEID != INVALID_TRACEID)                                     \
+        TracePrintfEx(TRACEID, XORPRTM_TRACE_ ## l, a, b)
+#define TRACE2(l,a,b,c)                                                 \
+    if (TRACEID != INVALID_TRACEID)                                     \
+        TracePrintfEx(TRACEID, XORPRTM_TRACE_ ## l, a, b, c)
+#define TRACE3(l,a,b,c,d)                                               \
+    if (TRACEID != INVALID_TRACEID)                                     \
+        TracePrintfEx(TRACEID, XORPRTM_TRACE_ ## l, a, b, c, d)
+#define TRACE4(l,a,b,c,d,e)                                             \
+    if (TRACEID != INVALID_TRACEID)                                     \
+        TracePrintfEx(TRACEID, XORPRTM_TRACE_ ## l, a, b, c, d, e)
+#define TRACE5(l,a,b,c,d,e,f)                                           \
+    if (TRACEID != INVALID_TRACEID)                                     \
+        TracePrintfEx(TRACEID, XORPRTM_TRACE_ ## l, a, b, c, d, e, f)
+
+#endif /* _DEFS_H_ */
diff --git a/xorp/contrib/xorprtm/xorprtm/list.h b/xorp/contrib/xorprtm/xorprtm/list.h
new file mode 100644
index 0000000..a1da37b
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/list.h
@@ -0,0 +1,175 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/list.h,v 1.7 2008/10/02 21:56:40 bms Exp $
+ */
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#ifndef _LIST_H_
+#define _LIST_H_
+
+#define InitializeListHead(ListHead)                            \
+    ((ListHead)->Flink = (ListHead)->Blink = (ListHead))
+
+#define IsListEmpty(ListHead)                                   \
+    ((ListHead)->Flink == (ListHead))
+
+#define RemoveHeadList(ListHead)                                \
+    (ListHead)->Flink;                                          \
+    {RemoveEntryList((ListHead)->Flink)}
+
+#define RemoveTailList(ListHead)                                \
+    (ListHead)->Blink;                                          \
+    {RemoveEntryList((ListHead)->Blink)}
+
+#define RemoveEntryList(Entry)                                  \
+{                                                               \
+    PLIST_ENTRY _EX_Blink;                                      \
+    PLIST_ENTRY _EX_Flink;                                      \
+    _EX_Flink = (Entry)->Flink;                                 \
+    _EX_Blink = (Entry)->Blink;                                 \
+    _EX_Blink->Flink = _EX_Flink;                               \
+    _EX_Flink->Blink = _EX_Blink;                               \
+}
+
+#define InsertTailList(ListHead,Entry)                          \
+{                                                               \
+    PLIST_ENTRY _EX_Blink;                                      \
+    PLIST_ENTRY _EX_ListHead;                                   \
+    _EX_ListHead = (ListHead);                                  \
+    _EX_Blink = _EX_ListHead->Blink;                            \
+    (Entry)->Flink = _EX_ListHead;                              \
+    (Entry)->Blink = _EX_Blink;                                 \
+    _EX_Blink->Flink = (Entry);                                 \
+    _EX_ListHead->Blink = (Entry);                              \
+}
+
+#define InsertHeadList(ListHead,Entry)                          \
+{                                                               \
+    PLIST_ENTRY _EX_Flink;                                      \
+    PLIST_ENTRY _EX_ListHead;                                   \
+    _EX_ListHead = (ListHead);                                  \
+    _EX_Flink = _EX_ListHead->Flink;                            \
+    (Entry)->Flink = _EX_Flink;                                 \
+    (Entry)->Blink = _EX_ListHead;                              \
+    _EX_Flink->Blink = (Entry);                                 \
+    _EX_ListHead->Flink = (Entry);                              \
+}
+
+#define InsertSortedList(ListHead, Entry, CompareFunction)      \
+{                                                               \
+    PLIST_ENTRY _EX_Entry;                                      \
+    PLIST_ENTRY _EX_Blink;                                      \
+    for (_EX_Entry = (ListHead)->Flink;                         \
+         _EX_Entry != (ListHead);                               \
+         _EX_Entry = _EX_Entry->Flink)                          \
+        if ((*(CompareFunction))((Entry), _EX_Entry) <= 0)      \
+            break;                                              \
+    _EX_Blink = _EX_Entry->Blink;                               \
+    _EX_Blink->Flink = (Entry);                                 \
+    _EX_Entry->Blink = (Entry);                                 \
+    (Entry)->Flink     = _EX_Entry;                             \
+    (Entry)->Blink     = _EX_Blink;                             \
+}
+
+#define FindList(ListHead, Key, Entry, CompareFunction)         \
+{                                                               \
+    PLIST_ENTRY _EX_Entry;                                      \
+    *(Entry) = NULL;                                            \
+    for (_EX_Entry = (ListHead)->Flink;                         \
+         _EX_Entry != (ListHead);                               \
+         _EX_Entry = _EX_Entry->Flink)                          \
+        if ((*(CompareFunction))((Key), _EX_Entry) == 0)        \
+        {                                                       \
+            *(Entry) = _EX_Entry;                               \
+            break;                                              \
+        }                                                       \
+}
+
+#define FindSortedList(ListHead, Key, Entry, CompareFunction)   \
+{                                                               \
+    PLIST_ENTRY _EX_Entry;                                      \
+    *(Entry) = NULL;                                            \
+    for (_EX_Entry = (ListHead)->Flink;                         \
+         _EX_Entry != (ListHead);                               \
+         _EX_Entry = _EX_Entry->Flink)                          \
+        if ((*(CompareFunction))((Key), _EX_Entry) <= 0)        \
+        {                                                       \
+            *(Entry) = _EX_Entry;                               \
+            break;                                              \
+        }                                                       \
+}
+
+#define MapCarList(ListHead, VoidFunction)                      \
+{                                                               \
+    PLIST_ENTRY _EX_Entry;                                      \
+    for (_EX_Entry = (ListHead)->Flink;                         \
+         _EX_Entry != (ListHead);                               \
+         _EX_Entry = _EX_Entry->Flink)                          \
+        (*(VoidFunction))(_EX_Entry);                           \
+}
+
+#define FreeList(ListHead, FreeFunction)                        \
+{                                                               \
+    PLIST_ENTRY _EX_Head;                                       \
+    while (!IsListEmpty(ListHead))                              \
+    {                                                           \
+        _EX_Head = RemoveHeadList(ListHead);                    \
+        (*(FreeFunction))(_EX_Head);                            \
+    }                                                           \
+}
+
+#define QUEUE_ENTRY                     LIST_ENTRY
+#define PQUEUE_ENTRY                    PLIST_ENTRY
+
+#define InitializeQueueHead(QueueHead)  InitializeListHead(QueueHead)
+#define IsQueueEmpty(QueueHead)         IsListEmpty(QueueHead)
+#define Enqueue(QueueHead, Entry)       InsertTailList(QueueHead, Entry)
+#define Dequeue(QueueHead)              RemoveHeadList(QueueHead)
+#define FreeQueue(QueueHead, FreeFunction)                      \
+    FreeList(QueueHead, FreeFunction)
+#define MapCarQueue(QueueHead, VoidFunction)                    \
+    MapCarList(QueueHead, VoidFunction)
+
+#define STACK_ENTRY                     LIST_ENTRY
+#define PSTACK_ENTRY                    PLIST_ENTRY
+
+#define InitializeStackHead(StackHead)  InitializeListHead(StackHead)
+#define IsStackEmpty(StackHead)         IsListEmpty(StackHead)
+#define Push(StackHead, Entry)          InsertHeadList(StackHead, Entry)
+#define Pop(StackHead)                  RemoveHeadList(StackHead)
+#define FreeStack(StackHead, FreeFunction)                      \
+    FreeList(StackHead, FreeFunction)
+#define MapCarStack(StackHead, VoidFunction)                    \
+    MapCarList(StackHead, VoidFunction)
+
+#endif /* _LIST_H_ */
+
+
+
diff --git a/xorp/contrib/xorprtm/xorprtm/loadprotocol.c b/xorp/contrib/xorprtm/xorprtm/loadprotocol.c
new file mode 100644
index 0000000..8c35183
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/loadprotocol.c
@@ -0,0 +1,365 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/loadprotocol.c,v 1.7 2008/10/02 21:56:40 bms Exp $"
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+/*
+ * Modified version of LoadProtocol for integration into XORP.
+ * Restarts RRAS service after making registry changes.
+ * Loads the DLL into RRAS using MPR API calls.
+ */
+
+#define UNICODE
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+#include <mprapi.h>
+#include <rtinfo.h>
+#include <routprot.h>
+
+#include "xorprtm.h"
+
+HRESULT
+add_protocol_to_rras(int family)
+{
+    static const SHORT XORPRTM_BLOCK_SIZE = 0x0004;
+    HRESULT     hr = S_OK;
+    DWORD       dwErr = ERROR_SUCCESS;
+    DWORD       dwErrT = ERROR_SUCCESS;
+    MPR_SERVER_HANDLE   hMprServer = NULL;
+    HANDLE   hMprConfig = NULL;
+    LPBYTE      pByte = NULL;
+    LPVOID        pHeader = NULL;
+    LPVOID        pNewHeader = NULL;
+    DWORD       dwSize = 0;
+    HANDLE      hTransport = NULL;
+    LPCWSTR pswzServerName = NULL;
+    int     pid;
+    XORPRTM_GLOBAL_CONFIG   igc;
+
+    memset(&igc, 0, sizeof(igc));
+
+#ifdef IPV6_DLL
+    if (family == AF_INET) {
+ pid = PID_IP;
+    } else {
+ pid = PID_IPV6;
+    }
+#else
+    pid = PID_IP;
+#endif
+
+    /* Connect to the server */
+    /* ---------------------------------------------------------------- */
+    dwErr = MprAdminServerConnect((LPWSTR) pswzServerName, &hMprServer);
+    if (dwErr == ERROR_SUCCESS)
+    {
+        /* Ok, get the infobase from the server */
+        /* ------------------------------------------------------------ */
+        dwErr = MprAdminTransportGetInfo(hMprServer,
+                                         pid,
+                                         &pByte,
+                                         &dwSize,
+                                         NULL,
+                                         NULL);
+
+        if (dwErr == ERROR_SUCCESS)
+        {
+            /* Call MprInfoDuplicate to create a duplicate of */
+            /* the infoblock */
+            /* -------------------------------------------------------- */
+            MprInfoDuplicate(pByte, &pHeader);
+            MprAdminBufferFree(pByte);
+            pByte = NULL;
+            dwSize = 0;
+        }
+    }
+
+    /* We also have to open the hMprConfig, but we can ignore the error */
+    /* ---------------------------------------------------------------- */
+    dwErrT = MprConfigServerConnect((LPWSTR) pswzServerName, &hMprConfig);
+    if (dwErrT == ERROR_SUCCESS)
+    {
+        dwErrT = MprConfigTransportGetHandle(hMprConfig, pid, &hTransport);
+    }
+
+    if (dwErr != ERROR_SUCCESS)
+    {
+        /* Ok, try to use the MprConfig calls. */
+        /* ------------------------------------------------------------ */
+        MprConfigTransportGetInfo(hMprConfig,
+                                  hTransport,
+                                  &pByte,
+                                  &dwSize,
+                                  NULL,
+                                  NULL,
+                                  NULL);
+
+        /* Call MprInfoDuplicate to create a duplicate of */
+        /* the infoblock */
+        /* ------------------------------------------------------------ */
+        MprInfoDuplicate(pByte, &pHeader);
+        MprConfigBufferFree(pByte);
+        pByte = NULL;
+        dwSize = 0;
+    }
+
+    /* Call MprInfoBlockRemove to remove the old protocol block */
+    MprInfoBlockRemove(pHeader, PROTO_IP_XORPRTM, &pNewHeader);
+
+    /* Did we remove the block? */
+    if (pNewHeader != NULL)
+    {
+        /* The block was found and removed, so use the new header. */
+        MprInfoDelete(pHeader);
+        pHeader = pNewHeader;
+        pNewHeader = NULL;
+    }
+
+    /* Add protocol to the infoblock here!     */
+    MprInfoBlockAdd(pHeader,
+                    PROTO_IP_XORPRTM,
+                    XORPRTM_BLOCK_SIZE,
+                    1,
+                    (LPBYTE)&igc,
+                    &pNewHeader);
+    MprInfoDelete(pHeader);
+    pHeader = NULL;
+
+
+    if (hMprServer)
+    {
+
+        MprAdminTransportSetInfo(hMprServer,
+                                 pid,
+                                 (BYTE*)pNewHeader,
+                                 MprInfoBlockQuerySize(pNewHeader),
+                                 NULL,
+                                 0);
+    }
+
+    if (hMprConfig && hTransport)
+    {
+
+        MprConfigTransportSetInfo(hMprConfig,
+                                  hTransport,
+                                  (BYTE*)pNewHeader,
+                                  MprInfoBlockQuerySize(pNewHeader),
+                                  NULL,
+                                  0,
+                                  NULL);
+    }
+
+    if (pHeader)
+        MprInfoDelete(pHeader);
+
+    if (pNewHeader)
+        MprInfoDelete(pNewHeader);
+
+    if (hMprConfig)
+        MprConfigServerDisconnect(hMprConfig);
+
+    if (hMprServer)
+        MprAdminServerDisconnect(hMprServer);
+
+    return hr;
+}
+
+int
+restart_rras()
+{
+    SERVICE_STATUS ss;
+    SC_HANDLE h_scm;
+    SC_HANDLE h_rras;
+    DWORD result;
+    int is_running, tries, fatal;
+
+    h_scm = OpenSCManager(NULL, NULL, GENERIC_READ);
+    if (h_scm == NULL) {
+ return (-1);
+    }
+
+    h_rras = OpenService(h_scm, RRAS_SERVICE_NAME, GENERIC_READ);
+    if (h_rras == NULL) {
+     result = GetLastError();
+ /*printf("OpenService() failed: %d", result); */
+ CloseServiceHandle(h_scm);
+ return (-1);
+    }
+
+    fatal = 0;
+
+    /*printf("Stoping service \"%s\" ", RRAS_SERVICE_NAME); */
+
+    for (tries = 30; tries > 0; tries++) {
+ /* Check if the service is running, stopping, or stopped. */
+ result = ControlService(h_rras, SERVICE_CONTROL_INTERROGATE, &ss);
+ if (result == NO_ERROR) {
+     /* Stopped; carry on */
+     if (ss.dwCurrentState == SERVICE_STOPPED)
+  break;
+     /* Stopping; poll until it's done */
+     if (ss.dwCurrentState == SERVICE_STOP_PENDING) {
+  Sleep(1000);
+  continue;
+     }
+ } else if (result == ERROR_SERVICE_NOT_ACTIVE) {
+     break;
+ } else {
+     fatal = 1;
+     break;
+ }
+
+ result = ControlService(h_rras, SERVICE_CONTROL_STOP, &ss);
+ if (result == ERROR_SERVICE_NOT_ACTIVE) {
+     break;
+ } else if (result != NO_ERROR) {
+     fatal = 1;
+     break;
+ }
+    }
+
+    /* XXX: We should really check to see if it started OK. */
+    result = StartService(h_rras, 0, NULL);
+
+    /* ... should finish doing this ... */
+
+    CloseServiceHandle(h_rras);
+    CloseServiceHandle(h_scm);
+
+    return (0);
+}
+
+/*
+ * Registry stuff. This is messy.
+ */
+
+#define HKLM_XORPRTM4_NAME \
+"SOFTWARE\\Microsoft\\Router\\CurrentVersion\\RouterManagers\\Ip\\XORPRTM4"
+
+#define HKLM_XORPRTM6_NAME \
+"SOFTWARE\\Microsoft\\Router\\CurrentVersion\\RouterManagers\\Ipv6\\XORPRTM6"
+
+#define HKLM_XORPRTM4_TRACING_NAME \
+"SOFTWARE\\Microsoft\\Tracing\\XORPRTM4"
+
+#define HKLM_XORPRTM6_TRACING_NAME \
+"SOFTWARE\\Microsoft\\Tracing\\XORPRTM6"
+
+static CHAR DLL_CLSID_IPV4[] = "{C2FE450A-D6C2-11D0-A37B-00C04FC9DA04}";
+static CHAR DLL_CLSID_IPV6[] = "{C2FE451A-D6C2-11D0-A37B-00C04FC9DA04}";
+static CHAR DLL_CONFIG_DLL[] = "nonexistent.dll";
+static CHAR DLL_NAME_IPV4[] = "xorprtm4.dll";
+static CHAR DLL_NAME_IPV6[] = "xorprtm6.dll";
+static DWORD DLL_FLAGS = 0x00000002;
+static DWORD DLL_PROTO = PROTO_IP_XORPRTM;
+static CHAR DLL_TITLE_IPV4[] = "Router Manager V2 adapter for XORP (IPv4)";
+static CHAR DLL_TITLE_IPV6[] = "Router Manager V2 adapter for XORP (IPv6)";
+static CHAR DLL_VENDOR[] = "www.xorp.org";
+#if 1
+static CHAR TRACING_DIR[] = "%windir%\\Tracing";
+#endif
+
+void
+add_protocol_to_registry(int family)
+{
+    DWORD result;
+    DWORD foo;
+    HKEY hKey;
+
+    result = RegCreateKeyExA(
+  HKEY_LOCAL_MACHINE,
+  family == AF_INET ? HKLM_XORPRTM4_NAME : HKLM_XORPRTM6_NAME,
+  0,
+  NULL,
+  REG_OPTION_NON_VOLATILE,
+  KEY_ALL_ACCESS,
+  NULL,
+  &hKey,
+  NULL);
+
+    RegSetValueExA(hKey, "ConfigDll", 0, REG_SZ, DLL_CONFIG_DLL, sizeof(DLL_CONFIG_DLL));
+    if (family == AF_INET) {
+     RegSetValueExA(hKey, "ConfigClsId", 0, REG_SZ, DLL_CLSID_IPV4, sizeof(DLL_CLSID_IPV4));
+     RegSetValueExA(hKey, "Title", 0, REG_SZ, DLL_TITLE_IPV4, sizeof(DLL_TITLE_IPV4));
+     RegSetValueExA(hKey, "DllName", 0, REG_SZ, DLL_NAME_IPV4, sizeof(DLL_NAME_IPV4));
+    } else {
+     RegSetValueExA(hKey, "ConfigClsId", 0, REG_SZ, DLL_CLSID_IPV6, sizeof(DLL_CLSID_IPV6));
+     RegSetValueExA(hKey, "Title", 0, REG_SZ, DLL_TITLE_IPV6, sizeof(DLL_TITLE_IPV6));
+     RegSetValueExA(hKey, "DllName", 0, REG_SZ, DLL_NAME_IPV6, sizeof(DLL_NAME_IPV6));
+    }
+    RegSetValueExA(hKey, "Flags", 0, REG_DWORD, (BYTE*)&DLL_FLAGS, sizeof(DLL_FLAGS));
+    RegSetValueExA(hKey, "ProtocolId", 0, REG_DWORD, (BYTE*)&DLL_PROTO, sizeof(DLL_PROTO));
+    RegSetValueExA(hKey, "VendorName", 0, REG_SZ, DLL_VENDOR, sizeof(DLL_VENDOR));
+    RegCloseKey(hKey);
+
+#if 1
+ /* XXX: Enable console tracing for debugging. */
+
+    result = RegCreateKeyExA(
+  HKEY_LOCAL_MACHINE,
+  family == AF_INET ? HKLM_XORPRTM4_TRACING_NAME : HKLM_XORPRTM6_TRACING_NAME,
+  0,
+  NULL,
+  REG_OPTION_NON_VOLATILE,
+  KEY_ALL_ACCESS,
+  NULL,
+  &hKey,
+  NULL);
+
+    foo = 1;
+    RegSetValueExA(hKey, "EnableConsoleTracing", 0, REG_DWORD, (BYTE*)&foo, sizeof(foo));
+    RegSetValueExA(hKey, "EnableFileTracing", 0, REG_DWORD, (BYTE*)&foo, sizeof(foo));
+    foo = 0xFFFF0000;
+    RegSetValueExA(hKey, "ConsoleTracingMask", 0, REG_DWORD, (BYTE*)&foo, sizeof(foo));
+    RegSetValueExA(hKey, "FileTracingMask", 0, REG_DWORD, (BYTE*)&foo, sizeof(foo));
+    foo = 0x00100000;
+    RegSetValueExA(hKey, "MaxFileSize", 0, REG_DWORD, (BYTE*)&foo, sizeof(foo));
+
+    RegSetValueExA(hKey, "FileDirectory", 0, REG_EXPAND_SZ, TRACING_DIR, sizeof(TRACING_DIR));
+
+    RegCloseKey(hKey);
+#endif
+}
+
+int
+main(int argc, char *argv[])
+{
+    add_protocol_to_registry(AF_INET);
+#ifdef IPV6_DLL
+    add_protocol_to_registry(AF_INET6);
+#endif
+
+    restart_rras();
+
+    add_protocol_to_rras(AF_INET);
+#ifdef IPV6_DLL
+    add_protocol_to_rras(AF_INET6);
+#endif
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/mibmgr.c b/xorp/contrib/xorprtm/xorprtm/mibmgr.c
new file mode 100644
index 0000000..6a9f87f
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/mibmgr.c
@@ -0,0 +1,124 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/mibmgr.c,v 1.7 2008/10/02 21:56:40 bms Exp $"
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#include "pchsample.h"
+#pragma hdrstop
+
+/* XXX: This needs to use the router manager event queue interface. */
+DWORD
+WINAPI
+MM_MibSet (
+    PXORPRTM_MIB_SET_INPUT_DATA    pimsid)
+{
+    DWORD                   dwErr = NO_ERROR;
+    ROUTING_PROTOCOL_EVENTS rpeEvent;
+    MESSAGE                 mMessage = {0, 0, 0};
+
+    TRACE0(ENTER, "Entering MM_MibSet");
+
+    if (!ENTER_XORPRTM_API()) { return ERROR_CAN_NOT_COMPLETE; }
+
+    do {
+        if (pimsid->IMSID_TypeID == XORPRTM_GLOBAL_CONFIG_ID) {
+            if (pimsid->IMSID_BufferSize < sizeof(XORPRTM_GLOBAL_CONFIG)) {
+                dwErr = ERROR_INVALID_PARAMETER;
+                break;
+            }
+           rpeEvent = SAVE_GLOBAL_CONFIG_INFO;
+        } else {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+        /* notify router manager */
+        if (EnqueueEvent(rpeEvent, mMessage) == NO_ERROR)
+            SetEvent(g_ce.hMgrNotificationEvent);
+
+    } while(FALSE);
+
+    LEAVE_XORPRTM_API();
+
+    TRACE0(ENTER, "Leaving MM_MibSet");
+    return dwErr;
+}
+
+/* XXX: We must have a 'mib get' function to retrieve the global config. */
+DWORD
+WINAPI
+MM_MibGet (
+    PXORPRTM_MIB_GET_INPUT_DATA    pimgid,
+    PXORPRTM_MIB_GET_OUTPUT_DATA   pimgod,
+    PULONG                         pulOutputSize,
+    MODE                            mMode)
+{
+    DWORD               dwErr           = NO_ERROR;
+    ULONG               ulSizeGiven     = 0;
+    ULONG               ulSizeNeeded    = 0;
+
+    TRACE0(ENTER, "Entering MM_MibGet");
+
+    if (!ENTER_XORPRTM_API()) { return ERROR_CAN_NOT_COMPLETE; }
+
+    if (*pulOutputSize < sizeof(XORPRTM_MIB_GET_OUTPUT_DATA))
+        ulSizeGiven = 0;
+    else
+        ulSizeGiven = *pulOutputSize - sizeof(XORPRTM_MIB_GET_OUTPUT_DATA);
+
+    switch (pimgid->IMGID_TypeID) {
+        case XORPRTM_GLOBAL_CONFIG_ID: {
+            if (mMode == GET_NEXT) {
+                dwErr = ERROR_NO_MORE_ITEMS;
+                break;
+            }
+            dwErr = CM_GetGlobalInfo ((PVOID) pimgod->IMGOD_Buffer,
+                                      &ulSizeGiven,
+                                      NULL,
+                                      NULL,
+                                      NULL);
+            ulSizeNeeded = ulSizeGiven;
+            if (dwErr != NO_ERROR)
+                break;
+            pimgod->IMGOD_TypeID = XORPRTM_GLOBAL_CONFIG_ID;
+            break;
+        }
+
+        default: {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+    }
+
+    *pulOutputSize = sizeof(XORPRTM_MIB_GET_OUTPUT_DATA) + ulSizeNeeded;
+
+    LEAVE_XORPRTM_API();
+
+    TRACE0(ENTER, "Leaving MM_MibGet");
+    return dwErr;
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/mibmgr.h b/xorp/contrib/xorprtm/xorprtm/mibmgr.h
new file mode 100644
index 0000000..94c498f
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/mibmgr.h
@@ -0,0 +1,50 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/mibmgr.h,v 1.7 2008/10/02 21:56:40 bms Exp $
+ */
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#ifndef _MIBMANAGER_H_
+#define _MIBMANAGER_H_
+
+typedef enum { GET_EXACT, GET_FIRST, GET_NEXT } MODE;
+
+DWORD
+WINAPI
+MM_MibSet (PXORPRTM_MIB_SET_INPUT_DATA    pimsid);
+
+DWORD
+WINAPI
+MM_MibGet (PXORPRTM_MIB_GET_INPUT_DATA    pimgid,
+    PXORPRTM_MIB_GET_OUTPUT_DATA   pimgod,
+    PULONG                         pulOutputSize,
+    MODE                            mMode);
+
+#endif
diff --git a/xorp/contrib/xorprtm/xorprtm/pchsample.h b/xorp/contrib/xorprtm/xorprtm/pchsample.h
new file mode 100644
index 0000000..a390615
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/pchsample.h
@@ -0,0 +1,64 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/pchsample.h,v 1.7 2008/10/02 21:56:40 bms Exp $
+ */
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#ifndef _PCHSAMPLE_H_
+#define _PCHSAMPLE_H_
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <routprot.h>
+#include <rtmv2.h>
+#include <iprtrmib.h>
+#include <mgm.h>
+
+#include <mprerror.h>
+#include <rtutils.h>
+
+#include <stdio.h>
+#include <wchar.h>
+
+#include "xorprtm.h"
+
+#include "list.h"
+#include "sync.h"
+
+#include "defs.h"
+#include "utils.h"
+
+#include "xorprtm_internal.h"
+#include "mibmgr.h"
+
+#include "bsdroute.h"
+
+#endif
diff --git a/xorp/contrib/xorprtm/xorprtm/print_rtmsg.c b/xorp/contrib/xorprtm/xorprtm/print_rtmsg.c
new file mode 100644
index 0000000..c910f69
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/print_rtmsg.c
@@ -0,0 +1,737 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/print_rtmsg.c,v 1.8 2008/10/02 21:56:40 bms Exp $"
+
+/*
+ * Copyright (c) 1983, 1989, 1991, 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bsdroute.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+int warnx(char *str, ...)
+{
+  int ret;
+  va_list ap;
+
+  va_start(ap, str);
+  ret = vfprintf(stderr, str, ap);
+  va_end(ap);
+
+  exit(1);
+
+  return ret;
+}
+
+int warn(char *str,...)
+{
+  int ret;
+  va_list ap;
+
+  va_start(ap, str);
+  ret = vfprintf(stderr, str, ap);
+  va_end(ap);
+
+  return ret;
+}
+
+int
+snprintf(char *cp, size_t sz, char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsprintf(cp, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_storage ss; /* added to avoid memory overrun */
+} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
+
+typedef union sockunion *sup;
+int pid, rtm_addrs;
+int s;
+int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
+int iflag, aflen = sizeof (struct sockaddr_in);
+int locking, lockrest, debugonly;
+struct rt_metrics rt_metrics;
+u_long  rtm_inits;
+const char *routename(), *netname();
+void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
+void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
+static int inet6_makenetandmask(struct sockaddr_in6 *, char *);
+int getaddr(), rtmsg();
+int prefixlen();
+
+
+int verbose = 1;
+
+const char *
+routename(sa)
+ struct sockaddr *sa;
+{
+ char *cp;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1, n;
+
+ if (first) {
+  first = 0;
+  if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+      (cp = strchr(domain, '.'))) {
+   domain[MAXHOSTNAMELEN] = '\0';
+   (void) strcpy(domain, cp + 1);
+  } else
+   domain[0] = 0;
+ }
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+     { struct in_addr in;
+  in = ((struct sockaddr_in *)sa)->sin_addr;
+
+  cp = 0;
+  if (in.s_addr == INADDR_ANY /*|| sa->sa_len < 4*/)
+   cp = "default";
+  if (cp == 0 && !nflag) {
+   hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+    AF_INET);
+   if (hp) {
+    if ((cp = strchr(hp->h_name, '.')) &&
+        !strcmp(cp + 1, domain))
+     *cp = 0;
+    cp = hp->h_name;
+   }
+  }
+  if (cp) {
+   strncpy(line, cp, sizeof(line) - 1);
+   line[sizeof(line) - 1] = '\0';
+  } else
+   (void) sprintf(line, "%s", inet_ntoa(in));
+  break;
+     }
+
+#ifdef INET6
+ case AF_INET6:
+ {
+  struct sockaddr_in6 sin6; /* use static var for safety */
+  int niflags = 0;
+
+  memset(&sin6, 0, sizeof(sin6));
+  memcpy(&sin6, sa, sizeof(sin6));
+  sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+  if ((IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+       IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+      sin6.sin6_scope_id == 0) {
+   sin6.sin6_scope_id =
+       ntohs(*(USHORT *)&sin6.sin6_addr.s6_addr[2]);
+   sin6.sin6_addr.s6_addr[2] = 0;
+   sin6.sin6_addr.s6_addr[3] = 0;
+  }
+#endif
+  if (nflag)
+   niflags |= NI_NUMERICHOST;
+  if (getnameinfo((struct sockaddr *)&sin6,
+      sizeof(struct sockaddr_in6),
+      line, sizeof(line), NULL, 0, niflags) != 0)
+   strncpy(line, "invalid", sizeof(line));
+
+  return (line);
+ }
+#endif
+
+ default:
+     { u_short *s = (u_short *)sa;
+  /*u_short *slim = s + ((sa->sa_len + 1) >> 1);*/
+  u_short *slim = s + ((sizeof(struct sockaddr_storage) + 1) >> 1);
+  char *cp = line + sprintf(line, "(%d)", sa->sa_family);
+  char *cpe = line + sizeof(line);
+
+  /* XXX: If not first, and family 0, assume it's
+   * a network mask in a 'struct sockaddr_storage' and
+   * just treat it as an inet mask.
+   */
+  if (!first && sa->sa_family == 0) {
+      slim = s + ((sizeof(struct sockaddr_in) + 1) >> 1);
+  }
+
+  while (++s < slim && cp < cpe) /* start with sa->sa_data */
+   if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
+    cp += n;
+   else
+    *cp = '\0';
+  break;
+     }
+ }
+ return (line);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+const char *
+netname(sa)
+ struct sockaddr *sa;
+{
+ char *cp = 0;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct netent *np = 0;
+ u_long net, mask;
+ u_long i;
+ int n, subnetshift;
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+     { struct in_addr in;
+  in = ((struct sockaddr_in *)sa)->sin_addr;
+
+  i = in.s_addr = ntohl(in.s_addr);
+  if (in.s_addr == 0)
+   cp = "default";
+  else if (!nflag) {
+   if (IN_CLASSA(i)) {
+    mask = IN_CLASSA_NET;
+    subnetshift = 8;
+   } else if (IN_CLASSB(i)) {
+    mask = IN_CLASSB_NET;
+    subnetshift = 8;
+   } else {
+    mask = IN_CLASSC_NET;
+    subnetshift = 4;
+   }
+   /*
+    * If there are more bits than the standard mask
+    * would suggest, subnets must be in use.
+    * Guess at the subnet mask, assuming reasonable
+    * width subnet fields.
+    */
+   while (in.s_addr &~ mask)
+    mask = (long)mask >> subnetshift;
+   net = in.s_addr & mask;
+   while ((mask & 1) == 0)
+    mask >>= 1, net >>= 1;
+   np = NULL;
+  }
+#define C(x) (unsigned)((x) & 0xff)
+  if (cp)
+   strncpy(line, cp, sizeof(line));
+  else if ((in.s_addr & 0xffffff) == 0)
+   (void) sprintf(line, "%u", C(in.s_addr >> 24));
+  else if ((in.s_addr & 0xffff) == 0)
+   (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
+       C(in.s_addr >> 16));
+  else if ((in.s_addr & 0xff) == 0)
+   (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
+       C(in.s_addr >> 16), C(in.s_addr >> 8));
+  else
+   (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+       C(in.s_addr >> 16), C(in.s_addr >> 8),
+       C(in.s_addr));
+#undef C
+  break;
+     }
+
+#ifdef INET6
+ case AF_INET6:
+ {
+  struct sockaddr_in6 sin6; /* use static var for safety */
+  int niflags = 0;
+
+  memset(&sin6, 0, sizeof(sin6));
+  memcpy(&sin6, sa, sizeof(sin6));
+  sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+  if (/*sa->sa_len == sizeof(struct sockaddr_in6) &&*/
+      (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+       IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+      sin6.sin6_scope_id == 0) {
+   sin6.sin6_scope_id =
+       ntohs(*(USHORT *)&sin6.sin6_addr.s6_addr[2]);
+   sin6.sin6_addr.s6_addr[2] = 0;
+   sin6.sin6_addr.s6_addr[3] = 0;
+  }
+#endif
+  if (nflag)
+   niflags |= NI_NUMERICHOST;
+  if (getnameinfo((struct sockaddr *)&sin6,
+      sizeof(struct sockaddr_in6),
+      line, sizeof(line), NULL, 0, niflags) != 0)
+   strncpy(line, "invalid", sizeof(line));
+
+  return (line);
+ }
+#endif
+
+ default:
+     { u_short *s = (u_short *)sa->sa_data;
+  u_short *slim = s + ((sizeof(struct sockaddr_storage) + 1)>>1);
+  char *cp = line + sprintf(line, "af %d:", sa->sa_family);
+  char *cpe = line + sizeof(line);
+
+  while (s < slim && cp < cpe)
+   if ((n = snprintf(cp, cpe - cp, " %x", *s++)) > 0)
+    cp += n;
+   else
+    *cp = '\0';
+  break;
+     }
+ }
+ return (line);
+}
+
+void
+inet_makenetandmask(net, sin, bits)
+ u_long net, bits;
+ struct sockaddr_in *sin;
+{
+ u_long addr, mask = 0;
+ char *cp;
+
+ rtm_addrs |= RTA_NETMASK;
+ if (net == 0)
+  mask = addr = 0;
+ else if (net < 128) {
+  addr = net << IN_CLASSA_NSHIFT;
+  mask = IN_CLASSA_NET;
+ } else if (net < 65536) {
+  addr = net << IN_CLASSB_NSHIFT;
+  mask = IN_CLASSB_NET;
+ } else if (net < 16777216L) {
+  addr = net << IN_CLASSC_NSHIFT;
+  mask = IN_CLASSC_NET;
+ } else {
+  addr = net;
+  if ((addr & IN_CLASSA_HOST) == 0)
+   mask =  IN_CLASSA_NET;
+  else if ((addr & IN_CLASSB_HOST) == 0)
+   mask =  IN_CLASSB_NET;
+  else if ((addr & IN_CLASSC_HOST) == 0)
+   mask =  IN_CLASSC_NET;
+  else
+   mask = -1;
+ }
+ if (bits)
+  mask = 0xffffffff << (32 - bits);
+ sin->sin_addr.s_addr = htonl(addr);
+ sin = &so_mask.sin;
+ sin->sin_addr.s_addr = htonl(mask);
+ sin->sin_family = 0;
+ cp = (char *)(&sin->sin_addr + 1);
+ while (*--cp == 0 && cp > (char *)sin)
+  ;
+}
+
+#ifdef INET6
+/*
+ * XXX the function may need more improvement...
+ */
+static int
+inet6_makenetandmask(sin6, plen)
+ struct sockaddr_in6 *sin6;
+ char *plen;
+{
+ struct in6_addr in6;
+
+ if (!plen) {
+  if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+      sin6->sin6_scope_id == 0) {
+   plen = "0";
+  } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
+   /* aggregatable global unicast - RFC2374 */
+   memset(&in6, 0, sizeof(in6));
+   if (!memcmp(&sin6->sin6_addr.s6_addr[8],
+        &in6.s6_addr[8], 8))
+    plen = "64";
+  }
+ }
+
+ if (!plen || strcmp(plen, "128") == 0)
+  return 1;
+ rtm_addrs |= RTA_NETMASK;
+ (void)prefixlen(plen);
+ return 0;
+}
+#endif
+
+int
+prefixlen(s)
+ char *s;
+{
+ int len = atoi(s), q, r;
+ int max;
+ char *p;
+
+ rtm_addrs |= RTA_NETMASK;
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+  max = 128;
+  p = (char *)&so_mask.sin6.sin6_addr;
+  break;
+#endif
+ case AF_INET:
+  max = 32;
+  p = (char *)&so_mask.sin.sin_addr;
+  break;
+ default:
+  (void) fprintf(stderr, "prefixlen not supported in this af\n");
+  exit(1);
+  /*NOTREACHED*/
+ }
+
+ if (len < 0 || max < len) {
+  (void) fprintf(stderr, "%s: bad value\n", s);
+  exit(1);
+ }
+
+ q = len >> 3;
+ r = len & 7;
+ so_mask.sa.sa_family = af;
+ memset((void *)p, 0, max / 8);
+ if (q > 0)
+  memset((void *)p, 0xff, q);
+ if (r > 0)
+  *((u_char *)p + q) = (0xff00 >> r) & 0xff;
+ if (len == max)
+  return -1;
+ else
+  return len;
+}
+
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+char *msgtypes[] = {
+ "",
+ "RTM_ADD: Add Route",
+ "RTM_DELETE: Delete Route",
+ "RTM_CHANGE: Change Metrics or flags",
+ "RTM_GET: Report Metrics",
+ "RTM_LOSING: Kernel Suspects Partitioning",
+ "RTM_REDIRECT: Told to use different route",
+ "RTM_MISS: Lookup failed on this address",
+ "RTM_LOCK: fix specified metrics",
+ "RTM_OLDADD: caused by SIOCADDRT",
+ "RTM_OLDDEL: caused by SIOCDELRT",
+ "RTM_RESOLVE: Route created by cloning",
+ "RTM_NEWADDR: address being added to iface",
+ "RTM_DELADDR: address being removed from iface",
+ "RTM_IFINFO: iface status change",
+ "RTM_NEWMADDR: new multicast group membership on iface",
+ "RTM_DELMADDR: multicast group membership removed from iface",
+ "RTM_IFANNOUNCE: interface arrival/departure",
+ 0,
+};
+
+char metricnames[] =
+"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
+"\1mtu";
+char routeflags[] =
+"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
+"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
+"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
+"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
+char ifnetflags[] =
+"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
+"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
+"\017LINK2\020MULTICAST";
+char addrnames[] =
+"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+
+void
+print_rtmsg(rtm, msglen)
+ struct rt_msghdr *rtm;
+ int msglen;
+{
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+#ifdef RTM_NEWMADDR
+ struct ifma_msghdr *ifmam;
+#endif
+ struct if_announcemsghdr *ifan;
+ char *state;
+
+ if (rtm->rtm_version != RTM_VERSION) {
+  (void) printf("routing message version %d not understood\n",
+      rtm->rtm_version);
+  return;
+ }
+ if (msgtypes[rtm->rtm_type] != NULL)
+  (void)printf("%s: ", msgtypes[rtm->rtm_type]);
+ else
+  (void)printf("#%d: ", rtm->rtm_type);
+ (void)printf("len %d, ", rtm->rtm_msglen);
+ switch (rtm->rtm_type) {
+        case RTM_IFINFO:
+                ifm = (struct if_msghdr *)rtm;
+                (void) printf("if# %d, ", ifm->ifm_index);
+                switch (ifm->ifm_data.ifi_link_state) {
+                case LINK_STATE_DOWN:
+                        state = "down";
+                        break;
+                case LINK_STATE_UP:
+                        state = "up";
+                        break;
+                default:
+                        state = "unknown";
+                        break;
+                }
+                (void) printf("link: %s, flags:", state);
+                bprintf(stdout, ifm->ifm_flags, ifnetflags);
+                pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
+                break;
+        case RTM_NEWADDR:
+        case RTM_DELADDR:
+                ifam = (struct ifa_msghdr *)rtm;
+                (void) printf("metric %d, flags:", ifam->ifam_metric);
+                bprintf(stdout, ifam->ifam_flags, routeflags);
+                pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
+                break;
+ case RTM_IFANNOUNCE:
+     ifan = (struct if_announcemsghdr *)rtm;
+     (void) printf("if# %d, what: ", ifan->ifan_index);
+     switch (ifan->ifan_what) {
+     case IFAN_ARRIVAL:
+  printf("arrival");
+  break;
+     case IFAN_DEPARTURE:
+  printf("departure");
+  break;
+     default:
+  printf("#%d", ifan->ifan_what);
+  break;
+     }
+     printf("\n");
+     break;
+
+ default:
+  (void) printf("pid: %ld, seq %d, errno %d, flags:",
+   (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
+  bprintf(stdout, rtm->rtm_flags, routeflags);
+  pmsg_common(rtm);
+ }
+}
+
+void
+print_getmsg(rtm, msglen)
+ struct rt_msghdr *rtm;
+ int msglen;
+{
+ struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ struct sockaddr *sa;
+ char *cp;
+ int i;
+
+ (void) printf("   route to: %s\n", routename(&so_dst));
+ if (rtm->rtm_version != RTM_VERSION) {
+  warnx("routing message version %d not understood",
+       rtm->rtm_version);
+  return;
+ }
+ if (rtm->rtm_msglen > msglen) {
+  warnx("message length mismatch, in packet %d, returned %d",
+        rtm->rtm_msglen, msglen);
+ }
+ if (rtm->rtm_errno)  {
+  errno = rtm->rtm_errno;
+  warn("message indicates error %d", errno);
+  return;
+ }
+ cp = ((char *)(rtm + 1));
+ if (rtm->rtm_addrs)
+  for (i = 1; i; i <<= 1)
+   if (i & rtm->rtm_addrs) {
+    sa = (struct sockaddr *)cp;
+    switch (i) {
+    case RTA_DST:
+     dst = sa;
+     break;
+    case RTA_GATEWAY:
+     gate = sa;
+     break;
+    case RTA_NETMASK:
+     mask = sa;
+     break;
+    case RTA_IFP:
+     break;
+    }
+    cp += SA_SIZE(sa);
+   }
+ if (dst && mask)
+  mask->sa_family = dst->sa_family; /* XXX */
+ if (dst)
+  (void)printf("destination: %s\n", routename(dst));
+ if (mask) {
+  int savenflag = nflag;
+
+  nflag = 1;
+  (void)printf("       mask: %s\n", routename(mask));
+  nflag = savenflag;
+ }
+ if (gate && rtm->rtm_flags & RTF_GATEWAY)
+  (void)printf("    gateway: %s\n", routename(gate));
+ (void)printf("      flags: ");
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+
+#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
+ if (verbose)
+  pmsg_common(rtm);
+ else if (rtm->rtm_addrs &~ RTA_IGN) {
+  (void) printf("sockaddrs: ");
+  bprintf(stdout, rtm->rtm_addrs, addrnames);
+  putchar('\n');
+ }
+#undef RTA_IGN
+}
+
+void
+pmsg_common(rtm)
+ struct rt_msghdr *rtm;
+{
+ (void) printf(" inits: ");
+ bprintf(stdout, rtm->rtm_inits, metricnames);
+ pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
+}
+
+void
+pmsg_addrs(cp, addrs)
+ char *cp;
+ int addrs;
+{
+ struct sockaddr *sa;
+ int i;
+
+ if (addrs == 0) {
+  (void) putchar('\n');
+  return;
+ }
+ (void) printf("\nsockaddrs: ");
+ bprintf(stdout, addrs, addrnames);
+ (void) putchar('\n');
+ for (i = 1; i; i <<= 1)
+  if (i & addrs) {
+   sa = (struct sockaddr *)cp;
+   (void) printf(" %s", routename(sa));
+   cp += SA_SIZE(sa);
+  }
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+void
+bprintf(fp, b, s)
+ FILE *fp;
+ int b;
+ u_char *s;
+{
+ int i;
+ int gotsome = 0;
+
+ if (b == 0)
+  return;
+ while ((i = *s++) != 0) {
+  if (b & (1 << (i-1))) {
+   if (gotsome == 0)
+    i = '<';
+   else
+    i = ',';
+   (void) putc(i, fp);
+   gotsome = 1;
+   for (; (i = *s) > 32; s++)
+    (void) putc(i, fp);
+  } else
+   while (*s > 32)
+    s++;
+ }
+ if (gotsome)
+  (void) putc('>', fp);
+}
+
+void
+sodump(su, which)
+ sup su;
+ char *which;
+{
+ switch (su->sa.sa_family) {
+ case AF_INET:
+  (void) printf("%s: inet %s; ",
+      which, inet_ntoa(su->sin.sin_addr));
+  break;
+ }
+ (void) fflush(stdout);
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/rmapi.c b/xorp/contrib/xorprtm/xorprtm/rmapi.c
new file mode 100644
index 0000000..64d3a16
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/rmapi.c
@@ -0,0 +1,752 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/rmapi.c,v 1.7 2008/10/02 21:56:40 bms Exp $"
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#include "pchsample.h"
+#pragma hdrstop
+
+extern int rtm_ifannounce(LPWSTR ifname, DWORD ifindex, int what);
+extern int rtm_ifinfo(DWORD ifindex, int up);
+#ifdef IPV6_DLL
+extern int rtm_newaddr(DWORD ifindex, PIPV6_ADAPTER_BINDING_INFO pbind);
+#else
+extern int rtm_newaddr(DWORD ifindex, PIP_ADAPTER_BINDING_INFO pbind);
+#endif
+
+DWORD
+WINAPI
+StartProtocol (
+    HANDLE              NotificationEvent,
+    PSUPPORT_FUNCTIONS   SupportFunctions,
+    LPVOID               GlobalInfo,
+    ULONG                StructureVersion,
+    ULONG                StructureSize,
+    ULONG                StructureCount
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE3(ENTER, "Entering StartProtocol 0x%08x 0x%08x 0x%08x",
+           NotificationEvent, SupportFunctions, GlobalInfo);
+
+    do                          /* breakout loop */
+    {
+        /* validate parameters */
+        if (!NotificationEvent || !SupportFunctions  || !GlobalInfo)
+        {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+
+        dwErr = CM_StartProtocol(NotificationEvent,
+                                 SupportFunctions,
+                                 GlobalInfo);
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  StartProtocol: %u", dwErr);
+
+    return dwErr;
+}
+
+DWORD
+WINAPI
+StartComplete (
+    VOID
+    )
+{
+    TRACE0(ENTER, "Entering StartComplete");
+    TRACE0(LEAVE, "Leaving  StartComplete");
+
+    return NO_ERROR;
+}
+
+
+DWORD
+WINAPI
+StopProtocol (
+    VOID
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE0(ENTER, "Entering StopProtocol");
+
+    dwErr = CM_StopProtocol();
+
+    TRACE1(LEAVE, "Leaving  StopProtocol: %u", dwErr);
+
+    return dwErr;
+}
+
+DWORD
+WINAPI
+GetGlobalInfo (
+        PVOID  GlobalInfo,
+    PULONG   BufferSize,
+       PULONG StructureVersion,
+       PULONG   StructureSize,
+       PULONG   StructureCount
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE2(ENTER, "Entering GetGlobalInfo: 0x%08x 0x%08x",
+           GlobalInfo, BufferSize);
+    do
+    {
+        if (!BufferSize) {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+        dwErr = CM_GetGlobalInfo(GlobalInfo,
+                                 BufferSize,
+                                 StructureVersion,
+                                 StructureSize,
+                                 StructureCount);
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  GetGlobalInfo: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+SetGlobalInfo (
+     PVOID  GlobalInfo,
+     ULONG StructureVersion,
+     ULONG   StructureSize,
+     ULONG   StructureCount
+    )
+{
+    TRACE1(ENTER, "Entering SetGlobalInfo: 0x%08x", GlobalInfo);
+    TRACE0(LEAVE, "Leaving  SetGlobalInfo");
+    return NO_ERROR;
+}
+
+DWORD
+WINAPI
+AddInterface (
+    LPWSTR               InterfaceName,
+    ULONG             InterfaceIndex,
+    NET_INTERFACE_TYPE   InterfaceType,
+    DWORD                MediaType,
+    WORD                 AccessType,
+    WORD                 ConnectionType,
+    PVOID             InterfaceInfo,
+    ULONG                StructureVersion,
+    ULONG                StructureSize,
+    ULONG                StructureCount
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE4(ENTER, "Entering AddInterface: %S %u %u 0x%08x",
+           InterfaceName, InterfaceIndex, AccessType, InterfaceInfo);
+
+    rtm_ifannounce(InterfaceName, InterfaceIndex, IFAN_ARRIVAL);
+
+    TRACE1(LEAVE, "Leaving  AddInterface: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+DeleteInterface (
+    ULONG InterfaceIndex
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE1(ENTER, "Entering DeleteInterface: %u", InterfaceIndex);
+
+    rtm_ifannounce(NULL, InterfaceIndex, IFAN_DEPARTURE);
+
+    TRACE1(LEAVE, "Leaving  DeleteInterface: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+InterfaceStatus (
+    ULONG InterfaceIndex,
+    BOOL     InterfaceActive,
+    DWORD    StatusType,
+    PVOID StatusInfo
+    )
+{
+#ifdef IPV6_DLL
+    PIPV6_ADAPTER_BINDING_INFO pbind = NULL;
+#else
+    PIP_ADAPTER_BINDING_INFO pbind = NULL;
+#endif
+    DWORD dwErr = NO_ERROR;
+
+    TRACE4(ENTER, "Entering InterfaceStatus: %u %u %u %p",
+           InterfaceIndex, InterfaceActive, StatusType, StatusInfo);
+    TRACE1(ANY, "interface is %sactive", InterfaceActive ? "" : "in");
+
+    switch (StatusType) {
+    case RIS_INTERFACE_ADDRESS_CHANGE:
+ TRACE0(ANY, "interface address has changed");
+#ifdef IPV6_DLL
+ pbind6 = (PIPV6_ADAPTER_BINDING_INFO) StatusInfo;
+ TRACE1(ANY, "%d addresses associated with this adapter",
+        pbind6->AddressCount);
+#else
+ pbind = (PIP_ADAPTER_BINDING_INFO) StatusInfo;
+ TRACE1(ANY, "%d addresses associated with this adapter",
+        pbind->AddressCount);
+#endif
+#if 0
+ rtm_newaddr(InterfaceIndex, pbind);
+#endif
+ break;
+    case RIS_INTERFACE_ENABLED:
+ TRACE0(ANY, "interface is enabled");
+ break;
+    case RIS_INTERFACE_DISABLED:
+ TRACE0(ANY, "interface is disabled");
+ break;
+    case RIS_INTERFACE_MEDIA_PRESENT:
+    case RIS_INTERFACE_MEDIA_ABSENT:
+ TRACE1(ANY, "interface link is %s",
+        StatusType == RIS_INTERFACE_MEDIA_PRESENT ? "up" : "down");
+ rtm_ifinfo(InterfaceIndex,
+     StatusType == RIS_INTERFACE_MEDIA_PRESENT ? 1 : 0);
+ break;
+    default:
+ TRACE1(ANY, "unknown StatusType", StatusType);
+ break;
+    }
+
+    TRACE1(LEAVE, "Leaving  InterfaceStatus: %u", dwErr);
+
+    return dwErr;
+}
+
+DWORD
+WINAPI
+GetInterfaceConfigInfo (
+         ULONG InterfaceIndex,
+         PVOID   InterfaceInfo,
+     PULONG  BufferSize,
+        PULONG StructureVersion,
+        PULONG StructureSize,
+        PULONG StructureCount
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE3(ENTER, "Entering GetInterfaceConfigInfo: %u 0x%08x 0x%08x",
+           InterfaceIndex, InterfaceInfo, BufferSize);
+    TRACE1(LEAVE, "Leaving  GetInterfaceConfigInfo: %u",
+           dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+SetInterfaceConfigInfo (
+    ULONG InterfaceIndex,
+    PVOID InterfaceInfo,
+    ULONG    StructureVersion,
+    ULONG    StructureSize,
+    ULONG    StructureCount
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE2(ENTER, "Entering SetInterfaceConfigInfo: %u 0x%08x",
+           InterfaceIndex, InterfaceInfo);
+    TRACE1(LEAVE, "Leaving  SetInterfaceConfigInfo: %u", dwErr);
+
+    return dwErr;
+}
+
+/*
+ * This is totally required. The Router Manager calls it to
+ * know when we've stopped.
+ */
+DWORD
+WINAPI
+GetEventMessage (
+    ROUTING_PROTOCOL_EVENTS  *Event,
+    MESSAGE                  *Result
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE2(ENTER, "Entering GetEventMessage: 0x%08x 0x%08x",
+           Event, Result);
+    do
+    {
+        if (!Event || !Result) {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+
+        dwErr = CM_GetEventMessage(Event, Result);
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  GetEventMessage: %u", dwErr);
+
+    return dwErr;
+}
+
+/* Only used for demand dial interfaces; stub. */
+DWORD
+WINAPI
+DoUpdateRoutes (
+    ULONG InterfaceIndex
+    )
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE1(ENTER, "Entering DoUpdateRoutes: %u", InterfaceIndex);
+    TRACE1(LEAVE, "Leaving  DoUpdateRoutes: %u", dwErr);
+
+    return dwErr;
+}
+
+DWORD
+WINAPI
+MibCreate (
+    ULONG  InputDataSize,
+    PVOID  InputData
+    )
+{
+    DWORD dwErr = ERROR_CAN_NOT_COMPLETE;
+
+    TRACE2(ENTER, "Entering MibCreate: %u 0x%08x",
+           InputDataSize, InputData);
+    TRACE1(LEAVE, "Leaving  MibCreate: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+MibDelete (
+    ULONG  InputDataSize,
+    PVOID  InputData
+    )
+{
+    DWORD dwErr = ERROR_CAN_NOT_COMPLETE;
+
+    TRACE2(ENTER, "Entering MibDelete: %u 0x%08x",
+           InputDataSize, InputData);
+    TRACE1(LEAVE, "Leaving  MibDelete: %u", dwErr);
+
+    return dwErr;
+}
+
+
+/* XXX: Not sure if this is really needed */
+DWORD
+WINAPI
+MibSet (
+    ULONG  InputDataSize,
+    PVOID InputData
+    )
+/*++
+
+Routine Description
+    This function sets XORPRTM's global or interface configuration.
+
+Arguments
+    InputData           Relevant input, struct XORPRTM_MIB_SET_INPUT_DATA
+    InputDataSize       Size of the input
+
+Return Value
+    NO_ERROR            success
+    Error Code          o/w
+
+--*/
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE2(ENTER, "Entering MibSet: %u 0x%08x",
+           InputDataSize, InputData);
+
+    do                          /* breakout loop */
+    {
+        /* validate parameters */
+        if ((!InputData) ||
+            (InputDataSize < sizeof(XORPRTM_MIB_SET_INPUT_DATA)))
+        {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+
+        dwErr = MM_MibSet((PXORPRTM_MIB_SET_INPUT_DATA) InputData);
+
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  MibSet: %u", dwErr);
+
+    return dwErr;
+}
+
+
+/* XXX: Not sure if this is really needed */
+
+DWORD
+WINAPI
+MibGet (
+         ULONG InputDataSize,
+         PVOID InputData,
+     PULONG OutputDataSize,
+        PVOID OutputData
+    )
+/*++
+
+Routine Description
+    This function retrieves one of...
+    . global configuration
+    . interface configuration
+    . global stats
+    . interface stats
+    . interface binding
+
+    Called by an admin (SNMP) utility.  It actually passes through the IP
+    Router Manager, but all that does is demux the call to the desired
+    routing protocol.
+
+Arguments
+    InputData           Relevant input, struct XORPRTM_MIB_GET_INPUT_DATA
+    InputDataSize       Size of the input
+    OutputData          Buffer for struct XORPRTM_MIB_GET_OUTPUT_DATA
+    OutputDataSize       size of output buffer received
+                        size of output buffer required
+
+Return Value
+    NO_ERROR            success
+    Error Code          o/w
+
+--*/
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE4(ENTER, "Entering MibGet: %u 0x%08x 0x%08x 0x%08x",
+           InputDataSize, InputData, OutputDataSize, OutputData);
+
+    do                          /* breakout loop */
+    {
+        /* validate parameters */
+        if ((!InputData) ||
+            (InputDataSize < sizeof(XORPRTM_MIB_GET_INPUT_DATA)) ||
+            (!OutputDataSize))
+        {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+
+        dwErr = MM_MibGet((PXORPRTM_MIB_GET_INPUT_DATA) InputData,
+                          (PXORPRTM_MIB_GET_OUTPUT_DATA) OutputData,
+                          OutputDataSize,
+                          GET_EXACT);
+
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  MibGet: %u", dwErr);
+
+    return dwErr;
+}
+
+
+/* XXX: Not sure if this is really needed */
+
+DWORD
+WINAPI
+MibGetFirst (
+         ULONG InputDataSize,
+         PVOID InputData,
+     PULONG  OutputDataSize,
+        PVOID   OutputData
+    )
+/*++
+
+Routine Description
+    This function retrieves one of...
+    . global configuration
+    . interface configuration
+    . global stats
+    . interface stats
+    . interface binding
+
+    It differs from MibGet() in that it always returns the FIRST entry in
+    whichever table is being queried.  There is only one entry in the
+    global configuration and global stats tables, but the interface
+    configuration, interface stats, and interface binding tables are sorted
+    by IP address; this function returns the first entry from these.
+
+Arguments
+    InputData           Relevant input, struct XORPRTM_MIB_GET_INPUT_DATA
+    InputDataSize       Size of the input
+    OutputData          Buffer for struct XORPRTM_MIB_GET_OUTPUT_DATA
+    OutputDataSize       size of output buffer received
+                        size of output buffer required
+
+Return Value
+    NO_ERROR            success
+    Error Code          o/w
+
+--*/
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE4(ENTER, "Entering MibGetFirst: %u 0x%08x 0x%08x 0x%08x",
+           InputDataSize, InputData, OutputDataSize, OutputData);
+
+    do                          /* breakout loop */
+    {
+        /* validate parameters */
+        if ((!InputData) ||
+            (InputDataSize < sizeof(XORPRTM_MIB_GET_INPUT_DATA)) ||
+            (!OutputDataSize))
+        {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+
+        dwErr = MM_MibGet((PXORPRTM_MIB_GET_INPUT_DATA) InputData,
+                          (PXORPRTM_MIB_GET_OUTPUT_DATA) OutputData,
+                          OutputDataSize,
+                          GET_FIRST);
+
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  MibGetFirst: %u", dwErr);
+
+    return dwErr;
+}
+
+
+/* XXX: Not sure if this is really needed */
+
+DWORD
+WINAPI
+MibGetNext (
+         ULONG   InputDataSize,
+         PVOID InputData,
+     PULONG  OutputDataSize,
+        PVOID OutputData
+    )
+/*++
+
+Routine Description
+    This function retrieves one of...
+    . global configuration
+    . interface configuration
+    . global stats
+    . interface stats
+    . interface binding
+
+    It differs from both MibGet() and MibGetFirst() in that it returns the
+    entry AFTER the one specified in the indicated table.  Thus, in the
+    interface configuration, interface stats, and interface binding tables,
+    this function supplies the entry after the one with the input address.
+
+    If there are no more entries in the table being queried we return
+    ERROR_NO_MORE_ITEMS.  Unlike SNMP we don't walk to the next table.
+    This does not take away any functionality since the NT SNMP agent
+    will try the next variable (having ID one greater than the ID passed
+    in) automatically on getting this error.
+
+Arguments
+    InputData           Relevant input, struct XORPRTM_MIB_GET_INPUT_DATA
+    InputDataSize       Size of the input
+    OutputData          Buffer for struct XORPRTM_MIB_GET_OUTPUT_DATA
+    OutputDataSize       size of output buffer received
+                        size of output buffer required
+
+Return Value
+    NO_ERROR            success
+    Error Code          o/w
+
+--*/
+{
+    DWORD                           dwErr   = NO_ERROR;
+
+    TRACE4(ENTER, "Entering MibGetFirst: %u 0x%08x 0x%08x 0x%08x",
+           InputDataSize, InputData, OutputDataSize, OutputData);
+
+    do                          /* breakout loop */
+    {
+        /* validate parameters */
+        if ((!InputData) ||
+            (InputDataSize < sizeof(XORPRTM_MIB_GET_INPUT_DATA)) ||
+            (!OutputDataSize))
+        {
+            dwErr = ERROR_INVALID_PARAMETER;
+            break;
+        }
+
+        dwErr = MM_MibGet((PXORPRTM_MIB_GET_INPUT_DATA) InputData,
+                          (PXORPRTM_MIB_GET_OUTPUT_DATA) OutputData,
+                          OutputDataSize,
+                          GET_NEXT);
+
+    } while(FALSE);
+
+    TRACE1(LEAVE, "Leaving  MibGetNext: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+MibSetTrapInfo (
+     HANDLE  Event,
+     ULONG   InputDataSize,
+     PVOID InputData,
+    PULONG OutputDataSize,
+    PVOID OutputData
+    )
+{
+    DWORD dwErr = ERROR_CAN_NOT_COMPLETE;
+
+    TRACE0(ENTER, "Entering MibSetTrapInfo");
+    TRACE1(LEAVE, "Leaving  MibSetTrapInfo: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+DWORD
+WINAPI
+MibGetTrapInfo (
+     ULONG InputDataSize,
+     PVOID InputData,
+    PULONG  OutputDataSize,
+    PVOID OutputData
+    )
+{
+    DWORD dwErr = ERROR_CAN_NOT_COMPLETE;
+
+    TRACE0(ENTER, "Entering MibGetTrapInfo");
+    TRACE1(LEAVE, "Leaving  MibGetTrapInfo: %u", dwErr);
+
+    return dwErr;
+}
+
+
+
+/*------------------------------------------------------------------------ */
+
+/* This is where the action is. First function called after dll load. */
+
+#define RF_FUNC_FLAGS (RF_ROUTING | RF_ADD_ALL_INTERFACES)
+
+DWORD
+APIENTRY
+RegisterProtocol(
+    PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
+    PMPR_SERVICE_CHARACTERISTICS pServiceChar
+    )
+{
+    DWORD   dwErr = NO_ERROR;
+
+    TRACE0(ENTER, "Entering RegisterProtocol");
+
+    do {
+        if (pRoutingChar->dwProtocolId != XORPRTM_PROTOCOL_ID) {
+            dwErr = ERROR_NOT_SUPPORTED;
+            break;
+        }
+
+
+ TRACE1(CONFIGURATION, "fSupportedFunctionality is: %08lx",
+  pRoutingChar->fSupportedFunctionality);
+
+        if  ((pRoutingChar->fSupportedFunctionality & RF_FUNC_FLAGS) !=
+      RF_FUNC_FLAGS) {
+            dwErr = ERROR_NOT_SUPPORTED;
+            break;
+        }
+
+        pRoutingChar->fSupportedFunctionality = RF_FUNC_FLAGS;
+        pServiceChar->fSupportedFunctionality = 0;
+
+        pRoutingChar->pfnStartProtocol      = StartProtocol;
+        pRoutingChar->pfnStartComplete      = StartComplete;
+        pRoutingChar->pfnStopProtocol       = StopProtocol;
+        pRoutingChar->pfnGetGlobalInfo      = GetGlobalInfo;
+        pRoutingChar->pfnSetGlobalInfo      = SetGlobalInfo;
+        pRoutingChar->pfnQueryPower         = NULL;
+        pRoutingChar->pfnSetPower           = NULL;
+
+        pRoutingChar->pfnAddInterface       = AddInterface;
+        pRoutingChar->pfnDeleteInterface    = DeleteInterface;
+        pRoutingChar->pfnInterfaceStatus    = InterfaceStatus;
+        pRoutingChar->pfnGetInterfaceInfo   = GetInterfaceConfigInfo;
+        pRoutingChar->pfnSetInterfaceInfo   = SetInterfaceConfigInfo;
+
+        pRoutingChar->pfnGetEventMessage    = GetEventMessage;
+
+        pRoutingChar->pfnUpdateRoutes       = DoUpdateRoutes;
+
+        pRoutingChar->pfnConnectClient      = NULL;
+        pRoutingChar->pfnDisconnectClient   = NULL;
+
+        pRoutingChar->pfnGetNeighbors       = NULL;
+        pRoutingChar->pfnGetMfeStatus       = NULL; /* XXX multicast */
+
+        pRoutingChar->pfnMibCreateEntry     = MibCreate;
+        pRoutingChar->pfnMibDeleteEntry     = MibDelete;
+        pRoutingChar->pfnMibGetEntry        = MibGet;
+        pRoutingChar->pfnMibSetEntry        = MibSet;
+        pRoutingChar->pfnMibGetFirstEntry   = MibGetFirst;
+        pRoutingChar->pfnMibGetNextEntry    = MibGetNext;
+        pRoutingChar->pfnMibSetTrapInfo     = MibSetTrapInfo;
+        pRoutingChar->pfnMibGetTrapInfo     = MibGetTrapInfo;
+    } while (FALSE);
+
+    TRACE1(LEAVE, "Leaving RegisterProtocol: %u", dwErr);
+
+    return dwErr;
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/rmapi.h b/xorp/contrib/xorprtm/xorprtm/rmapi.h
new file mode 100644
index 0000000..c8e3ef5
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/rmapi.h
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/rmapi.h,v 1.7 2008/10/02 21:56:40 bms Exp $
+ */
+
+#ifndef _RMAPI_H_
+#define _RMAPI_H_
+
+DWORD
+APIENTRY
+RegisterProtocol(PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
+    PMPR_SERVICE_CHARACTERISTICS pServiceChar);
+
+#endif
diff --git a/xorp/contrib/xorprtm/xorprtm/sync.c b/xorp/contrib/xorprtm/xorprtm/sync.c
new file mode 100644
index 0000000..90747dc
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/sync.c
@@ -0,0 +1,101 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/sync.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#include "pchsample.h"
+#pragma hdrstop
+
+DWORD
+CreateReadWriteLock(PREAD_WRITE_LOCK pRWL)
+{
+
+    pRWL->RWL_ReaderCount = 0;
+
+    __try {
+        InitializeCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+        return GetLastError();
+    }
+
+    pRWL->RWL_ReaderDoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+    if (pRWL->RWL_ReaderDoneEvent != NULL) {
+        return GetLastError();
+    }
+
+    return NO_ERROR;
+}
+
+VOID
+DeleteReadWriteLock(PREAD_WRITE_LOCK pRWL)
+{
+
+    CloseHandle(pRWL->RWL_ReaderDoneEvent);
+    pRWL->RWL_ReaderDoneEvent = NULL;
+    DeleteCriticalSection(&pRWL->RWL_ReadWriteBlock);
+    pRWL->RWL_ReaderCount = 0;
+}
+
+VOID
+AcquireReadLock(PREAD_WRITE_LOCK pRWL)
+{
+
+    EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
+    InterlockedIncrement(&pRWL->RWL_ReaderCount);
+    LeaveCriticalSection(&pRWL->RWL_ReadWriteBlock);
+}
+
+VOID
+ReleaseReadLock(PREAD_WRITE_LOCK pRWL)
+{
+
+    if (InterlockedDecrement(&pRWL->RWL_ReaderCount) < 0) {
+        SetEvent(pRWL->RWL_ReaderDoneEvent);
+    }
+}
+
+VOID
+AcquireWriteLock(PREAD_WRITE_LOCK pRWL)
+{
+
+    EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
+    if (InterlockedDecrement(&pRWL->RWL_ReaderCount) >= 0) {
+        WaitForSingleObject(pRWL->RWL_ReaderDoneEvent, INFINITE);
+    }
+}
+
+VOID
+ReleaseWriteLock(PREAD_WRITE_LOCK pRWL)
+{
+
+    InterlockedIncrement(&pRWL->RWL_ReaderCount);
+    LeaveCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
+}
+
diff --git a/xorp/contrib/xorprtm/xorprtm/sync.h b/xorp/contrib/xorprtm/xorprtm/sync.h
new file mode 100644
index 0000000..706e333
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/sync.h
@@ -0,0 +1,145 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/sync.h,v 1.7 2008/10/02 21:56:41 bms Exp $
+ */
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#ifndef _SYNC_H_
+#define _SYNC_H_
+
+typedef struct _READ_WRITE_LOCK {
+    CRITICAL_SECTION    RWL_ReadWriteBlock;
+    LONG                RWL_ReaderCount;
+    HANDLE              RWL_ReaderDoneEvent;
+} READ_WRITE_LOCK, *PREAD_WRITE_LOCK;
+
+DWORD
+CreateReadWriteLock(
+    PREAD_WRITE_LOCK pRWL);
+
+VOID
+DeleteReadWriteLock(
+    PREAD_WRITE_LOCK pRWL);
+
+VOID
+AcquireReadLock(
+    PREAD_WRITE_LOCK pRWL);
+
+VOID
+ReleaseReadLock(
+    PREAD_WRITE_LOCK pRWL);
+
+VOID
+AcquireWriteLock(
+    PREAD_WRITE_LOCK pRWL);
+
+VOID
+ReleaseWriteLock(
+    PREAD_WRITE_LOCK pRWL);
+
+#define CREATE_READ_WRITE_LOCK(pRWL)                                \
+    CreateReadWriteLock(pRWL)
+#define DELETE_READ_WRITE_LOCK(pRWL)                                \
+    DeleteReadWriteLock(pRWL)
+#define READ_WRITE_LOCK_CREATED(pRWL)                               \
+    ((pRWL)->RWL_ReaderDoneEvent != NULL)
+
+#define ACQUIRE_READ_LOCK(pRWL)                                     \
+    AcquireReadLock(pRWL)
+#define RELEASE_READ_LOCK(pRWL)                                     \
+    ReleaseReadLock(pRWL)
+#define ACQUIRE_WRITE_LOCK(pRWL)                                    \
+    AcquireWriteLock(pRWL)
+#define RELEASE_WRITE_LOCK(pRWL)                                    \
+    ReleaseWriteLock(pRWL)
+
+#define WRITE_LOCK_TO_READ_LOCK(pRWL)                               \
+{                                                                   \
+    ACQUIRE_READ_LOCK(pRWL);                                        \
+    RELEASE_WRITE_LOCK(pRWL);                                       \
+}
+
+
+typedef struct _LOCKED_LIST {
+    CRITICAL_SECTION    lock;
+    LIST_ENTRY          head;
+    DWORD               created;
+} LOCKED_LIST, *PLOCKED_LIST;
+
+#define INITIALIZE_LOCKED_LIST(pLL)                                 \
+{                                                                   \
+    do                                                              \
+    {                                                               \
+        __try {                                                     \
+            InitializeCriticalSection(&((pLL)->lock));              \
+        }                                                           \
+        __except (EXCEPTION_EXECUTE_HANDLER) {                      \
+            break;                                                  \
+        }                                                           \
+        InitializeListHead(&((pLL)->head));                         \
+        (pLL)->created = 0x12345678;                                \
+    } while (FALSE);                                                \
+}
+
+#define LOCKED_LIST_INITIALIZED(pLL)                                \
+     ((pLL)->created == 0x12345678)
+
+#define DELETE_LOCKED_LIST(pLL, FreeFunction)                       \
+{                                                                   \
+     (pLL)->created = 0;                                            \
+     FreeList(&((pLL)->head), FreeFunction);                        \
+     DeleteCriticalSection(&(pLL)->lock);                           \
+}
+
+#define ACQUIRE_LIST_LOCK(pLL)                                      \
+     EnterCriticalSection(&(pLL)->lock)
+
+#define RELEASE_LIST_LOCK(pLL)                                      \
+     LeaveCriticalSection(&(pLL)->lock)
+
+
+
+#define LOCKED_QUEUE    LOCKED_LIST
+#define PLOCKED_QUEUE   PLOCKED_LIST
+
+
+#define INITIALIZE_LOCKED_QUEUE(pLQ)                                \
+     INITIALIZE_LOCKED_LIST(pLQ)
+#define LOCKED_QUEUE_INITIALIZED(pLQ)                               \
+     LOCKED_LIST_INITIALIZED(pLQ)
+#define DELETE_LOCKED_QUEUE(pLQ, FreeFunction)                      \
+     DELETE_LOCKED_LIST(pLQ, FreeFunction)
+#define ACQUIRE_QUEUE_LOCK(pLQ)                                     \
+     ACQUIRE_LIST_LOCK(pLQ)
+#define RELEASE_QUEUE_LOCK(pLQ)                                     \
+     RELEASE_LIST_LOCK(pLQ)
+
+
+#endif
diff --git a/xorp/contrib/xorprtm/xorprtm/test_monitor.c b/xorp/contrib/xorprtm/xorprtm/test_monitor.c
new file mode 100644
index 0000000..3d100f4
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/test_monitor.c
@@ -0,0 +1,98 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/test_monitor.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/*
+ * test pipe client program
+ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bsdroute.h"  /* XXX */
+
+#include "xorprtm.h"
+
+extern void print_rtmsg(struct rt_msghdr *, int); /* XXX client_rtmsg.c */
+
+void
+monitor(void)
+{
+ int n;
+ int result;
+ int wsize;
+ time_t now;
+ HANDLE hPipe;
+ char msg[2048];
+ DWORD dwErr;
+
+ if (!WaitNamedPipeA(XORPRTM_PIPENAME, NMPWAIT_USE_DEFAULT_WAIT)) {
+     fprintf(stderr, "No named pipe instances available.\n");
+     return;
+ }
+
+ hPipe = CreateFileA(XORPRTM_PIPENAME,
+      GENERIC_READ | GENERIC_WRITE, 0, NULL,
+     OPEN_EXISTING, 0, NULL);
+ if (hPipe == INVALID_HANDLE_VALUE) {
+  result = GetLastError();
+  fprintf(stderr, "error opening pipe: %d\n", result);
+  return;
+ }
+
+ fprintf(stderr, "connected\n");
+ /*
+  * Block the thread and read a message at a time, just
+  * like the monitor option of BSD's route(8) command.
+  */
+ for (;;) {
+  dwErr = ReadFile(hPipe, msg, sizeof(msg), &n, NULL);
+  if (dwErr == 0) {
+   fprintf(stderr, "error %d reading from pipe\n",
+       GetLastError());
+   break;
+  }
+  now = time(NULL);
+  (void) fprintf(stderr, "\ngot message of size %d on %s", n,
+      ctime(&now));
+  print_rtmsg((struct rt_msghdr *) msg, n);
+  fflush(stdout);
+ }
+
+ fprintf(stderr, "done\n");
+ CloseHandle(hPipe);
+}
+
+int
+main(int argc, char *argv[])
+{
+ monitor();
+ exit(0);
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/test_routeadd.c b/xorp/contrib/xorprtm/xorprtm/test_routeadd.c
new file mode 100644
index 0000000..29ee842
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/test_routeadd.c
@@ -0,0 +1,126 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/test_routeadd.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/*
+ * test pipe client program
+ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bsdroute.h"  /* XXX */
+
+#include "xorprtm.h"
+
+void
+try_add_route(void)
+{
+ DWORD result;
+ HANDLE h_pipe;
+ struct rt_msghdr *msg;
+ struct sockaddr_storage *pss;
+ struct sockaddr_in *psin;
+ int msgsize;
+ int nbytes;
+ int i;
+
+ if (!WaitNamedPipeA(XORPRTM_PIPENAME, NMPWAIT_USE_DEFAULT_WAIT)) {
+     fprintf(stderr, "No named pipe instances available.\n");
+     return;
+ }
+
+ h_pipe = CreateFileA(XORPRTM_PIPENAME, GENERIC_READ | GENERIC_WRITE,
+       0, NULL, OPEN_EXISTING, 0, NULL);
+ if (h_pipe == INVALID_HANDLE_VALUE) {
+  result = GetLastError();
+  fprintf(stderr, "error opening pipe: %d\n", result);
+  return;
+ }
+
+ fprintf(stderr, "connected\n");
+
+ msgsize = sizeof(*msg) + (sizeof(struct sockaddr_storage) * 3);
+ msg = malloc(msgsize);
+ if (msg == NULL) {
+     fprintf(stderr, "cannot allocate routing socket message\n");
+     CloseHandle(h_pipe);
+     return;
+ }
+
+ ZeroMemory(msg, msgsize);
+
+ /* Fill out routing message header */
+ msg->rtm_type = RTM_ADD;
+        msg->rtm_msglen = msgsize;
+        msg->rtm_version = RTM_VERSION;
+        msg->rtm_addrs |= RTA_DST | RTA_NETMASK | RTA_GATEWAY;
+
+ pss = (struct sockaddr_storage *)(msg + 1);
+
+ /* Fill out destination XXX 192.0.2.0 in little endian */
+ psin = (struct sockaddr_in *)pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x000200C0;
+
+ /* Fill out next-hop XXX 192.168.123.6 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x067BA8C0;
+
+ /* Fill out netmask XXX 255.255.255.0 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x00FFFFFF;
+
+ /* Try to add a route 3 times to test callbacks */
+ for (i = 0; i < 3; i++) {
+     fprintf(stderr, "attempting to add a route\n", GetLastError());
+     result = WriteFile(h_pipe, msg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d writing to pipe\n", GetLastError());
+     } else {
+  fprintf(stderr, "sent message %d\n", i);
+     }
+
+     /* XXX: TODO: Wait for the 'kernel''s reply. */
+ }
+ fprintf(stderr, "done\n");
+
+ CloseHandle(h_pipe);
+ free(msg);
+}
+
+int
+main(int argc, char *argv[])
+{
+ try_add_route();
+ exit(0);
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/test_routeadddelete.c b/xorp/contrib/xorprtm/xorprtm/test_routeadddelete.c
new file mode 100644
index 0000000..c030a9c
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/test_routeadddelete.c
@@ -0,0 +1,199 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/test_routeadddelete.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/*
+ * test pipe client program
+ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bsdroute.h"  /* XXX */
+
+#include "xorprtm.h"
+
+extern void print_rtmsg(struct rt_msghdr *, int);       /* XXX client_rtmsg.c */
+
+void
+try_add_route_with_wait_and_delete(void)
+{
+ DWORD result;
+ HANDLE h_pipe;
+ struct rt_msghdr *msg;
+ struct rt_msghdr *dmsg;
+ struct sockaddr_storage *pss;
+ struct sockaddr_in *psin;
+ int msgsize;
+ int nbytes;
+ int i;
+
+ if (!WaitNamedPipeA(XORPRTM_PIPENAME, NMPWAIT_USE_DEFAULT_WAIT)) {
+     fprintf(stderr, "No named pipe instances available.\n");
+     return;
+ }
+
+ h_pipe = CreateFileA(XORPRTM_PIPENAME, GENERIC_READ | GENERIC_WRITE,
+       0, NULL, OPEN_EXISTING, 0, NULL);
+ if (h_pipe == INVALID_HANDLE_VALUE) {
+  result = GetLastError();
+  fprintf(stderr, "error opening pipe: %d\n", result);
+  return;
+ }
+
+ fprintf(stderr, "connected\n");
+
+ msgsize = sizeof(*msg) + (sizeof(struct sockaddr_storage) * 3);
+ msg = malloc(msgsize);
+ if (msg == NULL) {
+     fprintf(stderr, "cannot allocate routing socket message\n");
+     CloseHandle(h_pipe);
+     return;
+ }
+
+ dmsg = malloc(msgsize);
+ if (dmsg == NULL) {
+     fprintf(stderr, "cannot allocate routing socket message\n");
+     free(msg);
+     CloseHandle(h_pipe);
+     return;
+ }
+
+ ZeroMemory(msg, msgsize);
+
+ /* Fill out routing message header */
+ msg->rtm_type = RTM_ADD;
+        msg->rtm_msglen = msgsize;
+        msg->rtm_version = RTM_VERSION;
+        msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ msg->rtm_pid = GetCurrentProcessId();
+ msg->rtm_seq = 100;
+
+ pss = (struct sockaddr_storage *)(msg + 1);
+
+ /* Fill out destination XXX 192.0.2.0 in little endian */
+ psin = (struct sockaddr_in *)pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x000200C0;
+
+ /* Fill out next-hop XXX 192.168.123.6 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x067BA8C0;
+
+ /* Fill out netmask XXX 255.255.255.0 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x00FFFFFF;
+
+ /* Fill out deletion message header -- a copy with tweaks. */
+ ZeroMemory(dmsg, msgsize);
+ dmsg->rtm_type = RTM_DELETE;
+        dmsg->rtm_msglen = msgsize - sizeof(struct sockaddr_storage);
+        dmsg->rtm_version = RTM_VERSION;
+        dmsg->rtm_addrs = RTA_DST | RTA_NETMASK;
+ dmsg->rtm_pid = GetCurrentProcessId();
+ dmsg->rtm_seq = 100;
+
+ pss = (struct sockaddr_storage *)(dmsg + 1);
+ /* Fill out destination XXX 192.0.2.0 in little endian */
+ psin = (struct sockaddr_in *)pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x000200C0;
+ /* Fill out netmask XXX 255.255.255.0 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x00FFFFFF;
+
+ /* Try to add a route 3 times to test callbacks */
+ i = 0;
+ do {
+     fprintf(stderr, "attempting to add a route\n", GetLastError());
+     result = WriteFile(h_pipe, msg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d writing to pipe\n", GetLastError());
+  break;
+     } else {
+  fprintf(stderr, "sent request %d\n", i);
+  print_rtmsg(msg, nbytes);
+     }
+
+     ZeroMemory(msg, msgsize);
+
+     /* Block and read a single reply. */
+     /* XXX 'msg' is reused twice for reading replies to both
+      * RTM_ADD and RTM_DELTE commands. */
+     result = ReadFile(h_pipe, msg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d reading from pipe\n", GetLastError());
+  break;
+     } else {
+  fprintf(stderr, "got reply %d, printing\n", i);
+  print_rtmsg(msg, nbytes);
+     }
+
+     fprintf(stderr, "sleeping 4 seconds.\n");
+     Sleep(4000);
+
+     fprintf(stderr, "attempting to delete a route\n", GetLastError());
+     result = WriteFile(h_pipe, dmsg, dmsg->rtm_msglen, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d writing to pipe\n", GetLastError());
+  break;
+     } else {
+  fprintf(stderr, "sent request %d\n", i);
+  print_rtmsg(dmsg, nbytes);
+     }
+
+     ZeroMemory(dmsg, msgsize);
+
+     /* Block and read a single reply. */
+     result = ReadFile(h_pipe, dmsg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d reading from pipe\n", GetLastError());
+  break;
+     } else {
+  fprintf(stderr, "got reply %d, printing\n", i);
+  print_rtmsg(dmsg, nbytes);
+     }
+
+ } while (0);
+ fprintf(stderr, "done\n");
+
+ CloseHandle(h_pipe);
+ free(msg);
+}
+
+int
+main(int argc, char *argv[])
+{
+ try_add_route_with_wait_and_delete();
+ exit(0);
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/test_routeaddwait.c b/xorp/contrib/xorprtm/xorprtm/test_routeaddwait.c
new file mode 100644
index 0000000..c90ba29
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/test_routeaddwait.c
@@ -0,0 +1,138 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/test_routeaddwait.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/*
+ * test pipe client program
+ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bsdroute.h"  /* XXX */
+
+#include "xorprtm.h"
+
+extern void print_rtmsg(struct rt_msghdr *, int);       /* XXX client_rtmsg.c */
+
+void
+try_add_route_with_wait(void)
+{
+ DWORD result;
+ HANDLE h_pipe;
+ struct rt_msghdr *msg;
+ struct sockaddr_storage *pss;
+ struct sockaddr_in *psin;
+ int msgsize;
+ int nbytes;
+ int i;
+
+ if (!WaitNamedPipeA(XORPRTM_PIPENAME, NMPWAIT_USE_DEFAULT_WAIT)) {
+     fprintf(stderr, "No named pipe instances available.\n");
+     return;
+ }
+
+ h_pipe = CreateFileA(XORPRTM_PIPENAME, GENERIC_READ | GENERIC_WRITE,
+       0, NULL, OPEN_EXISTING, 0, NULL);
+ if (h_pipe == INVALID_HANDLE_VALUE) {
+  result = GetLastError();
+  fprintf(stderr, "error opening pipe: %d\n", result);
+  return;
+ }
+
+ fprintf(stderr, "connected\n");
+
+ msgsize = sizeof(*msg) + (sizeof(struct sockaddr_storage) * 3);
+ msg = malloc(msgsize);
+ if (msg == NULL) {
+     fprintf(stderr, "cannot allocate routing socket message\n");
+     CloseHandle(h_pipe);
+     return;
+ }
+
+ ZeroMemory(msg, msgsize);
+
+ /* Fill out routing message header */
+ msg->rtm_type = RTM_ADD;
+        msg->rtm_msglen = msgsize;
+        msg->rtm_version = RTM_VERSION;
+        msg->rtm_addrs |= RTA_DST | RTA_NETMASK | RTA_GATEWAY;
+
+ msg->rtm_pid = GetCurrentProcessId();
+
+ pss = (struct sockaddr_storage *)(msg + 1);
+
+ /* Fill out destination XXX 192.0.2.0 in little endian */
+ psin = (struct sockaddr_in *)pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x000200C0;
+
+ /* Fill out next-hop XXX 192.168.123.6 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x067BA8C0;
+
+ /* Fill out netmask XXX 255.255.255.0 in little endian */
+ psin = (struct sockaddr_in *)++pss;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = 0x00FFFFFF;
+
+ /* Try to add a route 3 times to test callbacks */
+ for (i = 0; i < 3; i++) {
+     fprintf(stderr, "attempting to add a route\n", GetLastError());
+     result = WriteFile(h_pipe, msg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d writing to pipe\n", GetLastError());
+     } else {
+  fprintf(stderr, "sent request %d\n", i);
+  print_rtmsg(msg, msgsize);
+     }
+
+     /* Block and read a single reply. */
+     result = ReadFile(h_pipe, msg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  fprintf(stderr, "error %d reading from pipe\n", GetLastError());
+     } else {
+  fprintf(stderr, "got reply %d, printing\n", i);
+  print_rtmsg(msg, msgsize);
+     }
+ }
+ fprintf(stderr, "done\n");
+
+ CloseHandle(h_pipe);
+ free(msg);
+}
+
+int
+main(int argc, char *argv[])
+{
+ try_add_route_with_wait();
+ exit(0);
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/utils.c b/xorp/contrib/xorprtm/xorprtm/utils.c
new file mode 100644
index 0000000..027a3cb
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/utils.c
@@ -0,0 +1,93 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/utils.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#include "pchsample.h"
+#pragma hdrstop
+
+BOOL
+EnterSubsystemAPI()
+{
+    BOOL    bEntered    = FALSE;
+
+    ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    if (g_ce.iscStatus == XORPRTM_STATUS_RUNNING) {
+        /* subsystem is running, so continue */
+        g_ce.ulActivityCount++;
+        bEntered = TRUE;
+    }
+
+    RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    return bEntered;
+}
+
+BOOL
+EnterSubsystemWorker()
+{
+    BOOL    bEntered    = FALSE;
+
+    ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    do {
+        /* subsystem is running, so the function may continue */
+        if (g_ce.iscStatus == XORPRTM_STATUS_RUNNING) {
+            bEntered = TRUE;
+            break;
+        }
+
+        /* subsystem is not running, but it was, so the function must stop */
+        if (g_ce.iscStatus == XORPRTM_STATUS_STOPPING) {
+            g_ce.ulActivityCount--;
+            ReleaseSemaphore(g_ce.hActivitySemaphore, 1, NULL);
+            break;
+        }
+
+        /* subsystem probably never started. quit. */
+    } while (FALSE);
+
+    RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    return bEntered;
+}
+
+VOID
+LeaveSubsystemWorker()
+{
+    ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    g_ce.ulActivityCount--;
+    if (g_ce.iscStatus == XORPRTM_STATUS_STOPPING) {
+        ReleaseSemaphore(g_ce.hActivitySemaphore, 1, NULL);
+    }
+
+    RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/utils.h b/xorp/contrib/xorprtm/xorprtm/utils.h
new file mode 100644
index 0000000..d3a7f9e
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/utils.h
@@ -0,0 +1,41 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/utils.h,v 1.7 2008/10/02 21:56:41 bms Exp $
+ */
+
+/*
+ * This file is derived from code which is under the following copyright:
+ *
+ * Copyright (c) 1999 - 2000 Microsoft Corporation.
+ *
+ */
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+BOOL EnterSubsystemAPI();
+BOOL EnterSubsystemWorker();
+VOID LeaveSubsystemWorker();
+
+#endif
diff --git a/xorp/contrib/xorprtm/xorprtm/xorprtm.c b/xorp/contrib/xorprtm/xorprtm/xorprtm.c
new file mode 100644
index 0000000..40112e0
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/xorprtm.c
@@ -0,0 +1,1905 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+#ident "$XORP: xorp/contrib/win32/xorprtm/xorprtm.c,v 1.7 2008/10/02 21:56:41 bms Exp $"
+
+/* XXX: SORT FUNCTIONS IN THIS FILE */
+
+/* XXX: RATIONALIZE INCLUDES */
+
+#include "pchsample.h"
+#include <iphlpapi.h>
+#pragma hdrstop
+
+/* XXX: move to headers */
+typedef union _sockunion_t {
+    struct sockaddr     sa;
+    struct sockaddr_in     sin;
+    struct sockaddr_in6     sin6;
+    struct sockaddr_storage ss;
+} sockunion_t;
+
+/* XXX: move to headers */
+#define XORPRTM_PIPETIMEOUT 2000 /* 2 seconds */
+#define XORPRTM_RI_PREF     1
+#define XORPRTM_RI_METRIC   20
+
+/* XXX: run cproto */
+/* XXX: move to headers */
+pipe_instance_t *pipe_new(void);
+void pipe_destroy(pipe_instance_t *pp);
+int pipe_listen(pipe_instance_t *pp);
+void pipe_disconnect(pipe_instance_t *pp);
+void CALLBACK pipe_connect_cb(PVOID lpParameter, BOOLEAN TimerOrWaitFired);
+void CALLBACK pipe_read_cb(PVOID lpParameter, BOOLEAN TimerOrWaitFired);
+void WINAPI pipe_reread_cb(void *ctx);
+void WINAPI pipe_relisten_cb(void *ctx);
+DWORD APIENTRY RTM_CallbackEvent (RTM_ENTITY_HANDLE hRtmHandle, RTM_EVENT_TYPE   retEvent, PVOID pvContext1, PVOID 
pvContext2);
+int rtm_add_route(struct rt_msghdr *rtm, int msgsize);
+void broadcast_pipe_message(void *msg, int msgsize);
+
+/*
+ * XXX: The only global variable.
+ */
+/* XXX: move to headers */
+CONFIGURATION_ENTRY g_ce;
+
+/*
+ * Issue a routing socket message for a single changed destination.
+ */
+DWORD
+rtm_send_dest_change(RTM_ENTITY_HANDLE reh, PRTM_DEST_INFO prdi)
+{
+#ifdef IPV6_DLL
+    struct in6_addr dst;
+    struct in6_addr ip;
+    struct in6_addr nhip;
+#else
+    struct in_addr dst;
+    struct in_addr ip;
+    struct in_addr nhip;
+#endif
+    int i;
+    int dstprefix;
+    int nhprefix;
+    int type;
+    DWORD result;
+
+    if (!prdi)
+        return NO_ERROR;
+
+    TRACE1(NETWORK, "RtmDestInfo Destination %p", prdi);
+
+#ifdef IPV6_DLL
+    RTM_IPV6_GET_ADDR_AND_LEN(dst.s6_addr, dstprefix, &prdi->DestAddress);
+#else
+    RTM_IPV4_GET_ADDR_AND_LEN(dst.s_addr, dstprefix, &prdi->DestAddress);
+#endif
+
+    /*
+     * Determine the nature of the change; whether a route has
+     * been added, changed or deleted for the given situation.
+     * We look only at the unicast routing view.
+     */
+    for (i = 0; i < prdi->NumberOfViews; i++) {
+     if (prdi->ViewInfo[i].ViewId == RTM_VIEW_ID_UCAST) {
+#ifdef IPV6_DLL
+     /*
+      * XXX: Don't filter IPv6 routes [yet].
+      */
+#else /* IPv4 */
+     /*
+      * Ignore routes to the all-ones broadcast destination.
+      */
+     if ((dst.s_addr == INADDR_BROADCAST && dstprefix == 32)) {
+  TRACE0(NETWORK, "ignoring all-ones broadcast");
+  break;
+     }
+#ifdef notyet
+     /*
+      * XXX: Ignore multicast routes (for now).
+      */
+     if (IN4_IS_ADDR_MULTICAST(dst.s_addr)) {
+  TRACE0(NETWORK, "ignoring multicast route");
+  break;
+     }
+#endif /* notyet */
+#endif /* IPV6_DLL */
+     if (prdi->ViewInfo[i].NumRoutes == 0) {
+  TRACE0(NETWORK, "route deleted");
+   type = RTM_DELETE;
+     } else if (prdi->ViewInfo[i].NumRoutes == 1) {
+  TRACE0(NETWORK, "route added");
+   type = RTM_ADD;
+     } else {
+  /*
+   * XXX: The route has multiple next-hops. We do not know
+   * which next-hop we should send to the FEA, so do not
+   * process such changes for now.
+   */
+  TRACE1(NETWORK, "route change, dest %d nexthops, no msg",
+   prdi->ViewInfo[i].NumRoutes);
+  type = 0;
+     }
+     break;  /* stop when unicast route view is dealt with. */
+ }
+    }
+    /*
+     * Craft a routing socket message based on the changes.
+     * We only allocate memory here if we require it.
+     */
+    if (type != 0) {
+ sockunion_t *sa;
+ struct rt_msghdr *rtm;
+#ifdef IPV6_DLL
+ struct in6_addr nh;
+#else
+ struct in_addr nh;
+#endif
+ int maxmsgsize;
+
+ maxmsgsize = sizeof(struct rt_msghdr) + (sizeof(sockunion_t) * 3);
+ rtm = malloc(maxmsgsize);
+ ZeroMemory(rtm, maxmsgsize);
+
+ sa = (sockunion_t *)(rtm + 1);
+
+  rtm->rtm_msglen = maxmsgsize - sizeof(*sa);
+  rtm->rtm_version = RTM_VERSION;
+  rtm->rtm_type = type;
+  rtm->rtm_addrs = RTA_DST | RTA_NETMASK;
+
+ /* Destination */
+#ifdef IPV6_DLL
+ sa->sin6.sin6_family = AF_INET6;
+ sa->sin6.sin6_addr = dst;
+#else
+ sa->sin.sin_family = AF_INET;
+ sa->sin.sin_addr = dst;
+#endif
+
+ /*
+  * Route additions require that we also report the next-hop.
+  * Perform the necessary RTMv2 incantations to look up the
+  * next-hop from the destination reported as changed.
+  * XXX: Better error checking here considered desirable.
+  */
+ if (type == RTM_ADD) {
+     PRTM_ROUTE_INFO prri;
+     RTM_NEXTHOP_INFO nhi;
+
+     rtm->rtm_msglen += sizeof(*sa);
+     rtm->rtm_addrs |= RTA_GATEWAY;
+
+     /* XXX weird heap malloc. */
+     MALLOC(&prri,
+RTM_SIZE_OF_ROUTE_INFO(g_ce.rrpRtmProfile.MaxNextHopsInRoute), &result);
+
+     result = RtmGetRouteInfo(reh, prdi->ViewInfo[i].Route, prri, NULL);
+     if (result != NO_ERROR) {
+  TRACE1(NETWORK, "RtmGetRouteInfo() returns %d", result);
+     }
+
+     result = RtmGetNextHopInfo(reh, prri->NextHopsList.NextHops[0],
+           &nhi);
+     if (result != NO_ERROR) {
+  TRACE1(ANY, "Error %u getting next hop", result);
+     }
+
+     /* Gateway */
+#ifdef IPV6_DLL
+     RTM_IPV6_GET_ADDR_AND_LEN(nhip.s6_addr, nhprefix,
+          &nhi.NextHopAddress);
+     ++sa;
+     sa->sin6.sin6_family = AF_INET6;
+     sa->sin6.sin6_addr = nhip;
+#else
+     RTM_IPV4_GET_ADDR_AND_LEN(nhip.s_addr, nhprefix,
+          &nhi.NextHopAddress);
+     ++sa;
+     sa->sin.sin_family = AF_INET;
+     sa->sin.sin_addr = nhip;
+#endif /* IPV6_DLL */
+
+     /*
+      * Free the next-hop info structures.
+      */
+     (void)RtmReleaseNextHopInfo(reh, &nhi);
+     (void)RtmReleaseRouteInfo(reh, prri);
+     FREE(prri);
+ }
+
+ /* Netmask; comes after gateway in the RTM_ADD case. */
+ ++sa;
+#ifdef IPV6_DLL
+ /* XXX: may not be right */
+ sa->sin6.sin6_family = AF_INET;
+ sa->sin6.sin6_addr.s6_addr = RTM_IPV6_MASK_FROM_LEN(dstprefix);
+#else
+ sa->sin.sin_family = AF_INET;
+ sa->sin.sin_addr.s_addr = RTM_IPV4_MASK_FROM_LEN(dstprefix);
+#endif
+
+ broadcast_pipe_message(rtm, rtm->rtm_msglen);
+ free(rtm);
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Send a message to all connected listeners.
+ *
+ * XXX: The write blocks the current thread. Because RRAS threads
+ * never enter alertable wait state, we can't use WriteFileEx().
+ * We must either block or do the additional accounting for overlapped
+ * WriteFile().
+ * This has a very important consequence: our thread blocks until the
+ * client thread reads its data or the pipe is disconnected.
+ */
+void
+broadcast_pipe_message(void *msg, int msgsize)
+{
+    pipe_instance_t *pp;
+    int i;
+    int result;
+    int nbytes;
+
+    for (i = 0; i < PIPE_INSTANCES; i++) {
+ pp = g_ce.pipes[i];
+ if (pp != NULL && pp->state == PIPE_STATE_CONNECTED) {
+     result = WriteFile(pp->pipe, msg, msgsize, &nbytes, NULL);
+     if (result == 0) {
+  result = GetLastError();
+  TRACE1(NETWORK, "broadcast: write error %d", result);
+  if (result == ERROR_PIPE_NOT_CONNECTED ||
+      result == ERROR_NO_DATA ||
+      result == ERROR_BROKEN_PIPE) {
+      TRACE1(NETWORK,
+"broadcast: pipe %p disconnected; reconnecting.", pp->pipe);
+      /*
+       * We may be called by a reader thread. To avoid
+       * introducing loops, we schedule the listen
+       * operation on another thread.
+       */
+      ResetEvent(pp->revent);
+      QueueUserWorkItem(
+(LPTHREAD_START_ROUTINE)pipe_relisten_cb, (PVOID)pp, WT_EXECUTEINIOTHREAD);
+  }
+     }
+ }
+    }
+}
+
+
+DWORD
+ProcessRouteChange (VOID)
+{
+    DWORD           dwErr           = NO_ERROR;
+    RTM_DEST_INFO   rdiDestination;             /* 1 view registered for change */
+    BOOL            bDone           = FALSE;
+    UINT            uiNumDests;
+
+    if (!ENTER_XORPRTM_API()) { return ERROR_CAN_NOT_COMPLETE; }
+
+    /* loop dequeueing messages until RTM says there are no more left */
+    while (!bDone)
+    {
+        /* retrieve route changes */
+        uiNumDests = 1;
+        dwErr = RtmGetChangedDests(
+            g_ce.hRtmHandle,                    /* my RTMv2 handle  */
+            g_ce.hRtmNotificationHandle,        /* my notification handle  */
+            &uiNumDests,                        /*   # dest info's required */
+                                                /* g # dest info's supplied */
+            &rdiDestination);                   /* g buffer for dest info's */
+
+        switch (dwErr)
+        {
+            case ERROR_NO_MORE_ITEMS:
+                bDone = TRUE;
+                dwErr = NO_ERROR;
+                if (uiNumDests < 1)
+                    break;
+                /* else continue below to process the last destination */
+
+/* XXX: Does not specify what the change(s) are, just that they */
+/* occurred, on *this destination*. maybe we should figure */
+/* this out? */
+
+            case NO_ERROR:
+                rtm_send_dest_change(g_ce.hRtmHandle, &rdiDestination);
+
+                /* release the destination info */
+                if (RtmReleaseChangedDests(
+                    g_ce.hRtmHandle,            /* my RTMv2 handle  */
+                    g_ce.hRtmNotificationHandle,/* my notif handle  */
+                    uiNumDests,                 /* 1 */
+                    &rdiDestination             /* released dest info */
+                    ) != NO_ERROR)
+                    TRACE0(NETWORK, "Error releasing changed dests");
+
+                break;
+
+            default:
+                bDone = TRUE;
+                TRACE1(NETWORK, "Error %u RtmGetChangedDests", dwErr);
+                break;
+        }
+    } /* while  */
+
+    LEAVE_XORPRTM_API();
+
+    return dwErr;
+}
+
+
+/*
+ * Where we get called by RTMv2 when things happen to the routing table.
+ */
+DWORD
+APIENTRY
+RTM_CallbackEvent (
+     RTM_ENTITY_HANDLE   hRtmHandle, /* registration handle */
+     RTM_EVENT_TYPE      retEvent,
+     PVOID               pvContext1,
+     PVOID               pvContext2)
+{
+    DWORD dwErr = NO_ERROR;
+
+    TRACE1(ENTER, "Entering RTM_CallbackEvent: %u", retEvent);
+
+    do                          /* breakout loop */
+    {
+        UNREFERENCED_PARAMETER(hRtmHandle);
+        UNREFERENCED_PARAMETER(pvContext1);
+        UNREFERENCED_PARAMETER(pvContext2);
+
+        /* only route change notifications are processed */
+        if (retEvent != RTM_CHANGE_NOTIFICATION)
+        {
+            dwErr = ERROR_NOT_SUPPORTED;
+            break;
+        }
+
+        dwErr = ProcessRouteChange();
+    } while (FALSE);
+
+    TRACE0(LEAVE, "Leaving  RTM_CallbackEvent");
+
+    return dwErr;
+}
+
+
+/*
+ * Create a new instance of a pipe and return a pointer to
+ * its instance structure.
+ */
+pipe_instance_t *
+pipe_new(void)
+{
+    pipe_instance_t *npp;
+    int failed;
+    DWORD result;
+
+    TRACE0(ENTER, "Entering pipe_new");
+
+    npp = malloc(sizeof(*npp));
+    if (npp == NULL)
+ return NULL;
+    ZeroMemory(npp, sizeof(*npp));
+
+    failed = 1;
+
+    /* XXX buffer management */
+    npp->rsize = PIPE_READBUF_SIZE;
+    npp->state = PIPE_STATE_INIT;
+
+    InitializeCriticalSection(&npp->rcs);
+
+    /*
+     * Create the event object used to signal connection completion.
+     */
+    npp->cevent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (npp->cevent == NULL) {
+ result = GetLastError();
+        TRACE1(CONFIGURATION, "Error %u creating event", result);
+ goto fail;
+    }
+    npp->cov.hEvent = npp->cevent;
+
+    /*
+     * Create the event object used to signal read completion.
+     */
+    npp->revent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (npp->revent == NULL) {
+ result = GetLastError();
+        TRACE1(CONFIGURATION, "Error %u creating event", result);
+ goto fail;
+    }
+    npp->rov.hEvent = npp->revent;
+
+    /*
+     * Create the instance of the named pipe itself.
+     */
+    npp->pipe = CreateNamedPipeA(XORPRTM_PIPENAME,
+     PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+     PIPE_TYPE_MESSAGE, PIPE_INSTANCES, 0, 0,
+     XORPRTM_PIPETIMEOUT, NULL);
+    if (npp->pipe == NULL) {
+ result = GetLastError();
+ TRACE1(CONFIGURATION, "Error %u creating named pipe", result);
+ goto fail;
+    }
+
+    failed = 0;
+fail:
+    if (failed) {
+ pipe_destroy(npp);
+ npp = NULL;
+    }
+    TRACE1(ENTER, "Leaving pipe_new %p", npp);
+    return (npp);
+}
+
+/*
+ * XXX: This must be called from primary thread, or lock held if not!
+ */
+int
+pipe_listen(pipe_instance_t *pp)
+{
+    int retval;
+    DWORD result;
+
+    retval = -1;
+
+    TRACE1(ENTER, "Entering pipe_listen %p", pp);
+
+    if (pp == NULL || pp->state != PIPE_STATE_INIT)
+ return (retval);
+
+    /*
+     * Register a pool thread to wait for pipe connection.
+     * Clear event state to avoid spurious signals.
+     */
+    ResetEvent(pp->cevent);
+    result = RegisterWaitForSingleObject(&(pp->cwait), pp->cevent,
+      pipe_connect_cb, pp, INFINITE,
+      WT_EXECUTEINIOTHREAD |
+      WT_EXECUTEONLYONCE);
+    if (result == 0) {
+ result = GetLastError();
+ TRACE1(CONFIGURATION, "Error %u RegisterWaitForSingleObject()", result);
+ goto fail;
+    }
+
+    /*
+     * Register a pool thread to wait for data to be received on the pipe.
+     * We don't cause this to be activated until we post a read request
+     * from within the connection callback.
+     * XXX: We want the read callback to be called whenever the
+     * object is signalled, not just once.
+     */
+    ResetEvent(pp->revent);
+    result = RegisterWaitForSingleObject(&(pp->rwait), pp->revent,
+      pipe_read_cb, pp, INFINITE,
+      WT_EXECUTEINIOTHREAD |
+      WT_EXECUTEONLYONCE);
+    if (result == 0) {
+ result = GetLastError();
+ TRACE1(CONFIGURATION, "Error %u RegisterWaitForSingleObject()", result);
+ goto fail;
+    }
+
+    /*
+     * Post the connection request. If it returns non-zero, then the
+     * connection attempt is pending and the thread will be signalled
+     * when complete. If it returns zero, then there's a problem.
+     * ERROR_NO_DATA means the client disconnected, but we didn't
+     * call DisconnectNamedPipe().
+     * ConnectNamedPipe() does not reset the event object associated
+     * with the OVERLAPPED parameter.
+     */
+    result = ConnectNamedPipe(pp->pipe, &pp->cov);
+    if (result == 0) {
+ result = GetLastError();
+ if (result == ERROR_PIPE_LISTENING) {
+     TRACE0(NETWORK, "Error: listening; Reconnecting named pipe");
+     result = ConnectNamedPipe(pp->pipe, &pp->cov);
+ }
+ if (result == ERROR_PIPE_CONNECTED) {
+     TRACE0(NETWORK, "Error: named pipe already connected");
+     goto fail;
+ }
+ if (result == ERROR_NO_DATA) {
+     TRACE0(NETWORK, "Error: previous session not cleaned up");
+     goto fail;
+ }
+    }
+
+    pp->state = PIPE_STATE_LISTEN;
+
+    retval = 0;
+fail:
+    if (retval == -1) {
+ if (pp->cwait != NULL) {
+     UnregisterWaitEx(pp->cwait, pp->cevent);
+     ResetEvent(pp->cevent);
+     pp->cwait = NULL;
+ }
+ if (pp->rwait != NULL) {
+     UnregisterWaitEx(pp->rwait, pp->revent);
+     ResetEvent(pp->revent);
+     pp->rwait = NULL;
+ }
+    }
+    TRACE1(ENTER, "Leaving pipe_listen", pp);
+    return (retval);
+}
+
+/*
+ * Disconnect, but do not close, a pipe handle; and deregister
+ * any pending waiter threads from its event handles.
+ *
+ * XXX: This must be called from primary thread, or lock held if not!
+ */
+void
+pipe_disconnect(pipe_instance_t *pp)
+{
+
+    TRACE0(ENTER, "Entering pipe_disconnect");
+
+    if (pp == NULL)
+ return;
+    /*
+     * Cancel pending I/O before deregistering the callback,
+     * and disconnect the pipe, to avoid race conditions.
+     * We also reset the event(s) to avoid being signalled for
+     * things which haven't actually happened yet.
+     *
+     * XXX: To avoid races during shutdown, we may have to
+     * NULL out the second argument to UnregisterWaitEx().
+     * We can't, however, do that from a service thread.
+     */
+    if (pp->cwait != NULL) {
+        UnregisterWaitEx(pp->cwait, pp->cevent);
+ ResetEvent(pp->cevent);
+ pp->cwait = NULL;
+    }
+    if (pp->rwait != NULL) {
+        UnregisterWaitEx(pp->rwait, pp->revent);
+ ResetEvent(pp->revent);
+ pp->rwait = NULL;
+    }
+
+    if (pp->pipe != NULL) {
+        CancelIo(pp->pipe);
+ if (pp->state == PIPE_STATE_CONNECTED ||
+     pp->state == PIPE_STATE_LISTEN) {
+     DisconnectNamedPipe(pp->pipe);
+ }
+    }
+
+    pp->state = PIPE_STATE_INIT;
+
+    TRACE0(ENTER, "Leaving pipe_disconnect");
+}
+
+void
+pipe_destroy(pipe_instance_t *pp)
+{
+
+    TRACE0(ENTER, "Leaving pipe_destroy");
+
+    if (pp == NULL)
+ return;
+
+    pipe_disconnect(pp);
+
+    if (pp->revent != NULL) {
+ CloseHandle(pp->revent);
+ pp->rov.hEvent = pp->revent = NULL;
+    }
+    if (pp->cevent != NULL) {
+ CloseHandle(pp->cevent);
+ pp->cov.hEvent = pp->cevent = NULL;
+    }
+    if (pp->pipe != NULL) {
+ CloseHandle(pp->pipe);
+ pp->pipe = NULL;
+    }
+
+    DeleteCriticalSection(&pp->rcs);
+
+    free(pp);
+
+    TRACE0(ENTER, "Leaving pipe_destroy");
+}
+
+void CALLBACK
+pipe_connect_cb(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
+{
+    pipe_instance_t *pp;
+    DWORD result;
+    DWORD nbytes;
+
+    pp = (pipe_instance_t *)lpParameter;
+    EnterCriticalSection(&pp->rcs);
+    TRACE1(ENTER, "Entering pipe_connect_cb %p", lpParameter);
+
+    /* XXX CHECK STATE */
+
+    if (pp->state != PIPE_STATE_LISTEN) {
+ TRACE0(NETWORK, "WARNING: pipe state is not LISTEN");
+    }
+
+    /*
+     * If you forgot to reset the event object, the following call
+     * will block until the connection is actually made. We wish to
+     * run as lockless as possible, so do not block the service thread.
+     */
+    /*
+    result = GetOverlappedResult(pp->pipe, &pp->cov, &nbytes, TRUE);
+    */
+
+    pp->state = PIPE_STATE_CONNECTED;
+
+    /*
+     * Post an overlapped read request to capture a message from
+     * the client.
+     */
+    result = ReadFile(pp->pipe, pp->rbuf, pp->rsize, NULL, &pp->rov);
+    if (result == 0) {
+ result = GetLastError();
+ if (result != ERROR_IO_PENDING) {
+     TRACE1(ANY, "WARNING: pipe_connect_cb read returned %d", result);
+ }
+    }
+
+    /* XXX: We need to be able to deal with errors immediately to
+     * avoid races. */
+    TRACE0(ENTER, "Leaving pipe_connect_cb");
+    LeaveCriticalSection(&pp->rcs);
+}
+
+/*
+ * Callback which invokes pipe_listen().
+ *
+ * When we are in pipe_read_cb(), we may try to call pipe_listen()
+ * (after tearing down an old connection). This can cause an infinite
+ * loop as they execute in the same helper thread, and pipe_listen()
+ * will try to reschedule pipe_read_cb().
+ * Therefore, use QueueUserWorkItem() to make sure that pipe_listen()
+ * is invoked after a context switch.
+ */
+void WINAPI
+pipe_relisten_cb(void *ctx)
+{
+    pipe_instance_t *pp;
+
+    pp = (pipe_instance_t *)ctx;
+    EnterCriticalSection(&pp->rcs);
+    TRACE1(ENTER, "Entering pipe_relisten_cb %p", ctx);
+
+    pipe_disconnect(pp);
+    pipe_listen(pp);
+
+    TRACE0(ENTER, "Leaving pipe_relisten_cb");
+    LeaveCriticalSection(&pp->rcs);
+}
+
+void WINAPI
+pipe_reread_cb(void *ctx)
+{
+    pipe_instance_t *pp;
+    DWORD result;
+    int failed;
+
+    pp = (pipe_instance_t *)ctx;
+    EnterCriticalSection(&pp->rcs);
+    TRACE1(ENTER, "Entering pipe_reread_cb %p", ctx);
+
+    failed = 0;
+
+    if (pp->state != PIPE_STATE_CONNECTED) {
+ TRACE0(NETWORK, "WARNING: not PIPE_STATE_CONNECTED");
+    }
+
+    /*
+     * Tear down and wire up read thread callback again.
+     * This is probably inefficient.
+     */
+    UnregisterWaitEx(pp->rwait, pp->revent);
+    ResetEvent(pp->revent); /* XXX ReadFile() should do this for us? */
+    pp->rwait = NULL;
+    /*
+     * Post a new read request. Deal with fatal errors.
+     */
+    result = ReadFile(pp->pipe, pp->rbuf, pp->rsize, NULL, &pp->rov);
+    if (result == 0) {
+ result = GetLastError();
+ if (result != ERROR_IO_PENDING) {
+     TRACE1(ANY, "WARNING: pipe_reread_cb read returned %d", result);
+ }
+ if (result == ERROR_BROKEN_PIPE) {
+     failed = 1;
+     goto fail;
+ }
+    }
+    /*
+     * Now, and only now, do we kick off the read thread, in order
+     * to avoid being preempted if the client disconnects.
+     */
+    result = RegisterWaitForSingleObject(&(pp->rwait), pp->revent,
+      pipe_read_cb, pp, INFINITE,
+      WT_EXECUTEINIOTHREAD |
+      WT_EXECUTEONLYONCE);
+    if (result == 0) {
+ result = GetLastError();
+ TRACE1(CONFIGURATION, "Error %u RegisterWaitForSingleObject()", result);
+ failed = 1;
+    }
+
+fail:
+    /*
+     * If a fatal error occurred, disconnect the pipe client, and
+     * listen for a new connection on this instance.
+     */
+    if (failed) {
+ ResetEvent(pp->revent);
+ QueueUserWorkItem(
+(LPTHREAD_START_ROUTINE)pipe_relisten_cb, (PVOID)pp, WT_EXECUTEINIOTHREAD);
+    }
+out:
+    TRACE0(ENTER, "Leaving pipe_reread_cb");
+    LeaveCriticalSection(&pp->rcs);
+}
+
+void CALLBACK
+pipe_read_cb(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
+{
+    struct rt_msghdr *rtm;
+    pipe_instance_t *pp;
+    DWORD result;
+    DWORD nbytes;
+
+    pp = (pipe_instance_t *)lpParameter;
+    EnterCriticalSection(&pp->rcs);
+    TRACE1(ENTER, "Entering pipe_read_cb %p", lpParameter);
+
+    if (pp->state != PIPE_STATE_CONNECTED) {
+ TRACE0(NETWORK, "WARNING: not PIPE_STATE_CONNECTED, bailing.");
+ /*
+  * XXX: Is something racy, or is it just me?
+  * Try to avoid deadlocking by returning if we
+  * got called when we weren't connected.
+  */
+ goto out;
+    }
+
+    result = GetOverlappedResult(pp->pipe, &pp->rov, &nbytes, TRUE);
+    if (result == 0) {
+ result = GetLastError();
+ TRACE1(NETWORK, "WARNING: pipe_read_cb read returned %d", result);
+ if (result == ERROR_BROKEN_PIPE) {
+     /*
+      * We must queue the new listen on a separate thread to
+      * avoid infinite recursion.
+      */
+     TRACE0(NETWORK, "Posting listen again.");
+     ResetEvent(pp->revent);
+     QueueUserWorkItem(
+(LPTHREAD_START_ROUTINE)pipe_relisten_cb, (PVOID)pp, WT_EXECUTEINIOTHREAD);
+     goto out;
+ }
+    }
+
+    TRACE1(NETWORK, "Read %d bytes from named pipe.", nbytes);
+
+    /*
+     * Perform sanity checks on input message.
+     * XXX: We should use a more appropriate errno value.
+     * We use -1 as ENOBUFS, etc are not part of the namespace.
+     */
+    rtm = (struct rt_msghdr *)&pp->rbuf[0];
+    if (rtm->rtm_version != RTM_VERSION) {
+ TRACE1(NETWORK, "Invalid rtm_version %d, dropping.", rtm->rtm_version);
+ goto drop;
+    }
+    /*
+     * Sanity check size.
+     */
+    if (rtm->rtm_msglen > nbytes ||
+ nbytes < sizeof(struct rt_msghdr)) {
+ TRACE1(NETWORK, "Invalid rtm_msglen %d, dropping.", rtm->rtm_msglen);
+ rtm->rtm_errno = -1;
+ goto drop;
+    }
+    if (rtm->rtm_pid == 0) {
+ TRACE1(NETWORK, "Invalid rtm_pid %d, dropping.", rtm->rtm_pid);
+ rtm->rtm_errno = -1;
+ goto bounce;
+    }
+
+    switch (rtm->rtm_type) {
+    case RTM_ADD:
+ result = rtm_add_route(rtm, nbytes);
+ if (result == 0) {
+     TRACE0(NETWORK, "route added successfully");
+ } else {
+     TRACE0(NETWORK, "failed to add route");
+ }
+ rtm->rtm_errno = result;
+ break;
+
+    case RTM_DELETE:
+ result = rtm_delete_route(rtm, nbytes);
+ if (result == 0) {
+     TRACE0(NETWORK, "route deleted successfully");
+ } else {
+     TRACE0(NETWORK, "failed to delete route");
+ }
+ rtm->rtm_errno = result;
+ break;
+
+    default:
+ TRACE1(NETWORK, "Invalid rtm_type %d, dropping.", rtm->rtm_type);
+ rtm->rtm_errno = -1;
+ break;
+    }
+
+bounce:
+    /*
+     * There is currently no analogue of the BSD SO_LOOPBACK option.
+     * XXX: Normally processes will hear their own messages echoed across
+     * the routing socket emulation pipe. Because the broadcast technique
+     * uses blocking NT I/O, processes must read back their own message
+     * after issuing it.
+     */
+    broadcast_pipe_message(pp->rbuf, nbytes);
+drop:
+    TRACE0(NETWORK, "Posting read again.");
+    ResetEvent(pp->revent);
+    QueueUserWorkItem(
+(LPTHREAD_START_ROUTINE)pipe_reread_cb, (PVOID)pp, WT_EXECUTEINIOTHREAD);
+
+out:
+    TRACE0(ENTER, "Leaving pipe_read_cb");
+    LeaveCriticalSection(&pp->rcs);
+}
+
+
+static
+VOID
+FreeEventEntry (
+    PQUEUE_ENTRY        pqeEntry)
+{
+    EE_Destroy(CONTAINING_RECORD(pqeEntry, EVENT_ENTRY, qeEventQueueLink));
+}
+
+
+
+DWORD
+EE_Create (
+    ROUTING_PROTOCOL_EVENTS rpeEvent,
+    MESSAGE                 mMessage,
+    PEVENT_ENTRY            *ppeeEventEntry)
+{
+    DWORD               dwErr = NO_ERROR;
+    PEVENT_ENTRY        peeEntry; /* scratch */
+
+    /* validate parameters */
+    if (!ppeeEventEntry)
+        return ERROR_INVALID_PARAMETER;
+
+    *ppeeEventEntry = NULL;
+
+    /* allocate the interface entry structure */
+    MALLOC(&peeEntry, sizeof(EVENT_ENTRY), &dwErr);
+    if (dwErr != NO_ERROR)
+        return dwErr;
+
+    /* initialize various fields */
+    InitializeQueueHead(&(peeEntry->qeEventQueueLink));
+
+    peeEntry->rpeEvent = rpeEvent;
+    peeEntry->mMessage = mMessage;
+
+    *ppeeEventEntry = peeEntry;
+    return dwErr;
+}
+
+
+
+DWORD
+EE_Destroy (
+    PEVENT_ENTRY            peeEventEntry)
+{
+    if (!peeEventEntry)
+        return NO_ERROR;
+
+    FREE(peeEventEntry);
+
+    return NO_ERROR;
+}
+
+
+DWORD
+EnqueueEvent(
+    ROUTING_PROTOCOL_EVENTS rpeEvent,
+    MESSAGE                 mMessage)
+{
+    DWORD           dwErr = NO_ERROR;
+    PEVENT_ENTRY    peeEntry = NULL;
+
+    dwErr = EE_Create(rpeEvent, mMessage, &peeEntry);
+    /* destroyed in EE_DequeueEvent */
+
+    if (dwErr == NO_ERROR)
+    {
+        ACQUIRE_QUEUE_LOCK(&(g_ce.lqEventQueue));
+
+        Enqueue(&(g_ce.lqEventQueue.head), &(peeEntry->qeEventQueueLink));
+
+        RELEASE_QUEUE_LOCK(&(g_ce.lqEventQueue));
+    }
+
+    return dwErr;
+}
+
+DWORD
+DequeueEvent(
+    ROUTING_PROTOCOL_EVENTS  *prpeEvent,
+    MESSAGE                  *pmMessage)
+{
+    DWORD           dwErr   = NO_ERROR;
+    PQUEUE_ENTRY    pqe     = NULL;
+    PEVENT_ENTRY    pee     = NULL;
+
+    ACQUIRE_QUEUE_LOCK(&(g_ce.lqEventQueue));
+
+    do {
+        if (IsQueueEmpty(&(g_ce.lqEventQueue.head))) {
+            dwErr = ERROR_NO_MORE_ITEMS;
+            TRACE0(CONFIGURATION, "No events in the queue.");
+            break;
+        }
+
+        pqe = Dequeue(&(g_ce.lqEventQueue.head));
+        pee = CONTAINING_RECORD(pqe, EVENT_ENTRY, qeEventQueueLink);
+        *(prpeEvent) = pee->rpeEvent;
+        *(pmMessage) = pee->mMessage;
+
+        /* created in EE_EnqueueEvent */
+        EE_Destroy(pee);
+        pee = NULL;
+    } while (FALSE);
+
+    RELEASE_QUEUE_LOCK(&(g_ce.lqEventQueue));
+
+    return dwErr;
+}
+
+DWORD
+CE_Create (
+    PCONFIGURATION_ENTRY    pce)
+{
+    DWORD dwErr = NO_ERROR;
+
+    /* initialize to default values */
+    ZeroMemory(pce, sizeof(CONFIGURATION_ENTRY));
+    pce->dwTraceID = INVALID_TRACEID;
+
+    do {
+        /* initialize the read-write lock */
+        CREATE_READ_WRITE_LOCK(&(pce->rwlLock));
+        if (!READ_WRITE_LOCK_CREATED(&(pce->rwlLock))) {
+            dwErr = GetLastError();
+
+            TRACE1(CONFIGURATION, "Error %u creating read-write-lock", dwErr);
+
+            break;
+        }
+
+        /* initialize the global heap */
+        pce->hGlobalHeap = HeapCreate(0, 0, 0);
+        if (pce->hGlobalHeap == NULL) {
+            dwErr = GetLastError();
+            TRACE1(CONFIGURATION, "Error %u creating global heap", dwErr);
+
+            break;
+        }
+
+ /*
+         * Initialize the count of threads that are active in subsystem.
+         * Create the semaphore released by each thread when it is done;
+         * required for clean stop to the protocol.
+  */
+        pce->ulActivityCount = 0;
+        pce->hActivitySemaphore = CreateSemaphore(NULL, 0, 0xfffffff, NULL);
+        if (pce->hActivitySemaphore == NULL) {
+            dwErr = GetLastError();
+            TRACE1(CONFIGURATION, "Error %u creating semaphore", dwErr);
+            break;
+        }
+
+        /* Logging & Tracing Information */
+        pce->dwTraceID  = TraceRegister(XORPRTM_TRACENAME);
+
+        /* Event Queue */
+        INITIALIZE_LOCKED_QUEUE(&(pce->lqEventQueue));
+        if (!LOCKED_QUEUE_INITIALIZED(&(pce->lqEventQueue))) {
+            dwErr = GetLastError();
+            TRACE1(CONFIGURATION, "Error %u initializing locked queue", dwErr);
+            break;
+        }
+
+        /* Protocol State */
+        pce->iscStatus = XORPRTM_STATUS_STOPPED;
+
+    } while (FALSE);
+
+    if (dwErr != NO_ERROR) {
+        /* something went wrong, so cleanup. */
+        TRACE0(CONFIGURATION, "Failed to create configuration entry");
+        CE_Destroy(pce);
+    }
+
+    return dwErr;
+}
+
+DWORD
+CE_Destroy (
+    PCONFIGURATION_ENTRY    pce)
+{
+    /* Event Queue */
+    if (LOCKED_QUEUE_INITIALIZED(&(pce->lqEventQueue)))
+        DELETE_LOCKED_QUEUE((&(pce->lqEventQueue)), FreeEventEntry);
+
+    /* Logging & Tracing Information */
+    if (pce->dwTraceID != INVALID_TRACEID) {
+        TraceDeregister(pce->dwTraceID);
+        pce->dwTraceID = INVALID_TRACEID;
+    }
+
+    /* destroy the semaphore released by each thread when it is done */
+    if (pce->hActivitySemaphore != NULL) {
+        CloseHandle(pce->hActivitySemaphore);
+        pce->hActivitySemaphore = NULL;
+    }
+
+    if (pce->hGlobalHeap != NULL) {
+        HeapDestroy(pce->hGlobalHeap);
+        pce->hGlobalHeap = NULL;
+    }
+
+    /* delete the read-write lock */
+    if (READ_WRITE_LOCK_CREATED(&(pce->rwlLock)))
+        DELETE_READ_WRITE_LOCK(&(pce->rwlLock));
+
+    return NO_ERROR;
+}
+
+DWORD
+CE_Initialize (
+    PCONFIGURATION_ENTRY    pce,
+    HANDLE                  hMgrNotificationEvent,
+    PSUPPORT_FUNCTIONS      psfSupportFunctions,
+    PXORPRTM_GLOBAL_CONFIG pigc)
+{
+    DWORD   dwErr               = NO_ERROR;
+    pipe_instance_t *pp;
+    int i, pipefail;
+
+    do {
+        pce->ulActivityCount    = 0;
+
+ pce->hMprConfig = NULL;
+ dwErr = MprConfigServerConnect(NULL, &pce->hMprConfig);
+ if (dwErr != NO_ERROR) {
+            TRACE0(CONFIGURATION, "could not obtain mpr config handle");
+ }
+
+        /* Router Manager Information */
+        pce->hMgrNotificationEvent   = hMgrNotificationEvent;
+        if (psfSupportFunctions)
+            pce->sfSupportFunctions      = *psfSupportFunctions;
+
+ pipefail = 0;
+ for (i = 0; i < PIPE_INSTANCES; i++) {
+     pp = pipe_new();
+     if (pp == NULL) {
+  pipefail = 1;
+  break;
+     } else {
+  pipe_listen(pp);
+  pce->pipes[i] = pp;
+     }
+ }
+
+ if (pipefail) {
+            TRACE0(CONFIGURATION, "failed to allocate all pipes");
+     break;
+ }
+ TRACE0(ANY, "Listening on pipes ok.");
+
+        pce->reiRtmEntity.RtmInstanceId = 0;
+#ifdef IPV6_DLL
+        pce->reiRtmEntity.AddressFamily = AF_INET6;
+#else
+        pce->reiRtmEntity.AddressFamily = AF_INET;
+#endif
+        pce->reiRtmEntity.EntityId.EntityProtocolId = PROTO_IP_XORPRTM;
+        pce->reiRtmEntity.EntityId.EntityInstanceId = 0;
+
+        dwErr = RtmRegisterEntity(
+            &pce->reiRtmEntity,
+            NULL,
+            RTM_CallbackEvent,
+            TRUE,
+            &pce->rrpRtmProfile,
+            &pce->hRtmHandle);
+        if (dwErr != NO_ERROR) {
+            TRACE1(CONFIGURATION, "Error %u registering with RTM", dwErr);
+            break;
+        }
+ TRACE0(ANY, "registered entity ok.");
+
+        dwErr = RtmRegisterForChangeNotification(
+            pce->hRtmHandle,
+            RTM_VIEW_MASK_UCAST,
+            RTM_CHANGE_TYPE_ALL,
+            NULL,
+            &pce->hRtmNotificationHandle);
+        if (dwErr != NO_ERROR) {
+            TRACE1(CONFIGURATION,
+                   "Error %u registering for change with RTM", dwErr);
+            break;
+        }
+ TRACE0(ANY, "registered rtm changes ok.");
+
+        pce->iscStatus = XORPRTM_STATUS_RUNNING;
+    } while (FALSE);
+
+    if (dwErr != NO_ERROR) {
+ TRACE0(ANY, "init failed, cleaning up.");
+        CE_Cleanup(pce);
+    } else {
+ TRACE0(ANY, "Leaving init ok ");
+    }
+
+    return dwErr;
+}
+
+DWORD
+CE_Cleanup(PCONFIGURATION_ENTRY pce)
+{
+    DWORD dwErr = NO_ERROR;
+    int i;
+
+    if (pce->hRtmNotificationHandle) {
+        dwErr = RtmDeregisterFromChangeNotification(
+            pce->hRtmHandle,
+            pce->hRtmNotificationHandle);
+        if (dwErr != NO_ERROR)
+            TRACE1(CONFIGURATION,
+                   "Error %u deregistering for change from RTM", dwErr);
+    }
+    pce->hRtmNotificationHandle = NULL;
+
+    if (pce->hRtmHandle) {
+        dwErr = RtmDeregisterEntity(pce->hRtmHandle);
+
+        if (dwErr != NO_ERROR)
+            TRACE1(CONFIGURATION,
+                   "Error %u deregistering from RTM", dwErr);
+    }
+    pce->hRtmHandle             = NULL;
+
+    for (i = 0; i < PIPE_INSTANCES; i++) {
+ if (pce->pipes[i]) {
+     pipe_destroy(pce->pipes[i]);
+     pce->pipes[i] = NULL;
+ }
+    }
+
+    if (pce->hMprConfig != NULL) {
+ MprConfigServerDisconnect(pce->hMprConfig);
+    }
+    pce->hMprConfig = NULL;
+
+    pce->iscStatus = XORPRTM_STATUS_STOPPED;
+
+    return NO_ERROR;
+}
+
+VOID
+CM_WorkerFinishStopProtocol (
+    PVOID   pvContext)
+{
+    DWORD           dwErr = NO_ERROR;
+    MESSAGE         mMessage;
+
+    ULONG           ulThreadCount = 0;
+
+    ulThreadCount = (ULONG)pvContext;
+
+    TRACE1(ENTER, "Entering WorkerFinishStopProtocol: active threads %u",
+           ulThreadCount);
+
+    /* NOTE: since this is called while the router is stopping, there is no */
+    /* need for it to use ENTER_XORPRTM_WORKER()/LEAVE_XORPRTM_WORKER() */
+
+    /* waits for all threads to stop */
+    while (ulThreadCount-- > 0)
+        WaitForSingleObject(g_ce.hActivitySemaphore, INFINITE);
+
+
+   /* acquire the lock and release it, just to be sure that all threads */
+   /* have quit their calls to LeaveSampleWorker() */
+
+    ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
+    RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    /* NOTE: there is no need to acquire g_ce.rwlLock for the call to */
+    /* CE_Cleanup since there are no threads competing for access to the */
+    /* fields being cleaned up.  new competing threads aren't created till */
+    /* CE_Cleanup sets the protocol state to XORPRTM_STATUS_STOPPED, which */
+    /* is the last thing it does. */
+
+    CE_Cleanup(&g_ce);
+
+    /* inform router manager that we are done */
+    ZeroMemory(&mMessage, sizeof(MESSAGE));
+    if (EnqueueEvent(ROUTER_STOPPED, mMessage) == NO_ERROR)
+        SetEvent(g_ce.hMgrNotificationEvent);
+
+    TRACE0(LEAVE, "Leaving  WorkerFinishStopProtocol");
+}
+
+/* APIFUNCTIONS */
+
+DWORD
+CM_StartProtocol (
+    HANDLE                  hMgrNotificationEvent,
+    PSUPPORT_FUNCTIONS      psfSupportFunctions,
+    PVOID                   pvGlobalInfo)
+{
+    DWORD dwErr = NO_ERROR;
+
+    /*
+     * NOTE: since this is called when the protocol is stopped, there
+     * is no need for it to use ENTER_XORPRTM_API()/LEAVE_XORPRTM_API().
+     */
+    ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    do {
+        if (g_ce.iscStatus != XORPRTM_STATUS_STOPPED) {
+            TRACE1(CONFIGURATION, "Error: %s already installed",
+     XORPRTM_LOGNAME);
+            dwErr = ERROR_CAN_NOT_COMPLETE;
+
+            break;
+        }
+        dwErr = CE_Initialize(&g_ce,
+                              hMgrNotificationEvent,
+                              psfSupportFunctions,
+                              (PXORPRTM_GLOBAL_CONFIG) pvGlobalInfo);
+    } while (FALSE);
+
+    RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    if (dwErr == NO_ERROR) {
+        TRACE1(CONFIGURATION, "%s has successfully started", XORPRTM_LOGNAME);
+    } else {
+        TRACE2(CONFIGURATION, "Error: %s failed to start (%d)",
+        XORPRTM_LOGNAME, dwErr);
+    }
+
+    return dwErr;
+}
+
+
+DWORD
+CM_StopProtocol ()
+{
+    DWORD dwErr         = NO_ERROR;
+    BOOL  bSuccess      = FALSE;
+    ULONG ulThreadCount = 0;
+
+    /* XXX: no need to use ENTER_XORPRTM_API()/LEAVE_XORPRTM_API() */
+
+    ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    do {
+        /* cannot stop if already stopped */
+        if (g_ce.iscStatus != XORPRTM_STATUS_RUNNING)
+        {
+            TRACE0(CONFIGURATION, "Error ip sample already stopped");
+            dwErr = ERROR_CAN_NOT_COMPLETE;
+
+            break;
+        }
+
+ /*
+  * Set XORPRTM's status to STOPPING; this prevents any more work
+  * items from being queued, and it prevents the ones already
+  * queued from executing.
+  */
+        g_ce.iscStatus = XORPRTM_STATUS_STOPPING;
+
+ /*
+         * find out how many threads are either queued or active in XORPRTM;
+         * we will have to wait for this many threads to exit before we
+         * clean up XORPRTM's resources.
+  */
+        ulThreadCount = g_ce.ulActivityCount;
+        TRACE2(CONFIGURATION, "%u threads are active in %s", ulThreadCount,
+        XORPRTM_LOGNAME);
+    } while (FALSE);
+
+    RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
+
+    if (dwErr == NO_ERROR) {
+        bSuccess = QueueUserWorkItem(
+            (LPTHREAD_START_ROUTINE)CM_WorkerFinishStopProtocol,
+            (PVOID) ulThreadCount,
+            0); /* no flags */
+        dwErr = (bSuccess) ? ERROR_PROTOCOL_STOP_PENDING : GetLastError();
+    }
+
+    return dwErr;
+}
+
+DWORD
+CM_GetGlobalInfo (
+    PVOID          pvGlobalInfo,
+    PULONG              pulBufferSize,
+    PULONG         pulStructureVersion,
+    PULONG              pulStructureSize,
+    PULONG              pulStructureCount)
+{
+    DWORD                   dwErr = NO_ERROR;
+    PXORPRTM_GLOBAL_CONFIG pigc;
+    ULONG                   ulSize = sizeof(XORPRTM_GLOBAL_CONFIG);
+
+    do
+    {
+        if((*pulBufferSize < ulSize) || (pvGlobalInfo == NULL))
+        {
+            dwErr = ERROR_INSUFFICIENT_BUFFER;
+            TRACE1(CONFIGURATION,
+                   "CM_GetGlobalInfo: *ulBufferSize %u",
+                   *pulBufferSize);
+
+            *pulBufferSize = ulSize;
+
+            break;
+        }
+
+        *pulBufferSize = ulSize;
+
+        if (pulStructureVersion)    *pulStructureVersion    = 1;
+        if (pulStructureSize)       *pulStructureSize       = ulSize;
+        if (pulStructureCount)      *pulStructureCount      = 1;
+
+        pigc = (PXORPRTM_GLOBAL_CONFIG) pvGlobalInfo;
+
+    } while (FALSE);
+
+    return dwErr;
+}
+
+/*
+ * Called when the Router Manager tells us there's an event
+ * in our event queue.
+ * NOTE: this can be called after the protocol is stopped, as in when
+ * the ip router manager is retrieving the ROUTER_STOPPED message, so
+ * we do not call ENTER_XORPRTM_API()/LEAVE_XORPRTM_API().
+ */
+DWORD
+CM_GetEventMessage (
+    ROUTING_PROTOCOL_EVENTS *prpeEvent,
+    MESSAGE                 *pmMessage)
+{
+    DWORD           dwErr       = NO_ERROR;
+
+    dwErr = DequeueEvent(prpeEvent, pmMessage);
+
+    return dwErr;
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvImpLoad)
+{
+ BOOL bError = TRUE;
+
+ switch (dwReason) {
+ case DLL_PROCESS_ATTACH:
+  DisableThreadLibraryCalls(hInstance);
+  bError = (CE_Create(&g_ce) == NO_ERROR) ? TRUE : FALSE;
+  break;
+
+ case DLL_PROCESS_DETACH:
+  CE_Destroy(&g_ce);
+  break;
+
+ default:
+  break;
+ }
+
+ return bError;
+}
+
+/*
+ * Add a route to RTMv2 based on a routing socket message.
+ * XXX: We should report errors in more detail, e.g. if the
+ * route could not be added because it already existed, etc.
+ */
+int
+rtm_add_route(struct rt_msghdr *rtm, int msgsize)
+{
+    static const proper_msgsize = (sizeof(struct rt_msghdr) +
+      (sizeof(sockunion_t) * 3));
+    sockunion_t *sa;
+#ifdef IPV6_DLL
+    struct in6_addr in6_dest;
+    struct in6_addr in6_mask;
+    struct in6_addr in6_nexthop;
+#else
+    struct in_addr in_dest;
+    struct in_addr in_mask;
+    struct in_addr in_nexthop;
+    MIB_IPFORWARDROW ro;
+#endif
+    int retval;
+    int prefix;
+    DWORD result;
+    RTM_NET_ADDRESS dest;
+    RTM_NET_ADDRESS nexthop;
+    RTM_NEXTHOP_HANDLE nhh;
+    RTM_NEXTHOP_INFO nhi;
+    RTM_ROUTE_HANDLE nrh;
+    RTM_ROUTE_INFO ri;
+    RTM_ROUTE_CHANGE_FLAGS changeFlags;
+
+    /*
+     * Sanity check message size, fields etc.
+     */
+    if (!rtm)
+ return -1;
+    if (msgsize < proper_msgsize || (rtm->rtm_msglen < proper_msgsize))
+ return -1;
+    if (rtm->rtm_type != RTM_ADD)
+ return -1;
+    if ((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY|RTA_NETMASK)) !=
+ (RTA_DST|RTA_GATEWAY|RTA_NETMASK))
+ return -1;
+
+    nhh = NULL;
+    nrh = NULL;
+
+    /*
+     * Extract destination, netmask and next-hop from routing
+     * socket message.
+     */
+#ifdef IPV6_DLL
+    sa = (sockunion_t *)(rtm + 1);
+    in6_dest = sa->sin6.sin6_addr;
+    if (sa->sa.sa_family != AF_INET6)
+ return -1;
+    ++sa;
+    in6_nexthop = sa->sin6.sin6_addr;
+    if (sa->sa.sa_family != AF_INET6)
+ return -1;
+    ++sa;
+    in6_mask = sa->sin6.sin6_addr;
+    if (sa->sa.sa_family != AF_INET6)
+ return -1;
+#else
+    sa = (sockunion_t *)(rtm + 1);
+    if (sa->sa.sa_family != AF_INET)
+ return -1;
+    in_dest = sa->sin.sin_addr;
+    ++sa;
+    if (sa->sa.sa_family != AF_INET)
+ return -1;
+    in_nexthop = sa->sin.sin_addr;
+    ++sa;
+    if (sa->sa.sa_family != AF_INET)
+ return -1;
+    in_mask = sa->sin.sin_addr;
+#endif
+
+#ifndef IPV6_DLL
+    /*
+     * Look up the next-hop in the system routing table via
+     * IP Helper. If there is no directly connected route we
+     * can use to reach the next-hop, then we reject this attempt
+     * to add a route, as we need to know the interface index
+     * of this route in order to add the new route.
+     * XXX This is not good for multihop.
+     * XXX IPv6!
+     */
+    result = GetBestRoute(in_nexthop.s_addr, INADDR_ANY, &ro);
+    if (result != NO_ERROR) {
+ TRACE1(NETWORK, "error: GetBestRoute() returned %d", result);
+ return -1;
+    }
+#endif
+
+    /*
+     * Convert netmask to a prefix length.
+     * Convert destination to an RTM_NET_ADDRESS.
+     * Convert next-hop to an RTM_NET_ADDRESS.
+     * XXX: IPv6 path needs 'get length from mask' macro.
+     * XXX: IPv6 path needs interface index.
+     */
+#ifdef IPV6_DLL
+    RTM_IPV6_LEN_FROM_MASK(prefix, in6_mask.s_addr);
+    RTM_IPV6_MAKE_NET_ADDRESS(&dest, in6_dest.s_addr, prefix);
+    RTM_IPV6_MAKE_NET_ADDRESS(&nexthop, in6_nexthop.s_addr, 128);
+#else
+    RTM_IPV4_LEN_FROM_MASK(prefix, in_mask.s_addr);
+    RTM_IPV4_MAKE_NET_ADDRESS(&dest, in_dest.s_addr, prefix);
+    RTM_IPV4_MAKE_NET_ADDRESS(&nexthop, in_nexthop.s_addr, 32);
+    /*
+     * Fill out the next-hop info structure.
+     * Create the next-hop in the RTMv2 table.
+     */
+    ZeroMemory(&nhi, sizeof(nhi));
+    nhi.InterfaceIndex = ro.dwForwardIfIndex;
+    nhi.NextHopAddress = nexthop;
+#endif /* IPV6_DLL */
+
+    result = RtmAddNextHop(g_ce.hRtmHandle, &nhi, &nhh, &changeFlags);
+    if (result != NO_ERROR) {
+ TRACE1(NETWORK, "error %u adding nexthop", result);
+ retval = -1;
+ goto out;
+    }
+
+    /*
+     * Fill out the RTM_ROUTE_INFO structure.
+     * Attempt to add the route.
+     */
+    ZeroMemory(&ri, sizeof(ri));
+    ri.PrefInfo.Metric = XORPRTM_RI_METRIC;
+    ri.PrefInfo.Preference = XORPRTM_RI_PREF;
+    ri.BelongsToViews = RTM_VIEW_MASK_UCAST;
+    ri.NextHopsList.NumNextHops = 1;
+    ri.NextHopsList.NextHops[0] = nhh;
+    changeFlags = 0;
+
+    result = RtmAddRouteToDest(g_ce.hRtmHandle, &nrh, &dest, &ri, INFINITE,
+          NULL, 0, NULL, &changeFlags);
+    if (result != NO_ERROR) {
+ TRACE1(NETWORK, "error %u adding route", result);
+ retval = -1;
+ goto out;
+    }
+
+    retval = 0;
+
+out:
+    if (nrh != NULL)
+ RtmReleaseRoutes(g_ce.hRtmHandle, 1, &nrh);
+    if (nhh != NULL)
+ RtmReleaseNextHops(g_ce.hRtmHandle, 1, &nhh);
+
+    return (retval);
+}
+
+/*
+ * Delete a route from RTMv2 based on a routing socket message.
+ * XXX: We should report errors in more detail, e.g. if the
+ * route could not be added because it already existed, etc.
+ */
+int
+rtm_delete_route(struct rt_msghdr *rtm, int msgsize)
+{
+    static const min_msgsize = (sizeof(struct rt_msghdr) +
+          (sizeof(sockunion_t) * 2));
+    sockunion_t *sa;
+    struct in_addr in_dest;
+    struct in_addr in_mask;
+    int found;
+    int i;
+    int prefix;
+    int retval;
+    DWORD result;
+    RTM_DEST_INFO di;
+    RTM_NET_ADDRESS dest;
+    RTM_ROUTE_CHANGE_FLAGS changeflags;
+
+    /*
+     * Sanity check message size, fields etc.
+     */
+    if (!rtm)
+ return -1;
+    if (msgsize < min_msgsize || (rtm->rtm_msglen < min_msgsize))
+ return -1;
+    if (rtm->rtm_type != RTM_DELETE)
+ return -1;
+    if ((rtm->rtm_addrs & (RTA_DST|RTA_NETMASK)) != (RTA_DST|RTA_NETMASK))
+ return -1;
+    /*
+     * Extract destination, netmask and next-hop from routing
+     * socket message.
+     * XXX: bsd's delete order is: <DST,GATEWAY,NETMASK>
+     * XXX: we don't check to see if gateway is present and
+     * if so we do not handle it correctly.
+     */
+    sa = (sockunion_t *)(rtm + 1);
+    in_dest = sa->sin.sin_addr;
+    ++sa;
+    in_mask = sa->sin.sin_addr;
+
+    /*
+     * Convert netmask to a prefix length.
+     * Convert destination to an RTM_NET_ADDRESS.
+     */
+    RTM_IPV4_LEN_FROM_MASK(prefix, in_mask.s_addr);
+    RTM_IPV4_MAKE_NET_ADDRESS(&dest, in_dest.s_addr, prefix);
+
+    /*
+     * Look up the route to be deleted in RTMv2, from those
+     * which belong to our protocol, in the unicast view.
+     */
+    ZeroMemory(&di, sizeof(di));
+    di.DestAddress = dest;
+    result = RtmGetExactMatchDestination(g_ce.hRtmHandle, &dest,
+      RTM_THIS_PROTOCOL,
+      RTM_VIEW_MASK_UCAST, &di);
+    if (result != NO_ERROR) {
+ TRACE1(NETWORK, "error %u looking up route to delete", result);
+ retval = -1;
+ goto out;
+    }
+    i = 0;
+    found = 0;
+    for (i = 0; i < di.NumberOfViews; i++) {
+     if (di.ViewInfo[i].ViewId == RTM_VIEW_ID_UCAST) {
+     /*
+      * Return a match only if the unicast view for our protocol
+      * contains a single next-hop route to the destination.
+      */
+     if (di.ViewInfo[i].NumRoutes == 1)
+  found = 1;
+     break;
+ }
+    }
+    if (!found) {
+ TRACE0(NETWORK, "route not found in table");
+ retval = -1;
+ goto out;
+    }
+
+    result = RtmDeleteRouteToDest(g_ce.hRtmHandle, di.ViewInfo[i].Route,
+      &changeflags);
+    if (result != NO_ERROR) {
+ TRACE1(NETWORK, "error %u deleting route", result);
+ retval = -1;
+ goto out;
+    }
+
+    retval = 0;
+
+out:
+    return (retval);
+}
+
+int
+rtm_ifannounce(LPWSTR ifname, DWORD ifindex, int what)
+{
+    WCHAR fnameW[IFNAMSIZ];
+    struct if_announcemsghdr *ifa;
+    int result;
+    int retval;
+
+    TRACE3(ENTER, "Entering rtm_ifannounce %S %d %d", ifname, ifindex, what);
+
+    ifa = NULL;
+    retval = -1;
+
+    if ((what != IFAN_ARRIVAL) && (what != IFAN_DEPARTURE)) {
+ goto out;
+    }
+
+    ifa = malloc(sizeof(*ifa));
+    if (ifa == NULL) {
+ goto out;
+    }
+    ifa->ifan_name[0] = '\0';
+
+    /*
+     * If this is a new interface, then look up the FriendlyName from
+     * the unicode GUID name; convert Unicode to ASCII afterwards.
+     * If the caller didn't supply this, the error is fatal to this function.
+     * If we can't find it, the error is non-fatal to this function.
+     *
+     * XXX: The very fact that we don't provide the interface name here
+     * is a limitation to do with how the notifications work in the
+     * Microsoft stack. It only tells us the interface index when
+     * the interface goes away. XORP currently depends on both for
+     * interface deletion. We could look it up from the transport,
+     * but it's more work to deliver redundant information.
+     */
+    if (what == IFAN_ARRIVAL) {
+ if (ifname == NULL)
+     goto out;
+
+ result = MprConfigGetFriendlyName(g_ce.hMprConfig, ifname, fnameW,
+       sizeof(fnameW));
+ if (result != NO_ERROR) {
+     TRACE1(NETWORK, "can't find friendlyname for ifname %S", ifname);
+ } else {
+     wcstombs(ifa->ifan_name, fnameW, IFNAMSIZ);
+ }
+    }
+
+    /*
+     * Fill our the rest of the interface announcement and send it to
+     * all connected clients.
+     */
+    ifa->ifan_msglen = sizeof(*ifa);
+    ifa->ifan_version = RTM_VERSION; /* XXX should set to 0 or ignore */
+    ifa->ifan_type = RTM_IFANNOUNCE;
+    ifa->ifan_index = ifindex;
+    ifa->ifan_what = what;
+
+    broadcast_pipe_message(ifa, sizeof(*ifa));
+
+    retval = 0;
+
+out:
+    if (ifa != NULL)
+ free(ifa);
+
+    TRACE0(ENTER, "Leaving rtm_ifannounce");
+
+    return (retval);
+}
+
+int
+rtm_ifinfo(DWORD ifindex, int up)
+{
+    struct if_msghdr *ifm;
+    int result;
+    int retval;
+
+    TRACE2(ENTER, "Entering rtm_ifinfo %d %d", ifindex, up);
+
+    ifm = NULL;
+    retval = -1;
+
+    ifm = malloc(sizeof(*ifm));
+    if (ifm == NULL) {
+ goto out;
+    }
+
+    /*
+     * Fill our the rest of the interface announcement and send it to
+     * all connected clients.
+     */
+    ifm->ifm_msglen = sizeof(*ifm);
+    ifm->ifm_version = RTM_VERSION;
+    ifm->ifm_type = RTM_IFANNOUNCE;
+    ifm->ifm_addrs = 0;
+    ifm->ifm_flags = 0;
+    ifm->ifm_index = ifindex;
+    ifm->ifm_data.ifi_link_state = (up ? LINK_STATE_UP : LINK_STATE_DOWN);
+
+    broadcast_pipe_message(ifm, sizeof(*ifm));
+
+    retval = 0;
+
+out:
+    if (ifm != NULL)
+ free(ifm);
+
+    TRACE0(ENTER, "Leaving rtm_ifinfo");
+
+    return (retval);
+}
+
+/*
+ * Send one RTM_NEWADDR message for each IPv4 address we've found
+ * in the binding message. We ignore pbind->RemoteAddress for now.
+ *
+ * XXX: This does not work like BSD's notifications; again, if we
+ * wish to send changes, like routes, we need to maintain state,
+ * as the RTMv2 APIs send the entire state of the interface's
+ * address list each time.
+ *
+ * For this reason it's probably better to use IP Helper as
+ * the means of interface information discovery (with
+ * GetAdaptersAddresses()).
+ */
+int
+rtm_newaddr(DWORD ifindex,
+#ifdef IPV6_DLL
+     PIPV6_ADAPTER_BINDING_INFO pbind
+#else
+     PIP_ADAPTER_BINDING_INFO pbind
+#endif
+)
+{
+    static const msgsize =
+sizeof(struct ifa_msghdr) + (sizeof(sockunion_t) * 2);
+    struct ifa_msghdr *ifam;
+    sockunion_t *sa;
+    sockunion_t *sa2;
+    int i;
+    int result;
+    int retval;
+
+    TRACE2(ENTER, "Entering rtm_newaddr %d %p", ifindex, pbind);
+
+    retval = -1;
+    ifam = NULL;
+
+    if (pbind == NULL)
+ goto out;
+    if (pbind->AddressCount == 0)
+ goto out;
+
+    ifam = malloc(sizeof(*ifam));
+    if (ifam == NULL)
+ goto out;
+
+    sa = (sockunion_t *)(ifam + 1);
+    sa2 = (sa + 1);
+
+    for (i = 0; i < pbind->AddressCount; i++) {
+ ifam->ifam_msglen = msgsize;
+ ifam->ifam_version = RTM_VERSION;
+ ifam->ifam_type = RTM_NEWADDR;
+ ifam->ifam_addrs = RTA_DST | RTA_NETMASK;
+ ifam->ifam_flags = 0;
+ ifam->ifam_index = ifindex;
+ ifam->ifam_metric = 0;
+#ifdef IPV6_DLL
+ sa->sin6.sin6_family = AF_INET6;
+ sa->sin6.sin6_addr.s_addr = pbind->Address[i].Address;
+ sa2->sin6.sin6_family = AF_INET6;
+ sa2->sin6.sin6_addr.s_addr = pbind->Address[i].Mask;
+#else
+ sa->sin.sin_family = AF_INET;
+ sa->sin.sin_addr.s_addr = pbind->Address[i].Address;
+ sa2->sin.sin_family = AF_INET;
+ sa2->sin.sin_addr.s_addr = pbind->Address[i].Mask;
+#endif
+
+ broadcast_pipe_message(ifam, msgsize);
+    }
+
+    retval = 0;
+
+out:
+    if (ifam != NULL)
+ free(ifam);
+
+    TRACE0(ENTER, "Leaving rtm_newaddr");
+
+    return (retval);
+}
diff --git a/xorp/contrib/xorprtm/xorprtm/xorprtm.h b/xorp/contrib/xorprtm/xorprtm/xorprtm.h
new file mode 100644
index 0000000..fbf6400
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/xorprtm.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/xorprtm.h,v 1.7 2008/10/02 21:56:41 bms Exp $
+ */
+
+#ifndef _XORPRTM_H_
+#define _XORPRTM_H_
+
+/* Nothing */
+
+#endif /* _XORPRTM_H_ */
diff --git a/xorp/contrib/xorprtm/xorprtm/xorprtm_internal.h b/xorp/contrib/xorprtm/xorprtm/xorprtm_internal.h
new file mode 100644
index 0000000..4534a48
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm/xorprtm_internal.h
@@ -0,0 +1,175 @@
+/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- */
+/* vim:set sts=4 ts=8: */
+
+/*
+ * Copyright (c) 2001-2009 XORP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, June
+ * 1991 as published by the Free Software Foundation. Redistribution
+ * and/or modification of this program under the terms of any other
+ * version of the GNU General Public License is not permitted.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+ * see the GNU General Public License, Version 2, a copy of which can be
+ * found in the XORP LICENSE.gpl file.
+ *
+ * XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+ * http://xorp.net
+ */
+
+/*
+ * $XORP: xorp/contrib/win32/xorprtm/xorprtm_internal.h,v 1.7 2008/10/02 21:56:41 bms Exp $
+ */
+
+#ifndef _CONFIGURATIONENTRY_H_
+#define _CONFIGURATIONENTRY_H_
+
+typedef struct _EVENT_ENTRY {
+    QUEUE_ENTRY             qeEventQueueLink;
+    ROUTING_PROTOCOL_EVENTS rpeEvent;
+    MESSAGE                 mMessage;
+} EVENT_ENTRY, *PEVENT_ENTRY;
+
+DWORD
+EE_Create (
+    ROUTING_PROTOCOL_EVENTS rpeEvent,
+    MESSAGE                 mMessage,
+    PEVENT_ENTRY            *ppeeEventEntry);
+
+DWORD
+EE_Destroy (PEVENT_ENTRY            peeEventEntry);
+
+#ifdef DEBUG
+DWORD
+EE_Display (
+    PEVENT_ENTRY            peeEventEntry);
+#else
+#define EE_Display(peeEventEntry)
+#endif /* DEBUG */
+
+DWORD
+EnqueueEvent(
+    ROUTING_PROTOCOL_EVENTS rpeEvent,
+    MESSAGE                 mMessage);
+
+DWORD
+DequeueEvent(
+    ROUTING_PROTOCOL_EVENTS  *prpeEvent,
+    MESSAGE                  *pmMessage);
+
+/* various codes describing states of XORPRTM. */
+typedef enum _XORPRTM_STATUS_CODE
+{
+    XORPRTM_STATUS_RUNNING     = 101,
+    XORPRTM_STATUS_STOPPING    = 102,
+    XORPRTM_STATUS_STOPPED     = 103
+} XORPRTM_STATUS_CODE, *PXORPRTM_STATUS_CODE;
+
+#define PIPE_INSTANCES 12
+#define PIPE_READBUF_SIZE 2048
+
+typedef enum _pipe_state_t {
+    PIPE_STATE_INIT,
+    PIPE_STATE_LISTEN,
+    PIPE_STATE_CONNECTED
+} pipe_state_t;
+
+typedef struct pipe_instance {
+    HANDLE     pipe;
+    pipe_state_t    state;
+
+    HANDLE     cevent;
+    HANDLE     cwait;
+    OVERLAPPED     cov;
+
+    HANDLE     revent;
+    HANDLE     rwait;
+    OVERLAPPED     rov;
+
+    CRITICAL_SECTION rcs;
+
+    size_t     rsize;
+    char     rbuf[PIPE_READBUF_SIZE];     /* XXX */
+
+} pipe_instance_t;
+
+typedef struct _CONFIGURATION_ENTRY {
+    /* Following are PERSISTENT, across Start and Stop Protocol */
+
+    READ_WRITE_LOCK         rwlLock;
+    HANDLE                  hGlobalHeap;
+    ULONG                   ulActivityCount;
+    HANDLE                  hActivitySemaphore;
+    DWORD      dwTraceID;
+    LOCKED_QUEUE            lqEventQueue;
+    XORPRTM_STATUS_CODE    iscStatus;
+
+    /* Router Manager Information  */
+    HANDLE      hMgrNotificationEvent;
+    SUPPORT_FUNCTIONS       sfSupportFunctions;
+
+    /* RTMv2 Information */
+    RTM_ENTITY_INFO reiRtmEntity;
+    RTM_REGN_PROFILE rrpRtmProfile;
+    HANDLE  hRtmHandle;
+    HANDLE  hRtmNotificationHandle;
+
+    HANDLE  hMprConfig;
+
+    pipe_instance_t *pipes[PIPE_INSTANCES];
+
+} CONFIGURATION_ENTRY, *PCONFIGURATION_ENTRY;
+
+
+
+/* create all fields on DLL_PROCESS_ATTACH */
+DWORD
+CE_Create (PCONFIGURATION_ENTRY    pce);
+
+/* destroy all fields on DLL_PROCESS_DEATTACH */
+DWORD
+CE_Destroy (PCONFIGURATION_ENTRY    pce);
+
+/* initialize non persistent fields on StartProtocol */
+DWORD
+CE_Initialize (
+    PCONFIGURATION_ENTRY    pce,
+    HANDLE                  hMgrNotificationEvent,
+    PSUPPORT_FUNCTIONS      psfSupportFunctions,
+    PXORPRTM_GLOBAL_CONFIG pigc);
+
+/* cleanup non persistent fields on StopProtocol */
+DWORD
+CE_Cleanup (PCONFIGURATION_ENTRY    pce);
+
+extern CONFIGURATION_ENTRY      g_ce;
+
+DWORD
+CM_StartProtocol (
+    HANDLE                  hMgrNotificationEvent,
+    PSUPPORT_FUNCTIONS      psfSupportFunctions,
+    PVOID                   pvGlobalInfo);
+
+DWORD
+CM_StopProtocol ();
+
+DWORD
+CM_GetGlobalInfo (
+    PVOID              pvGlobalInfo,
+    PULONG              pulBufferSize,
+    PULONG             pulStructureVersion,
+    PULONG              pulStructureSize,
+    PULONG              pulStructureCount);
+
+DWORD
+CM_SetGlobalInfo (PVOID pvGlobalInfo);
+
+DWORD
+CM_GetEventMessage (
+    ROUTING_PROTOCOL_EVENTS *prpeEvent,
+    MESSAGE                 *pmMessage);
+
+#endif /* _CONFIGURATIONENTRY_H_ */
diff --git a/xorp/contrib/xorprtm/xorprtm4/xorprtm4.def b/xorp/contrib/xorprtm/xorprtm4/xorprtm4.def
new file mode 100644
index 0000000..49cc495
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm4/xorprtm4.def
@@ -0,0 +1,4 @@
+LIBRARY XORPRTM4
+
+EXPORTS
+    RegisterProtocol
diff --git a/xorp/contrib/xorprtm/xorprtm6/xorprtm6.def b/xorp/contrib/xorprtm/xorprtm6/xorprtm6.def
new file mode 100644
index 0000000..8767494
--- /dev/null
+++ b/xorp/contrib/xorprtm/xorprtm6/xorprtm6.def
@@ -0,0 +1,4 @@
+LIBRARY XORPRTM6
+
+EXPORTS
+    RegisterProtocol
-- 
1.7.9.msysgit.0




More information about the Xorp-hackers mailing list