[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