diff --git a/build-root/build-vpp-native/vpp/vnet/dhcp/dhcp.api.h b/build-root/build-vpp-native/vpp/vnet/dhcp/dhcp.api.h
new file mode 100644
index 0000000..8f719f2
--- /dev/null
+++ b/build-root/build-vpp-native/vpp/vnet/dhcp/dhcp.api.h
@@ -0,0 +1,413 @@
+/*
+ * VLIB API definitions Tue Oct 24 18:42:06 2017
+ * Input file: vnet/dhcp/dhcp.api.h
+ * Automatically generated: please edit the input file NOT this file!
+ */
+
+#if defined(vl_msg_id)||defined(vl_union_id)||defined(vl_printfun) \
+ ||defined(vl_endianfun)|| defined(vl_api_version)||defined(vl_typedefs) \
+ ||defined(vl_msg_name)||defined(vl_msg_name_crc_list)
+/* ok, something was selected */
+#else
+#warning no content included from vnet/dhcp/dhcp.api.h
+#endif
+
+#define VL_API_PACKED(x) x __attribute__ ((packed))
+
+
+/****** Message ID / handler enum ******/
+
+#ifdef vl_msg_id
+vl_msg_id(VL_API_DHCP_PROXY_CONFIG, vl_api_dhcp_proxy_config_t_handler)
+vl_msg_id(VL_API_DHCP_PROXY_CONFIG_REPLY, vl_api_dhcp_proxy_config_reply_t_handler)
+vl_msg_id(VL_API_DHCP_PROXY_SET_VSS, vl_api_dhcp_proxy_set_vss_t_handler)
+vl_msg_id(VL_API_DHCP_PROXY_SET_VSS_REPLY, vl_api_dhcp_proxy_set_vss_reply_t_handler)
+vl_msg_id(VL_API_DHCP_CLIENT_CONFIG, vl_api_dhcp_client_config_t_handler)
+vl_msg_id(VL_API_DHCP_CLIENT_CONFIG_REPLY, vl_api_dhcp_client_config_reply_t_handler)
+vl_msg_id(VL_API_DHCP_COMPL_EVENT, vl_api_dhcp_compl_event_t_handler)
+vl_msg_id(VL_API_DHCP_PROXY_DUMP, vl_api_dhcp_proxy_dump_t_handler)
+/* typeonly: dhcp_server */
+vl_msg_id(VL_API_DHCP_PROXY_DETAILS, vl_api_dhcp_proxy_details_t_handler)
+#endif
+
+/****** Message names ******/
+
+#ifdef vl_msg_name
+vl_msg_name(vl_api_dhcp_proxy_config_t, 1)
+vl_msg_name(vl_api_dhcp_proxy_config_reply_t, 1)
+vl_msg_name(vl_api_dhcp_proxy_set_vss_t, 1)
+vl_msg_name(vl_api_dhcp_proxy_set_vss_reply_t, 1)
+vl_msg_name(vl_api_dhcp_client_config_t, 1)
+vl_msg_name(vl_api_dhcp_client_config_reply_t, 1)
+vl_msg_name(vl_api_dhcp_compl_event_t, 1)
+vl_msg_name(vl_api_dhcp_proxy_dump_t, 1)
+/* typeonly: dhcp_server */
+vl_msg_name(vl_api_dhcp_proxy_details_t, 1)
+#endif
+
+
+/****** Message name, crc list ******/
+
+#ifdef vl_msg_name_crc_list
+#define foreach_vl_msg_name_crc_dhcp \
+_(VL_API_DHCP_PROXY_CONFIG, dhcp_proxy_config, 3b4f2bc8) \
+_(VL_API_DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply, fe63196f) \
+_(VL_API_DHCP_PROXY_SET_VSS, dhcp_proxy_set_vss, be54d194) \
+_(VL_API_DHCP_PROXY_SET_VSS_REPLY, dhcp_proxy_set_vss_reply, 5bb4e754) \
+_(VL_API_DHCP_CLIENT_CONFIG, dhcp_client_config, 87920bb6) \
+_(VL_API_DHCP_CLIENT_CONFIG_REPLY, dhcp_client_config_reply, d947f4c8) \
+_(VL_API_DHCP_COMPL_EVENT, dhcp_compl_event, 5218db55) \
+_(VL_API_DHCP_PROXY_DUMP, dhcp_proxy_dump, 175bc073) \
+_(VL_API_DHCP_PROXY_DETAILS, dhcp_proxy_details, 9727dbdd) 
+#endif
+
+
+/****** Typedefs *****/
+
+#ifdef vl_typedefs
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_proxy_config {
+    u16 _vl_msg_id;
+    u32 client_index;
+    u32 context;
+    u32 rx_vrf_id;
+    u32 server_vrf_id;
+    u8 is_ipv6;
+    u8 is_add;
+    u8 dhcp_server[16];
+    u8 dhcp_src_address[16];
+}) vl_api_dhcp_proxy_config_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_proxy_config_reply {
+    u16 _vl_msg_id;
+    u32 context;
+    i32 retval;
+}) vl_api_dhcp_proxy_config_reply_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_proxy_set_vss {
+    u16 _vl_msg_id;
+    u32 client_index;
+    u32 context;
+    u32 tbl_id;
+    u32 oui;
+    u32 fib_id;
+    u8 is_ipv6;
+    u8 is_add;
+}) vl_api_dhcp_proxy_set_vss_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_proxy_set_vss_reply {
+    u16 _vl_msg_id;
+    u32 context;
+    i32 retval;
+}) vl_api_dhcp_proxy_set_vss_reply_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_client_config {
+    u16 _vl_msg_id;
+    u32 client_index;
+    u32 context;
+    u32 sw_if_index;
+    u8 hostname[64];
+    u8 is_add;
+    u8 want_dhcp_event;
+    u32 pid;
+}) vl_api_dhcp_client_config_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_client_config_reply {
+    u16 _vl_msg_id;
+    u32 context;
+    i32 retval;
+}) vl_api_dhcp_client_config_reply_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_compl_event {
+    u16 _vl_msg_id;
+    u32 client_index;
+    u32 pid;
+    u8 hostname[64];
+    u8 is_ipv6;
+    u8 host_address[16];
+    u8 router_address[16];
+    u8 host_mac[6];
+}) vl_api_dhcp_compl_event_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_proxy_dump {
+    u16 _vl_msg_id;
+    u32 client_index;
+    u32 context;
+    u8 is_ip6;
+}) vl_api_dhcp_proxy_dump_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_server {
+    u32 server_vrf_id;
+    u8 dhcp_server[16];
+}) vl_api_dhcp_server_t;
+
+typedef VL_API_PACKED(struct _vl_api_dhcp_proxy_details {
+    u16 _vl_msg_id;
+    u32 context;
+    u32 rx_vrf_id;
+    u32 vss_oui;
+    u32 vss_fib_id;
+    u8 is_ipv6;
+    u8 dhcp_src_address[16];
+    u8 count;
+    vl_api_dhcp_server_t servers[0];
+}) vl_api_dhcp_proxy_details_t;
+
+#endif /* vl_typedefs */
+
+/****** Discriminated Union Definitions *****/
+
+#ifdef vl_union_id
+
+
+#endif /* vl_union_id */
+
+/****** Print functions *****/
+
+#ifdef vl_printfun
+
+#ifdef LP64
+#define _uword_fmt "%lld"
+#define _uword_cast (long long)
+#else
+#define _uword_fmt "%ld"
+#define _uword_cast long
+#endif
+
+static inline void *vl_api_dhcp_proxy_config_t_print (vl_api_dhcp_proxy_config_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_proxy_config_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "client_index: %u\n", (unsigned) a->client_index);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "rx_vrf_id: %u\n", (unsigned) a->rx_vrf_id);
+    vl_print(handle, "server_vrf_id: %u\n", (unsigned) a->server_vrf_id);
+    vl_print(handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6);
+    vl_print(handle, "is_add: %u\n", (unsigned) a->is_add);
+    {
+        int _i;
+        for (_i = 0; _i < 16; _i++) {
+            vl_print(handle, "dhcp_server[%d]: %u\n", _i, a->dhcp_server[_i]);
+        }
+    }
+    {
+        int _i;
+        for (_i = 0; _i < 16; _i++) {
+            vl_print(handle, "dhcp_src_address[%d]: %u\n", _i, a->dhcp_src_address[_i]);
+        }
+    }
+    return handle;
+}
+
+static inline void *vl_api_dhcp_proxy_config_reply_t_print (vl_api_dhcp_proxy_config_reply_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_proxy_config_reply_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "retval: %ld\n", (long) a->retval);
+    return handle;
+}
+
+static inline void *vl_api_dhcp_proxy_set_vss_t_print (vl_api_dhcp_proxy_set_vss_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_proxy_set_vss_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "client_index: %u\n", (unsigned) a->client_index);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "tbl_id: %u\n", (unsigned) a->tbl_id);
+    vl_print(handle, "oui: %u\n", (unsigned) a->oui);
+    vl_print(handle, "fib_id: %u\n", (unsigned) a->fib_id);
+    vl_print(handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6);
+    vl_print(handle, "is_add: %u\n", (unsigned) a->is_add);
+    return handle;
+}
+
+static inline void *vl_api_dhcp_proxy_set_vss_reply_t_print (vl_api_dhcp_proxy_set_vss_reply_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_proxy_set_vss_reply_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "retval: %ld\n", (long) a->retval);
+    return handle;
+}
+
+static inline void *vl_api_dhcp_client_config_t_print (vl_api_dhcp_client_config_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_client_config_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "client_index: %u\n", (unsigned) a->client_index);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "sw_if_index: %u\n", (unsigned) a->sw_if_index);
+    {
+        int _i;
+        for (_i = 0; _i < 64; _i++) {
+            vl_print(handle, "hostname[%d]: %u\n", _i, a->hostname[_i]);
+        }
+    }
+    vl_print(handle, "is_add: %u\n", (unsigned) a->is_add);
+    vl_print(handle, "want_dhcp_event: %u\n", (unsigned) a->want_dhcp_event);
+    vl_print(handle, "pid: %u\n", (unsigned) a->pid);
+    return handle;
+}
+
+static inline void *vl_api_dhcp_client_config_reply_t_print (vl_api_dhcp_client_config_reply_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_client_config_reply_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "retval: %ld\n", (long) a->retval);
+    return handle;
+}
+
+static inline void *vl_api_dhcp_compl_event_t_print (vl_api_dhcp_compl_event_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_compl_event_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "client_index: %u\n", (unsigned) a->client_index);
+    vl_print(handle, "pid: %u\n", (unsigned) a->pid);
+    {
+        int _i;
+        for (_i = 0; _i < 64; _i++) {
+            vl_print(handle, "hostname[%d]: %u\n", _i, a->hostname[_i]);
+        }
+    }
+    vl_print(handle, "is_ipv6: %u\n", (unsigned) a->is_ipv6);
+    {
+        int _i;
+        for (_i = 0; _i < 16; _i++) {
+            vl_print(handle, "host_address[%d]: %u\n", _i, a->host_address[_i]);
+        }
+    }
+    {
+        int _i;
+        for (_i = 0; _i < 16; _i++) {
+            vl_print(handle, "router_address[%d]: %u\n", _i, a->router_address[_i]);
+        }
+    }
+    {
+        int _i;
+        for (_i = 0; _i < 6; _i++) {
+            vl_print(handle, "host_mac[%d]: %u\n", _i, a->host_mac[_i]);
+        }
+    }
+    return handle;
+}
+
+static inline void *vl_api_dhcp_proxy_dump_t_print (vl_api_dhcp_proxy_dump_t *a,void *handle)
+{
+    vl_print(handle, "vl_api_dhcp_proxy_dump_t:\n");
+    vl_print(handle, "_vl_msg_id: %u\n", (unsigned) a->_vl_msg_id);
+    vl_print(handle, "client_index: %u\n", (unsigned) a->client_index);
+    vl_print(handle, "context: %u\n", (unsigned) a->context);
+    vl_print(handle, "is_ip6: %u\n", (unsigned) a->is_ip6);
+    return handle;
+}
+
+/***** manual: vl_api_dhcp_server_t_print  *****/
+
+/***** manual: vl_api_dhcp_proxy_details_t_print  *****/
+
+#endif /* vl_printfun */
+
+
+/****** Endian swap functions *****/
+
+#ifdef vl_endianfun
+
+#undef clib_net_to_host_uword
+#ifdef LP64
+#define clib_net_to_host_uword clib_net_to_host_u64
+#else
+#define clib_net_to_host_uword clib_net_to_host_u32
+#endif
+
+static inline void vl_api_dhcp_proxy_config_t_endian (vl_api_dhcp_proxy_config_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->client_index = clib_net_to_host_u32(a->client_index);
+    a->context = clib_net_to_host_u32(a->context);
+    a->rx_vrf_id = clib_net_to_host_u32(a->rx_vrf_id);
+    a->server_vrf_id = clib_net_to_host_u32(a->server_vrf_id);
+    /* a->is_ipv6 = a->is_ipv6 (no-op) */
+    /* a->is_add = a->is_add (no-op) */
+    /* a->dhcp_server[0..15] = a->dhcp_server[0..15] (no-op) */
+    /* a->dhcp_src_address[0..15] = a->dhcp_src_address[0..15] (no-op) */
+}
+
+static inline void vl_api_dhcp_proxy_config_reply_t_endian (vl_api_dhcp_proxy_config_reply_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->context = clib_net_to_host_u32(a->context);
+    a->retval = clib_net_to_host_u32(a->retval);
+}
+
+static inline void vl_api_dhcp_proxy_set_vss_t_endian (vl_api_dhcp_proxy_set_vss_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->client_index = clib_net_to_host_u32(a->client_index);
+    a->context = clib_net_to_host_u32(a->context);
+    a->tbl_id = clib_net_to_host_u32(a->tbl_id);
+    a->oui = clib_net_to_host_u32(a->oui);
+    a->fib_id = clib_net_to_host_u32(a->fib_id);
+    /* a->is_ipv6 = a->is_ipv6 (no-op) */
+    /* a->is_add = a->is_add (no-op) */
+}
+
+static inline void vl_api_dhcp_proxy_set_vss_reply_t_endian (vl_api_dhcp_proxy_set_vss_reply_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->context = clib_net_to_host_u32(a->context);
+    a->retval = clib_net_to_host_u32(a->retval);
+}
+
+static inline void vl_api_dhcp_client_config_t_endian (vl_api_dhcp_client_config_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->client_index = clib_net_to_host_u32(a->client_index);
+    a->context = clib_net_to_host_u32(a->context);
+    a->sw_if_index = clib_net_to_host_u32(a->sw_if_index);
+    /* a->hostname[0..63] = a->hostname[0..63] (no-op) */
+    /* a->is_add = a->is_add (no-op) */
+    /* a->want_dhcp_event = a->want_dhcp_event (no-op) */
+    a->pid = clib_net_to_host_u32(a->pid);
+}
+
+static inline void vl_api_dhcp_client_config_reply_t_endian (vl_api_dhcp_client_config_reply_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->context = clib_net_to_host_u32(a->context);
+    a->retval = clib_net_to_host_u32(a->retval);
+}
+
+static inline void vl_api_dhcp_compl_event_t_endian (vl_api_dhcp_compl_event_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->client_index = clib_net_to_host_u32(a->client_index);
+    a->pid = clib_net_to_host_u32(a->pid);
+    /* a->hostname[0..63] = a->hostname[0..63] (no-op) */
+    /* a->is_ipv6 = a->is_ipv6 (no-op) */
+    /* a->host_address[0..15] = a->host_address[0..15] (no-op) */
+    /* a->router_address[0..15] = a->router_address[0..15] (no-op) */
+    /* a->host_mac[0..5] = a->host_mac[0..5] (no-op) */
+}
+
+static inline void vl_api_dhcp_proxy_dump_t_endian (vl_api_dhcp_proxy_dump_t *a)
+{
+    a->_vl_msg_id = clib_net_to_host_u16(a->_vl_msg_id);
+    a->client_index = clib_net_to_host_u32(a->client_index);
+    a->context = clib_net_to_host_u32(a->context);
+    /* a->is_ip6 = a->is_ip6 (no-op) */
+}
+
+/***** manual: vl_api_dhcp_server_t_endian  *****/
+
+/***** manual: vl_api_dhcp_proxy_details_t_endian  *****/
+
+#endif /* vl_endianfun */
+
+
+#ifdef vl_api_version
+vl_api_version(dhcp.api, 0x214119c5)
+
+#endif
+
diff --git a/src/configure.ac b/src/configure.ac
index fb2ead6..ef5537d 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -152,6 +152,7 @@ PLUGIN_ENABLED(ioam)
 PLUGIN_ENABLED(ixge)
 PLUGIN_ENABLED(lb)
 PLUGIN_ENABLED(memif)
+PLUGIN_ENABLED(vbng)
 PLUGIN_ENABLED(sixrd)
 PLUGIN_ENABLED(snat)
 
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 623892e..d6f607f 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -61,6 +61,10 @@ if ENABLE_MEMIF_PLUGIN
 include memif.am
 endif
 
+if ENABLE_VBNG_PLUGIN
+include vbng.am
+endif
+
 if ENABLE_SIXRD_PLUGIN
 include sixrd.am
 endif
diff --git a/src/plugins/vbng.am b/src/plugins/vbng.am
new file mode 100644
index 0000000..99398f4
--- /dev/null
+++ b/src/plugins/vbng.am
@@ -0,0 +1,32 @@
+# Copyright (c) 2017 Intel and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+vppplugins_LTLIBRARIES += vbng_plugin.la
+
+vbng_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lfreeradiusclient
+
+vbng_plugin_la_SOURCES = vbng/vbng_dhcp4_node.c	\
+			 vbng/vbng_dhcp4.c	\
+			 vbng/vbng_api.c        \
+			 vbng/vbng_aaa.c
+
+BUILT_SOURCES += vbng/vbng.api.h		\
+		 vbng/vbng.api.json
+
+API_FILES += vbng/vbng.api
+
+nobase_apiinclude_HEADERS += vbng/vbng_all_api_h.h	\
+			     vbng/vbng_msg_enum.h	\
+			     vbng/vbng.api.h
+
+# vi:syntax=automake
diff --git a/src/plugins/vbng/etc/dictionary b/src/plugins/vbng/etc/dictionary
new file mode 100644
index 0000000..45f4189
--- /dev/null
+++ b/src/plugins/vbng/etc/dictionary
@@ -0,0 +1,274 @@
+#
+# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl
+#
+#	This file contains dictionary translations for parsing
+#	requests and generating responses.  All transactions are
+#	composed of Attribute/Value Pairs.  The value of each attribute
+#	is specified as one of 4 data types.  Valid data types are:
+#
+#	string - 0-253 octets
+#	ipaddr - 4 octets in network byte order
+#	integer - 32 bit value in big endian order (high byte first)
+#	date - 32 bit value in big endian order - seconds since
+#					00:00:00 GMT,  Jan.  1,  1970
+#
+#	Enumerated values are stored in the user file with dictionary
+#	VALUE translations for easy administration.
+#
+#	Example:
+#
+#	ATTRIBUTE	  VALUE
+#	---------------   -----
+#	Framed-Protocol = PPP
+#	7		= 1	(integer encoding)
+#
+
+#
+#	Following are the proper new names. Use these.
+#
+ATTRIBUTE	User-Name		1	string
+ATTRIBUTE	Password		2	string
+ATTRIBUTE	CHAP-Password		3	string
+ATTRIBUTE	NAS-IP-Address		4	ipaddr
+ATTRIBUTE	NAS-Port-Id		5	integer
+ATTRIBUTE	Service-Type		6	integer
+ATTRIBUTE	Framed-Protocol		7	integer
+ATTRIBUTE	Framed-IP-Address	8	ipaddr
+ATTRIBUTE	Framed-IP-Netmask	9	ipaddr
+ATTRIBUTE	Framed-Routing		10	integer
+ATTRIBUTE	Filter-Id		11	string
+ATTRIBUTE	Framed-MTU		12	integer
+ATTRIBUTE	Framed-Compression	13	integer
+ATTRIBUTE	Login-IP-Host		14	ipaddr
+ATTRIBUTE	Login-Service		15	integer
+ATTRIBUTE	Login-TCP-Port		16	integer
+ATTRIBUTE	Reply-Message		18	string
+ATTRIBUTE	Callback-Number		19	string
+ATTRIBUTE	Callback-Id		20	string
+ATTRIBUTE	Framed-Route		22	string
+ATTRIBUTE	Framed-IPX-Network	23	ipaddr
+ATTRIBUTE	State			24	string
+ATTRIBUTE	Class			25	string
+ATTRIBUTE	Vendor-Specific		26	string
+ATTRIBUTE	Session-Timeout		27	integer
+ATTRIBUTE	Idle-Timeout		28	integer
+ATTRIBUTE	Termination-Action	29	integer
+ATTRIBUTE	Called-Station-Id	30	string
+ATTRIBUTE	Calling-Station-Id	31	string
+ATTRIBUTE	NAS-Identifier		32	string
+ATTRIBUTE	Proxy-State		33	string
+ATTRIBUTE	Login-LAT-Service	34	string
+ATTRIBUTE	Login-LAT-Node		35	string
+ATTRIBUTE	Login-LAT-Group		36	string
+ATTRIBUTE	Framed-AppleTalk-Link	37	integer
+ATTRIBUTE	Framed-AppleTalk-Network	38	integer
+ATTRIBUTE	Framed-AppleTalk-Zone	39	string
+ATTRIBUTE	Acct-Status-Type	40	integer
+ATTRIBUTE	Acct-Delay-Time		41	integer
+ATTRIBUTE	Acct-Input-Octets	42	integer
+ATTRIBUTE	Acct-Output-Octets	43	integer
+ATTRIBUTE	Acct-Session-Id		44	string
+ATTRIBUTE	Acct-Authentic		45	integer
+ATTRIBUTE	Acct-Session-Time	46	integer
+ATTRIBUTE	Acct-Input-Packets	47	integer
+ATTRIBUTE	Acct-Output-Packets	48	integer
+ATTRIBUTE	Acct-Terminate-Cause	49	integer
+ATTRIBUTE	Acct-Multi-Session-Id	50	string
+ATTRIBUTE	Acct-Link-Count		51	integer
+ATTRIBUTE	Acct-Input-Gigawords	52	integer
+ATTRIBUTE	Acct-Output-Gigawords	53	integer
+ATTRIBUTE	Event-Timestamp		55	integer
+ATTRIBUTE	CHAP-Challenge		60	string
+ATTRIBUTE	NAS-Port-Type		61	integer
+ATTRIBUTE	Port-Limit		62	integer
+ATTRIBUTE	Login-LAT-Port		63	integer
+ATTRIBUTE	Connect-Info		77	string
+
+#
+#	RFC3162 IPv6 attributes
+#
+ATTRIBUTE	NAS-IPv6-Address	95	string
+ATTRIBUTE	Framed-Interface-Id	96	string
+ATTRIBUTE	Framed-IPv6-Prefix	97	ipv6prefix
+ATTRIBUTE	Login-IPv6-Host		98	string
+ATTRIBUTE	Framed-IPv6-Route	99	string
+ATTRIBUTE	Framed-IPv6-Pool	100	string
+
+#
+#	RFC6911 IPv6 attributes
+#
+ATTRIBUTE	Framed-IPv6-Address	168	ipv6addr
+ATTRIBUTE	DNS-Server-IPv6-Address	169	ipv6addr
+ATTRIBUTE	Route-IPv6-Information	170	ipv6prefix
+
+#
+#	Experimental Non Protocol Attributes used by Cistron-Radiusd
+#
+ATTRIBUTE	Huntgroup-Name		221	string
+ATTRIBUTE	User-Category		1029	string
+ATTRIBUTE	Group-Name		1030	string
+ATTRIBUTE	Simultaneous-Use	1034	integer
+ATTRIBUTE	Strip-User-Name		1035	integer
+ATTRIBUTE	Fall-Through		1036	integer
+ATTRIBUTE	Add-Port-To-IP-Address	1037	integer
+ATTRIBUTE	Exec-Program		1038	string
+ATTRIBUTE	Exec-Program-Wait	1039	string
+ATTRIBUTE	Hint			1040	string
+
+#
+#	Non-Protocol Attributes
+#	These attributes are used internally by the server
+#
+ATTRIBUTE	Expiration		  21	date
+ATTRIBUTE	Auth-Type		1000	integer
+ATTRIBUTE	Menu			1001	string
+ATTRIBUTE	Termination-Menu	1002	string
+ATTRIBUTE	Prefix			1003	string
+ATTRIBUTE	Suffix			1004	string
+ATTRIBUTE	Group			1005	string
+ATTRIBUTE	Crypt-Password		1006	string
+ATTRIBUTE	Connect-Rate		1007	integer
+
+#
+#	Integer Translations
+#
+
+#	User Types
+
+VALUE		Service-Type		Login-User		1
+VALUE		Service-Type		Framed-User		2
+VALUE		Service-Type		Callback-Login-User	3
+VALUE		Service-Type		Callback-Framed-User	4
+VALUE		Service-Type		Outbound-User		5
+VALUE		Service-Type		Administrative-User	6
+VALUE		Service-Type		NAS-Prompt-User		7
+VALUE		Service-Type		Authenticate-Only	8
+VALUE		Service-Type		Callback-NAS-Prompt	9
+VALUE		Service-Type		Call-Check		10
+VALUE		Service-Type		Callback-Administrative	11
+
+#	Framed Protocols
+
+VALUE		Framed-Protocol		PPP			1
+VALUE		Framed-Protocol		SLIP			2
+VALUE		Framed-Protocol		ARAP			3
+VALUE		Framed-Protocol		GANDALF-SLMLP		4
+VALUE		Framed-Protocol		XYLOGICS-IPX-SLIP	5
+VALUE		Framed-Protocol		X75			6
+
+#	Framed Routing Values
+
+VALUE		Framed-Routing		None			0
+VALUE		Framed-Routing		Broadcast		1
+VALUE		Framed-Routing		Listen			2
+VALUE		Framed-Routing		Broadcast-Listen	3
+
+#	Framed Compression Types
+
+VALUE		Framed-Compression	None			0
+VALUE		Framed-Compression	Van-Jacobson-TCP-IP	1
+VALUE		Framed-Compression	IPX-Header		2
+VALUE		Framed-Compression	Stac-LZS		3
+
+#	Login Services
+
+VALUE		Login-Service		Telnet			0
+VALUE		Login-Service		Rlogin			1
+VALUE		Login-Service		TCP-Clear		2
+VALUE		Login-Service		PortMaster		3
+VALUE		Login-Service		LAT			4
+VALUE		Login-Service		X.25-PAD		5
+VALUE		Login-Service		X.25-T3POS		6
+VALUE		Login-Service		TCP-Clear-Quiet		8
+
+#	Status Types
+
+VALUE		Acct-Status-Type	Start			1
+VALUE		Acct-Status-Type	Stop			2
+VALUE		Acct-Status-Type	Alive			3
+VALUE		Acct-Status-Type	Accounting-On		7
+VALUE		Acct-Status-Type	Accounting-Off		8
+
+#	Authentication Types
+
+VALUE		Acct-Authentic		RADIUS			1
+VALUE		Acct-Authentic		Local			2
+VALUE		Acct-Authentic		Remote			3
+
+#	Termination Options
+
+VALUE		Termination-Action	Default			0
+VALUE		Termination-Action	RADIUS-Request		1
+
+#	NAS Port Types, available in 3.3.1 and later
+
+VALUE		NAS-Port-Type		Async			0
+VALUE		NAS-Port-Type		Sync			1
+VALUE		NAS-Port-Type		ISDN			2
+VALUE		NAS-Port-Type		ISDN-V120		3
+VALUE		NAS-Port-Type		ISDN-V110		4
+VALUE		NAS-Port-Type		Virtual			5
+VALUE		NAS-Port-Type		PIAFS			6
+VALUE		NAS-Port-Type		HDLC-Clear-Channel	7
+VALUE		NAS-Port-Type		X.25			8
+VALUE		NAS-Port-Type		X.75			9
+VALUE		NAS-Port-Type		G.3-Fax			10
+VALUE		NAS-Port-Type		SDSL			11
+VALUE		NAS-Port-Type		ADSL-CAP		12
+VALUE		NAS-Port-Type		ADSL-DMT		13
+VALUE		NAS-Port-Type		IDSL			14
+VALUE		NAS-Port-Type		Ethernet		15
+
+#	Acct Terminate Causes, available in 3.3.2 and later
+
+VALUE           Acct-Terminate-Cause    User-Request            1
+VALUE           Acct-Terminate-Cause    Lost-Carrier            2
+VALUE           Acct-Terminate-Cause    Lost-Service            3
+VALUE           Acct-Terminate-Cause    Idle-Timeout            4
+VALUE           Acct-Terminate-Cause    Session-Timeout         5
+VALUE           Acct-Terminate-Cause    Admin-Reset             6
+VALUE           Acct-Terminate-Cause    Admin-Reboot            7
+VALUE           Acct-Terminate-Cause    Port-Error              8
+VALUE           Acct-Terminate-Cause    NAS-Error               9
+VALUE           Acct-Terminate-Cause    NAS-Request             10
+VALUE           Acct-Terminate-Cause    NAS-Reboot              11
+VALUE           Acct-Terminate-Cause    Port-Unneeded           12
+VALUE           Acct-Terminate-Cause    Port-Preempted          13
+VALUE           Acct-Terminate-Cause    Port-Suspended          14
+VALUE           Acct-Terminate-Cause    Service-Unavailable     15
+VALUE           Acct-Terminate-Cause    Callback                16
+VALUE           Acct-Terminate-Cause    User-Error              17
+VALUE           Acct-Terminate-Cause    Host-Request            18
+
+#
+#	Non-Protocol Integer Translations
+#
+
+VALUE		Auth-Type		Local			0
+VALUE		Auth-Type		System			1
+VALUE		Auth-Type		SecurID			2
+VALUE		Auth-Type		Crypt-Local		3
+VALUE		Auth-Type		Reject			4
+
+#
+#	Cistron extensions
+#
+VALUE		Auth-Type		Pam			253
+VALUE		Auth-Type		Accept			254
+
+#
+#	Experimental Non-Protocol Integer Translations for Cistron-Radiusd
+#
+VALUE		Fall-Through		No			0
+VALUE		Fall-Through		Yes			1
+VALUE		Add-Port-To-IP-Address	No			0
+VALUE		Add-Port-To-IP-Address	Yes			1
+
+#
+#	Configuration Values
+#	uncomment these two lines to turn account expiration on
+#
+
+#VALUE		Server-Config		Password-Expiration	30
+#VALUE		Server-Config		Password-Warning	5
+
diff --git a/src/plugins/vbng/etc/dictionary.ascend b/src/plugins/vbng/etc/dictionary.ascend
new file mode 100644
index 0000000..a02c207
--- /dev/null
+++ b/src/plugins/vbng/etc/dictionary.ascend
@@ -0,0 +1,297 @@
+#
+# Ascend dictionary.
+#
+#		Enable by putting the line "$INCLUDE dictionary.ascend" into
+#		the main dictionary file.
+#
+# Version:	1.00  21-Jul-1997  Jens Glaser <jens@regio.net>
+#
+
+
+#
+#	Ascend specific extensions
+#	Used by ASCEND MAX/Pipeline products
+#
+ATTRIBUTE	Ascend-FCP-Parameter		119	string
+ATTRIBUTE	Ascend-Modem-PortNo		120	integer
+ATTRIBUTE	Ascend-Modem-SlotNo		121	integer
+ATTRIBUTE	Ascend-Modem-ShelfNo		122	integer
+ATTRIBUTE	Ascend-Call-Attempt-Limit	123	integer
+ATTRIBUTE	Ascend-Call-Block-Duration	124	integer
+ATTRIBUTE	Ascend-Maximum-Call-Duration	125	integer
+ATTRIBUTE	Ascend-Temporary-Rtes		126	integer
+ATTRIBUTE       Tunneling-Protocol              127     integer
+ATTRIBUTE       Ascend-Shared-Profile-Enable    128     integer
+ATTRIBUTE	Ascend-Primary-Home-Agent	129	string
+ATTRIBUTE	Ascend-Secondary-Home-Agent	130	string
+ATTRIBUTE	Ascend-Dialout-Allowed		131	integer
+ATTRIBUTE	Ascend-Client-Gateway		132	ipaddr
+ATTRIBUTE	Ascend-BACP-Enable		133	integer
+ATTRIBUTE	Ascend-DHCP-Maximum-Leases	134	integer
+ATTRIBUTE	Ascend-Client-Primary-DNS	135	ipaddr
+ATTRIBUTE	Ascend-Client-Secondary-DNS	136	ipaddr
+ATTRIBUTE	Ascend-Client-Assign-DNS	137	integer
+ATTRIBUTE	Ascend-User-Acct-Type		138	integer
+ATTRIBUTE	Ascend-User-Acct-Host		139	ipaddr
+ATTRIBUTE	Ascend-User-Acct-Port		140	integer
+ATTRIBUTE	Ascend-User-Acct-Key		141	string
+ATTRIBUTE	Ascend-User-Acct-Base		142	integer
+ATTRIBUTE	Ascend-User-Acct-Time		143	integer
+ATTRIBUTE	Ascend-Assign-IP-Client		144	ipaddr
+ATTRIBUTE	Ascend-Assign-IP-Server		145	ipaddr
+ATTRIBUTE	Ascend-Assign-IP-Global-Pool	146	string
+ATTRIBUTE	Ascend-DHCP-Reply		147	integer
+ATTRIBUTE	Ascend-DHCP-Pool-Number		148	integer
+ATTRIBUTE	Ascend-Expect-Callback		149	integer
+ATTRIBUTE	Ascend-Event-Type		150	integer
+ATTRIBUTE	Ascend-Session-Svr-Key		151	string
+ATTRIBUTE	Ascend-Multicast-Rate-Limit	152	integer
+ATTRIBUTE	Ascend-IF-Netmask		153	ipaddr
+ATTRIBUTE	Ascend-Remote-Addr		154	ipaddr
+ATTRIBUTE	Ascend-Multicast-Client		155	integer
+ATTRIBUTE	Ascend-FR-Circuit-Name		156	string
+ATTRIBUTE	Ascend-FR-LinkUp		157	integer
+ATTRIBUTE	Ascend-FR-Nailed-Grp		158	integer
+ATTRIBUTE	Ascend-FR-Type			159	integer
+ATTRIBUTE	Ascend-FR-Link-Mgt		160	integer
+ATTRIBUTE	Ascend-FR-N391			161	integer
+ATTRIBUTE	Ascend-FR-DCE-N392		162	integer
+ATTRIBUTE	Ascend-FR-DTE-N392		163	integer
+ATTRIBUTE	Ascend-FR-DCE-N393		164	integer
+ATTRIBUTE	Ascend-FR-DTE-N393		165	integer
+ATTRIBUTE	Ascend-FR-T391			166	integer
+ATTRIBUTE	Ascend-FR-T392			167	integer
+ATTRIBUTE	Ascend-Bridge-Address  	 	168	string
+ATTRIBUTE       Ascend-TS-Idle-Limit            169     integer
+ATTRIBUTE       Ascend-TS-Idle-Mode             170     integer
+ATTRIBUTE	Ascend-DBA-Monitor	 	171	integer
+ATTRIBUTE	Ascend-Base-Channel-Count 	172	integer
+ATTRIBUTE	Ascend-Minimum-Channels		173	integer
+ATTRIBUTE	Ascend-IPX-Route		174	string
+ATTRIBUTE	Ascend-FT1-Caller		175	integer
+ATTRIBUTE	Ascend-Backup			176	string
+ATTRIBUTE	Ascend-Call-Type		177	integer
+ATTRIBUTE	Ascend-Group			178	string
+ATTRIBUTE	Ascend-FR-DLCI			179	integer
+ATTRIBUTE	Ascend-FR-Profile-Name		180	string
+ATTRIBUTE	Ascend-Ara-PW			181	string
+ATTRIBUTE	Ascend-IPX-Node-Addr		182	string
+ATTRIBUTE	Ascend-Home-Agent-IP-Addr	183	ipaddr
+ATTRIBUTE	Ascend-Home-Agent-Password	184	string
+ATTRIBUTE	Ascend-Home-Network-Name	185	string
+ATTRIBUTE	Ascend-Home-Agent-UDP-Port	186	integer
+ATTRIBUTE	Ascend-Multilink-ID		187	integer
+ATTRIBUTE	Ascend-Num-In-Multilink		188	integer
+ATTRIBUTE	Ascend-First-Dest		189	ipaddr
+ATTRIBUTE	Ascend-Pre-Input-Octets		190	integer
+ATTRIBUTE	Ascend-Pre-Output-Octets	191	integer
+ATTRIBUTE	Ascend-Pre-Input-Packets	192	integer
+ATTRIBUTE	Ascend-Pre-Output-Packets	193	integer
+ATTRIBUTE	Ascend-Maximum-Time		194	integer
+ATTRIBUTE	Ascend-Disconnect-Cause		195	integer
+ATTRIBUTE	Ascend-Connect-Progress		196	integer
+ATTRIBUTE	Ascend-Data-Rate		197	integer
+ATTRIBUTE	Ascend-PreSession-Time		198	integer
+ATTRIBUTE	Ascend-Token-Idle		199	integer
+ATTRIBUTE	Ascend-Token-Immediate		200	integer
+ATTRIBUTE	Ascend-Require-Auth		201	integer
+ATTRIBUTE	Ascend-Number-Sessions		202	string
+ATTRIBUTE	Ascend-Authen-Alias		203	string
+ATTRIBUTE	Ascend-Token-Expiry		204	integer
+ATTRIBUTE	Ascend-Menu-Selector		205	string
+ATTRIBUTE	Ascend-Menu-Item		206	string
+ATTRIBUTE	Ascend-PW-Warntime		207	integer
+ATTRIBUTE	Ascend-PW-Lifetime		208	integer
+ATTRIBUTE	Ascend-IP-Direct		209	ipaddr
+ATTRIBUTE	Ascend-PPP-VJ-Slot-Comp		210	integer
+ATTRIBUTE	Ascend-PPP-VJ-1172		211	integer
+ATTRIBUTE	Ascend-PPP-Async-Map		212	integer
+ATTRIBUTE	Ascend-Third-Prompt		213	string
+ATTRIBUTE	Ascend-Send-Secret		214	string
+ATTRIBUTE	Ascend-Receive-Secret		215	string
+ATTRIBUTE	Ascend-IPX-Peer-Mode		216	integer
+ATTRIBUTE	Ascend-IP-Pool-Definition	217	string
+ATTRIBUTE	Ascend-Assign-IP-Pool		218	integer
+ATTRIBUTE	Ascend-FR-Direct		219	integer
+ATTRIBUTE	Ascend-FR-Direct-Profile	220	string
+ATTRIBUTE	Ascend-FR-Direct-DLCI		221	integer
+ATTRIBUTE	Ascend-Handle-IPX		222	integer
+ATTRIBUTE	Ascend-Netware-timeout		223	integer
+ATTRIBUTE	Ascend-IPX-Alias		224	integer
+ATTRIBUTE	Ascend-Metric			225	integer
+ATTRIBUTE	Ascend-PRI-Number-Type		226	integer
+ATTRIBUTE	Ascend-Dial-Number		227	string
+ATTRIBUTE	Ascend-Route-IP			228	integer
+ATTRIBUTE	Ascend-Route-IPX		229	integer
+ATTRIBUTE	Ascend-Bridge			230	integer
+ATTRIBUTE	Ascend-Send-Auth		231	integer
+ATTRIBUTE	Ascend-Send-Passwd		232	string
+ATTRIBUTE	Ascend-Link-Compression		233	integer
+ATTRIBUTE	Ascend-Target-Util		234	integer
+ATTRIBUTE	Ascend-Maximum-Channels		235	integer
+ATTRIBUTE	Ascend-Inc-Channel-Count	236	integer
+ATTRIBUTE	Ascend-Dec-Channel-Count	237	integer
+ATTRIBUTE	Ascend-Seconds-Of-History	238	integer
+ATTRIBUTE	Ascend-History-Weigh-Type	239	integer
+ATTRIBUTE	Ascend-Add-Seconds		240	integer
+ATTRIBUTE	Ascend-Remove-Seconds		241	integer
+ATTRIBUTE	Ascend-Idle-Limit		244	integer
+ATTRIBUTE	Ascend-Preempt-Limit		245	integer
+ATTRIBUTE	Ascend-Callback			246	integer
+ATTRIBUTE	Ascend-Data-Svc			247	integer
+ATTRIBUTE	Ascend-Force-56			248	integer
+ATTRIBUTE	Ascend-Billing-Number		249	string
+ATTRIBUTE	Ascend-Call-By-Call		250	integer
+ATTRIBUTE	Ascend-Transit-Number		251	string
+ATTRIBUTE	Ascend-Host-Info		252	string
+ATTRIBUTE	Ascend-PPP-Address		253	ipaddr
+ATTRIBUTE	Ascend-MPP-Idle-Percent		254	integer
+ATTRIBUTE	Ascend-Xmit-Rate		255	integer
+
+
+
+# Ascend protocols
+VALUE		Service-Type		Dialout-Framed-User	5
+VALUE		Framed-Protocol		ARA			255
+VALUE		Framed-Protocol		MPP			256
+VALUE		Framed-Protocol		EURAW			257
+VALUE		Framed-Protocol		EUUI			258
+VALUE		Framed-Protocol		X25			259
+VALUE		Framed-Protocol		COMB			260
+VALUE		Framed-Protocol		FR			261
+VALUE		Framed-Protocol		MP			262
+VALUE		Framed-Protocol		FR-CIR			263
+
+
+#
+#	Ascend specific extensions
+#	Used by ASCEND MAX/Pipeline products (see above)
+#
+
+VALUE		Ascend-FR-Direct	FR-Direct-No		0
+VALUE		Ascend-FR-Direct	FR-Direct-Yes		1
+VALUE		Ascend-Handle-IPX	Handle-IPX-None		0
+VALUE		Ascend-Handle-IPX	Handle-IPX-Client	1
+VALUE		Ascend-Handle-IPX	Handle-IPX-Server	2
+VALUE		Ascend-IPX-Peer-Mode	IPX-Peer-Router		0
+VALUE		Ascend-IPX-Peer-Mode	IPX-Peer-Dialin		1
+VALUE		Ascend-Call-Type	Nailed			1
+VALUE		Ascend-Call-Type	Nailed/Mpp		2
+VALUE		Ascend-Call-Type	Perm/Switched		3
+VALUE		Ascend-FT1-Caller	FT1-No			0
+VALUE		Ascend-FT1-Caller	FT1-Yes			1
+VALUE		Ascend-PRI-Number-Type	Unknown-Number		0
+VALUE		Ascend-PRI-Number-Type	Intl-Number		1
+VALUE		Ascend-PRI-Number-Type	National-Number		2
+VALUE		Ascend-PRI-Number-Type	Local-Number		4
+VALUE		Ascend-PRI-Number-Type	Abbrev-Number		5
+VALUE		Ascend-Route-IPX	Route-IPX-No		0
+VALUE		Ascend-Route-IPX	Route-IPX-Yes		1
+VALUE		Ascend-Bridge		Bridge-No		0
+VALUE		Ascend-Bridge		Bridge-Yes		1
+VALUE  		Ascend-TS-Idle-Mode     TS-Idle-None		0
+VALUE	  	Ascend-TS-Idle-Mode     TS-Idle-Input		1
+VALUE  		Ascend-TS-Idle-Mode     TS-Idle-Input-Output	2
+VALUE		Ascend-Send-Auth	Send-Auth-None		0
+VALUE		Ascend-Send-Auth	Send-Auth-PAP		1
+VALUE		Ascend-Send-Auth	Send-Auth-CHAP		2
+VALUE		Ascend-Send-Auth	Send-Auth-MS-CHAP	3
+VALUE		Ascend-Link-Compression	Link-Comp-None		0
+VALUE		Ascend-Link-Compression	Link-Comp-Stac		1
+VALUE		Ascend-Link-Compression	Link-Comp-Stac-Draft-9	2
+VALUE		Ascend-Link-Compression	Link-Comp-MS-Stac	3
+VALUE		Ascend-History-Weigh-Type	History-Constant	0
+VALUE		Ascend-History-Weigh-Type	History-Linear		1
+VALUE		Ascend-History-Weigh-Type	History-Quadratic	2
+VALUE		Ascend-Callback		Callback-No		0
+VALUE		Ascend-Callback		Callback-Yes		1
+VALUE		Ascend-Expect-Callback	Expect-Callback-No	0
+VALUE		Ascend-Expect-Callback	Expect-Callback-Yes	1
+VALUE		Ascend-Data-Svc		Switched-Voice-Bearer	0
+VALUE		Ascend-Data-Svc		Switched-56KR		1
+VALUE		Ascend-Data-Svc		Switched-64K		2
+VALUE		Ascend-Data-Svc		Switched-64KR		3
+VALUE		Ascend-Data-Svc		Switched-56K		4
+VALUE		Ascend-Data-Svc		Switched-384KR		5
+VALUE		Ascend-Data-Svc		Switched-384K		6
+VALUE		Ascend-Data-Svc		Switched-1536K		7
+VALUE		Ascend-Data-Svc		Switched-1536KR		8
+VALUE		Ascend-Data-Svc		Switched-128K		9
+VALUE		Ascend-Data-Svc		Switched-192K		10
+VALUE		Ascend-Data-Svc		Switched-256K		11
+VALUE		Ascend-Data-Svc		Switched-320K		12
+VALUE		Ascend-Data-Svc		Switched-384K-MR	13
+VALUE		Ascend-Data-Svc		Switched-448K		14
+VALUE		Ascend-Data-Svc		Switched-512K		15
+VALUE		Ascend-Data-Svc		Switched-576K		16
+VALUE		Ascend-Data-Svc		Switched-640K		17
+VALUE		Ascend-Data-Svc		Switched-704K		18
+VALUE		Ascend-Data-Svc		Switched-768K		19
+VALUE		Ascend-Data-Svc		Switched-832K		20
+VALUE		Ascend-Data-Svc		Switched-896K		21
+VALUE		Ascend-Data-Svc		Switched-960K		22
+VALUE		Ascend-Data-Svc		Switched-1024K		23
+VALUE		Ascend-Data-Svc		Switched-1088K		24
+VALUE		Ascend-Data-Svc		Switched-1152K		25
+VALUE		Ascend-Data-Svc		Switched-1216K		26
+VALUE		Ascend-Data-Svc		Switched-1280K		27
+VALUE		Ascend-Data-Svc		Switched-1344K		28
+VALUE		Ascend-Data-Svc		Switched-1408K		29
+VALUE		Ascend-Data-Svc		Switched-1472K		30
+VALUE		Ascend-Data-Svc		Switched-1600K		31
+VALUE		Ascend-Data-Svc		Switched-1664K		32
+VALUE		Ascend-Data-Svc		Switched-1728K		33
+VALUE		Ascend-Data-Svc		Switched-1792K		34
+VALUE		Ascend-Data-Svc		Switched-1856K		35
+VALUE		Ascend-Data-Svc		Switched-1920K		36
+VALUE		Ascend-Data-Svc		Switched-inherited		37
+VALUE		Ascend-Data-Svc		Switched-restricted-bearer-x30  38
+VALUE		Ascend-Data-Svc		Switched-clear-bearer-v110	39
+VALUE		Ascend-Data-Svc		Switched-restricted-64-x30	40
+VALUE		Ascend-Data-Svc		Switched-clear-56-v110		41
+VALUE		Ascend-Data-Svc		Switched-modem			42
+VALUE		Ascend-Data-Svc		Switched-atmodem		43
+VALUE		Ascend-Data-Svc		Nailed-56KR		1
+VALUE		Ascend-Data-Svc		Nailed-64K		2
+VALUE		Ascend-Force-56		Force-56-No		0
+VALUE		Ascend-Force-56		Force-56-Yes		1
+VALUE		Ascend-PW-Lifetime	Lifetime-In-Days	0
+VALUE		Ascend-PW-Warntime	Days-Of-Warning		0
+VALUE		Ascend-PPP-VJ-1172	PPP-VJ-1172		1
+VALUE		Ascend-PPP-VJ-Slot-Comp	VJ-Slot-Comp-No		1
+VALUE		Ascend-Require-Auth	Not-Require-Auth	0
+VALUE		Ascend-Require-Auth	Require-Auth		1
+VALUE		Ascend-Token-Immediate	Tok-Imm-No		0
+VALUE		Ascend-Token-Immediate	Tok-Imm-Yes		1
+VALUE		Ascend-DBA-Monitor		DBA-Transmit		0
+VALUE 		Ascend-DBA-Monitor	DBA-Transmit-Recv	1
+VALUE		Ascend-DBA-Monitor	DBA-None		2
+VALUE		Ascend-FR-Type		Ascend-FR-DTE		0
+VALUE		Ascend-FR-Type		Ascend-FR-DCE		1
+VALUE		Ascend-FR-Type		Ascend-FR-NNI		2
+VALUE		Ascend-FR-Link-Mgt	Ascend-FR-No-Link-Mgt	0
+VALUE		Ascend-FR-Link-Mgt	Ascend-FR-T1-617D	1
+VALUE		Ascend-FR-Link-Mgt	Ascend-FR-Q-933A	2
+VALUE		Ascend-FR-LinkUp	Ascend-LinkUp-Default	0
+VALUE		Ascend-FR-LinkUp	Ascend-LinkUp-AlwaysUp	1
+VALUE		Ascend-Multicast-Client	Multicast-No		0
+VALUE		Ascend-Multicast-Client	Multicast-Yes		1
+VALUE		Ascend-User-Acct-Type	Ascend-User-Acct-None	0
+VALUE		Ascend-User-Acct-Type	Ascend-User-Acct-User	1
+VALUE		Ascend-User-Acct-Type	Ascend-User-Acct-User-Default	2
+VALUE		Ascend-User-Acct-Base	Base-10			0
+VALUE		Ascend-User-Acct-Base	Base-16			1
+VALUE		Ascend-DHCP-Reply	DHCP-Reply-No		0
+VALUE		Ascend-DHCP-Reply	DHCP-Reply-Yes		1
+VALUE		Ascend-Client-Assign-DNS	DNS-Assign-No		0
+VALUE		Ascend-Client-Assign-DNS	DNS-Assign-Yes		1
+VALUE		Ascend-Event-Type	Ascend-ColdStart	1
+VALUE		Ascend-Event-Type	Ascend-Session-Event	2
+VALUE		Ascend-BACP-Enable	BACP-No			0
+VALUE		Ascend-BACP-Enable	BACP-Yes		1
+VALUE		Ascend-Dialout-Allowed	Dialout-Not-Allowed	0
+VALUE		Ascend-Dialout-Allowed	Dialout-Allowed		1
+VALUE		Ascend-Shared-Profile-Enable    Shared-Profile-No       0
+VALUE		Ascend-Shared-Profile-Enable    Shared-Profile-Yes      1
+VALUE		Ascend-Temporary-Rtes	Temp-Rtes-No		0
+VALUE		Ascend-Temporary-Rtes	Temp-Rtes-Yes		1
diff --git a/src/plugins/vbng/etc/dictionary.compat b/src/plugins/vbng/etc/dictionary.compat
new file mode 100644
index 0000000..4c85ea8
--- /dev/null
+++ b/src/plugins/vbng/etc/dictionary.compat
@@ -0,0 +1,47 @@
+#
+#	Obsolete names for backwards compatibility with older users files.
+#	Move the $INCLUDE in the main dictionary file to the end if you want
+#	these names to be used in the "details" logfile.
+#
+ATTRIBUTE	Client-Id		4	ipaddr
+ATTRIBUTE	Client-Port-Id		5	integer
+ATTRIBUTE	User-Service-Type	6	integer
+ATTRIBUTE	Framed-Address		8	ipaddr
+ATTRIBUTE	Framed-Netmask		9	ipaddr
+ATTRIBUTE	Framed-Filter-Id	11	string
+ATTRIBUTE	Login-Host		14	ipaddr
+ATTRIBUTE	Login-Port		16	integer
+ATTRIBUTE	Old-Password		17	string
+ATTRIBUTE	Port-Message		18	string
+ATTRIBUTE	Dialback-No		19	string
+ATTRIBUTE	Dialback-Name		20	string
+ATTRIBUTE	Challenge-State		24	string
+VALUE		Framed-Compression	Van-Jacobsen-TCP-IP	1
+VALUE		Framed-Compression	VJ-TCP-IP		1
+VALUE		Service-Type		Shell-User		6
+VALUE		Auth-Type		Unix			1
+VALUE		Service-Type		Dialback-Login-User	3
+VALUE		Service-Type		Dialback-Framed-User	4
+
+#
+#	For compatibility with MERIT users files.
+#
+ATTRIBUTE	NAS-Port		5	integer
+ATTRIBUTE	Login-Host		14	ipaddr
+ATTRIBUTE	Login-Callback-Number	19	string
+ATTRIBUTE	Framed-Callback-Id	20	string
+ATTRIBUTE	Client-Port-DNIS	30	string
+ATTRIBUTE	Caller-ID		31	string
+VALUE		Service-Type		Login			1
+VALUE		Service-Type		Framed			2
+VALUE		Service-Type		Callback-Login		3
+VALUE		Service-Type		Callback-Framed		4
+VALUE		Service-Type		Exec-User		7
+
+#
+#	For compatibility with ESVA RADIUS, Old Cistron RADIUS
+#
+ATTRIBUTE	Session			1034	integer
+ATTRIBUTE	User-Name-Is-Star	1035	integer
+VALUE		User-Name-Is-Star	No			0
+VALUE		User-Name-Is-Star	Yes			1
diff --git a/src/plugins/vbng/etc/dictionary.dhcp b/src/plugins/vbng/etc/dictionary.dhcp
new file mode 100644
index 0000000..cf32934
--- /dev/null
+++ b/src/plugins/vbng/etc/dictionary.dhcp
@@ -0,0 +1,440 @@
+# -*- text -*-
+# Copyright (C) 2011 The FreeRADIUS Server project and contributors
+##############################################################################
+#
+#	DHCP to RADUS gateway dictionary.
+#
+#	http://www.iana.org/assignments/bootp-dhcp-parameters
+#
+#	Also http://www.networksorcery.com/enp/protocol/bootp/options.htm
+#
+#	http://www.bind9.net/rfc-dhcp
+#
+#	$Id: 73632c57d3860bb30749a1df4dad2320d5f79f31 $
+#
+##############################################################################
+
+#
+
+#	This is really Apollo's number, but since they're out of business,
+#	I don't think they'll be needing this.
+#
+#	HP owns the Apollo assets, but let's not worry about that.
+#
+#	The vendor codes are 2 octets, because we need 256 numbers
+#	for the base DHCP options, PLUS a few for the DHCP headers,
+#	which aren't in option format.
+#
+#	On top of that, a number of options are really TLV's.
+#	We need to be able to understand them, too.
+#
+VENDOR		DHCP				54	format=2,1
+
+BEGIN-VENDOR	DHCP
+
+ATTRIBUTE	DHCP-Opcode				256	byte
+ATTRIBUTE	DHCP-Hardware-Type			257	byte
+ATTRIBUTE	DHCP-Hardware-Address-Length		258	byte
+ATTRIBUTE	DHCP-Hop-Count				259	byte
+ATTRIBUTE	DHCP-Transaction-Id			260	integer
+ATTRIBUTE	DHCP-Number-of-Seconds			261	short
+ATTRIBUTE	DHCP-Flags				262	short
+ATTRIBUTE	DHCP-Client-IP-Address			263	ipaddr
+ATTRIBUTE	DHCP-Your-IP-Address			264	ipaddr
+ATTRIBUTE	DHCP-Server-IP-Address			265	ipaddr
+ATTRIBUTE	DHCP-Gateway-IP-Address			266	ipaddr
+ATTRIBUTE	DHCP-Client-Hardware-Address		267	ether	  # 16 octets
+ATTRIBUTE	DHCP-Server-Host-Name			268	string	  # 64 octets
+ATTRIBUTE	DHCP-Boot-Filename			269	string	  # 128 octets
+
+ATTRIBUTE	DHCP-Relay-To-IP-Address		270	ipaddr
+ATTRIBUTE	DHCP-Relay-Max-Hop-Count		271	integer
+
+# This is copied from the request packet, giaddr, and
+# added to the reply packet by the server core.
+ATTRIBUTE	DHCP-Relay-IP-Address			272	ipaddr
+
+VALUE	DHCP-Flags			Broadcast		0x8000
+
+VALUE	DHCP-Hardware-Type		Ethernet		1
+VALUE	DHCP-Hardware-Type		Experiemental-Ethernet	2
+VALUE	DHCP-Hardware-Type		AX.25			3
+VALUE	DHCP-Hardware-Type		Proteon-Token-Ring	4
+VALUE	DHCP-Hardware-Type		Chaos			5
+VALUE	DHCP-Hardware-Type		IEEE-802		6
+VALUE	DHCP-Hardware-Type		Arcnet			7
+VALUE	DHCP-Hardware-Type		Hyperchannel		8
+VALUE	DHCP-Hardware-Type		Lanstar			9
+VALUE	DHCP-Hardware-Type		Autonet-Short-Address	10
+VALUE	DHCP-Hardware-Type		LocalTalk		11
+VALUE	DHCP-Hardware-Type		LocalNet		12
+VALUE	DHCP-Hardware-Type		Ultra-Link		13
+VALUE	DHCP-Hardware-Type		SMDS			14
+VALUE	DHCP-Hardware-Type		Frame-Relay		15
+VALUE	DHCP-Hardware-Type		ATM-16			16
+VALUE	DHCP-Hardware-Type		HDLC			17
+VALUE	DHCP-Hardware-Type		Fibre-Channel		18
+VALUE	DHCP-Hardware-Type		ATM-19			19
+VALUE	DHCP-Hardware-Type		Serial-Line		20
+VALUE	DHCP-Hardware-Type		ATM-21			21
+VALUE	DHCP-Hardware-Type		MIL-STD-188-220		22
+VALUE	DHCP-Hardware-Type		Metricom		23
+VALUE	DHCP-Hardware-Type		IEEE-1394		24
+VALUE	DHCP-Hardware-Type		MAPOS			25
+VALUE	DHCP-Hardware-Type		Twinaxial		26
+VALUE	DHCP-Hardware-Type		EUI-64			27
+VALUE	DHCP-Hardware-Type		HIPARP			28
+VALUE	DHCP-Hardware-Type		IP-Over-ISO-7816-3	29
+VALUE	DHCP-Hardware-Type		ARPSec			30
+VALUE	DHCP-Hardware-Type		IPSec-Tunnel		31
+VALUE	DHCP-Hardware-Type		Infiniband		32
+VALUE	DHCP-Hardware-Type		CAI-TIA-102		33
+
+##############################################################################
+#
+#	DHCP Options, with comments.  For now, many are "octets",
+#	as FreeRADIUS doesn't handle complex data structures.
+#
+##############################################################################
+
+#ATTRIBUTE	DHCP-Pad				0	octets
+ATTRIBUTE	DHCP-Subnet-Mask			1	ipaddr
+# Time Offset in twos-complement notation.
+ATTRIBUTE	DHCP-Time-Offset			2	integer
+ATTRIBUTE	DHCP-Router-Address			3	ipaddr array
+ATTRIBUTE	DHCP-Time-Server			4	ipaddr array
+ATTRIBUTE	DHCP-IEN-116-Name-Server		5	ipaddr array
+ATTRIBUTE	DHCP-Domain-Name-Server			6	ipaddr array
+# Logging-Server addresses
+ATTRIBUTE	DHCP-Log-Server				7	ipaddr array
+ATTRIBUTE	DHCP-Quotes-Server			8	ipaddr array
+ATTRIBUTE	DHCP-LPR-Server				9	ipaddr array
+ATTRIBUTE	DHCP-Impress-Server			10	ipaddr array
+ATTRIBUTE	DHCP-RLP-Server				11	ipaddr array
+# Hostname string
+ATTRIBUTE	DHCP-Hostname				12	string
+# Size of boot file in 512 byte
+ATTRIBUTE	DHCP-Boot-File-Size			13	short
+# Client to dump and name
+ATTRIBUTE	DHCP-Merit-Dump-File			14	octets
+ATTRIBUTE	DHCP-Domain-Name			15	string
+ATTRIBUTE	DHCP-Swap-Server			16	ipaddr
+# Path name for root disk
+ATTRIBUTE	DHCP-Root-Path				17	string
+ATTRIBUTE	DHCP-Bootp-Extensions-Path		18	string
+ATTRIBUTE	DHCP-IP-Forward-Enable			19	byte
+ATTRIBUTE	DHCP-Source-Route-Enable		20	byte
+# Routing Policy Filters
+ATTRIBUTE	DHCP-Policy-Filter			21	octets
+ATTRIBUTE	DHCP-Max-Datagram-Reassembly-Sz		22	short
+ATTRIBUTE	DHCP-Default-IP-TTL			23	octets
+ATTRIBUTE	DHCP-Path-MTU-Aging-Timeout		24	integer
+ATTRIBUTE	DHCP-Path-MTU-Plateau-Table		25	short array
+ATTRIBUTE	DHCP-Interface-MTU-Size			26	short
+ATTRIBUTE	DHCP-All-Subnets-Are-Local		27	byte
+ATTRIBUTE	DHCP-Broadcast-Address			28	ipaddr
+ATTRIBUTE	DHCP-Perform-Mask-Discovery		29	byte
+ATTRIBUTE	DHCP-Provide-Mask-To-Others		30	byte
+ATTRIBUTE	DHCP-Perform-Router-Discovery		31	byte
+ATTRIBUTE	DHCP-Router-Solicitation-Address	32	ipaddr
+# first is destination address, second is router.
+ATTRIBUTE	DHCP-Static-Routes			33	ipaddr array
+ATTRIBUTE	DHCP-Trailer-Encapsulation		34	byte
+ATTRIBUTE	DHCP-ARP-Cache-Timeout			35	integer
+ATTRIBUTE	DHCP-Ethernet-Encapsulation		36	byte
+ATTRIBUTE	DHCP-Default-TCP-TTL			37	byte
+ATTRIBUTE	DHCP-Keep-Alive-Interval		38	integer
+ATTRIBUTE	DHCP-Keep-Alive-Garbage			39	byte
+ATTRIBUTE	DHCP-NIS-Domain-Name			40	string
+ATTRIBUTE	DHCP-NIS-Servers			41	ipaddr array
+ATTRIBUTE	DHCP-NTP-Servers			42	ipaddr array
+# N Vendor Specific Information
+ATTRIBUTE	DHCP-Vendor				43	octets # tlv
+ATTRIBUTE	DHCP-NETBIOS-Name-Servers		44	ipaddr array
+ATTRIBUTE	DHCP-NETBIOS-Dgm-Dist-Servers		45	ipaddr array
+ATTRIBUTE	DHCP-NETBIOS-Node-Type			46	byte
+# N NETBIOS Scope
+ATTRIBUTE	DHCP-NETBIOS				47	octets
+ATTRIBUTE	DHCP-X-Window-Font-Server		48	ipaddr array
+ATTRIBUTE	DHCP-X-Window-Display-Mgr		49	ipaddr array
+ATTRIBUTE	DHCP-Requested-IP-Address		50	ipaddr
+ATTRIBUTE	DHCP-IP-Address-Lease-Time		51	integer
+# Overload "sname" or "file"
+ATTRIBUTE	DHCP-Overload				52	byte
+ATTRIBUTE	DHCP-Message-Type			53	byte
+ATTRIBUTE	DHCP-DHCP-Server-Identifier		54	ipaddr
+
+# Array of 1-byte numbers indicating which options the client
+# would like to see in the response.
+ATTRIBUTE	DHCP-Parameter-Request-List		55	byte array
+ATTRIBUTE	DHCP-DHCP-Error-Message			56	octets
+ATTRIBUTE	DHCP-DHCP-Maximum-Msg-Size		57	short
+ATTRIBUTE	DHCP-Renewal-Time			58	integer
+ATTRIBUTE	DHCP-Rebinding-Time			59	integer
+ATTRIBUTE	DHCP-Vendor-Class-Identifier		60	string
+
+# Client Identifier
+# First octets is DHCP-Hardware-Type, rest are type-specific data,
+# e.g. MAC address.
+ATTRIBUTE	DHCP-Client-Identifier			61	ether
+ATTRIBUTE	DHCP-Netware-Domain-Name		62	octets
+ATTRIBUTE	DHCP-Netware-Sub-Options		63	octets
+ATTRIBUTE	DHCP-NIS-Client-Domain-Name		64	octets
+ATTRIBUTE	DHCP-NIS-Server-Address			65	ipaddr
+ATTRIBUTE	DHCP-TFTP-Server-Name			66	string
+ATTRIBUTE	DHCP-Boot-File-Name			67	string
+# Home Agent Addresses
+ATTRIBUTE	DHCP-Home-Agent-Address			68	octets
+ATTRIBUTE	DHCP-SMTP-Server-Address		69	ipaddr array
+ATTRIBUTE	DHCP-POP3-Server-Address		70	ipaddr array
+ATTRIBUTE	DHCP-NNTP-Server-Address		71	ipaddr array
+ATTRIBUTE	DHCP-WWW-Server-Address			72	ipaddr array
+ATTRIBUTE	DHCP-Finger-Server-Address		73	ipaddr array
+ATTRIBUTE	DHCP-IRC-Server-Address			74	ipaddr array
+ATTRIBUTE	DHCP-StreetTalk-Server-Address		75	ipaddr array
+ATTRIBUTE	DHCP-STDA-Server-Address		76	ipaddr array
+# User Class Information
+ATTRIBUTE	DHCP-User-Class				77	octets
+# directory agent information
+ATTRIBUTE	DHCP-Directory-Agent			78	octets
+# service location agent scope
+ATTRIBUTE	DHCP-Service-Scope			79	octets
+# Rapid Commit
+ATTRIBUTE	DHCP-Rapid-Commit			80	octets
+# Fully Qualified Domain Name
+ATTRIBUTE	DHCP-Client-FQDN			81	string
+# Relay Agent Information
+ATTRIBUTE	DHCP-Relay-Agent-Information		82	tlv
+
+ATTRIBUTE	DHCP-Agent-Circuit-Id			82.1	octets
+ATTRIBUTE	DHCP-Agent-Remote-Id			82.2	octets
+
+ATTRIBUTE	DHCP-Relay-Circuit-Id			82.1	octets
+ATTRIBUTE	DHCP-Relay-Remote-Id			82.2	octets
+
+# 3 is reserved and shouldn't be used for anything
+ATTRIBUTE	DHCP-Docsis-Device-Class		82.4	integer
+ATTRIBUTE	DHCP-Relay-Link-Selection		82.5	ipaddr
+ATTRIBUTE	DHCP-Subscriber-Id			82.6	string
+
+# AGH!  RADIUS inside of DHCP!
+ATTRIBUTE	DHCP-RADIUS-Attributes			82.7	octets
+
+# Horribly complicated
+ATTRIBUTE	DHCP-Authentication-Information		82.8	octets
+ATTRIBUTE	DHCP-Vendor-Specific-Information	82.9	octets
+ATTRIBUTE	DHCP-Relay-Agent-Flags			82.10	byte
+ATTRIBUTE	DHCP-Server-Identifier-Override		82.11	ipaddr
+
+# Internet Storage Name Service
+ATTRIBUTE	DHCP-iSNS				83	octets
+# Novell Directory Services
+ATTRIBUTE	DHCP-NDS-Servers			85	octets
+# Novell Directory Services
+ATTRIBUTE	DHCP-NDS-Tree-Name			86	octets
+# Novell Directory Services
+ATTRIBUTE	DHCP-NDS-Context			87	octets
+# Authentication
+ATTRIBUTE	DHCP-Authentication			90	octets
+
+ATTRIBUTE	DHCP-Client-Last-Txn-Time		91	octets
+
+ATTRIBUTE	DHCP-associated-ip			92	octets
+# Client System Architecture
+ATTRIBUTE	DHCP-Client-System			93	octets
+# Client Network Device Interface
+ATTRIBUTE	DHCP-Client-NDI				94	octets
+# Lightweight Directory Access Protocol
+ATTRIBUTE	DHCP-LDAP				95	octets
+# UUID/GUID-based Client Identifier
+ATTRIBUTE	DHCP-UUID/GUID				97	octets
+# Open Group's User Authentication
+ATTRIBUTE	DHCP-User-Auth				98	octets
+# NetInfo Parent-Server Address
+ATTRIBUTE	DHCP-Netinfo-Address			112	octets
+# NetInfo Parent-Server Tag
+ATTRIBUTE	DHCP-Netinfo-Tag			113	octets
+# URL
+ATTRIBUTE	DHCP-URL				114	octets
+# DHCP Auto-Configuration
+ATTRIBUTE	DHCP-Auto-Config			116	byte
+# Name Service Search
+ATTRIBUTE	DHCP-Name-Service-Search		117	octets
+# Subnet Selection Option
+ATTRIBUTE	DHCP-Subnet-Selection-Option		118	octets
+# DNS domain serach list
+ATTRIBUTE	DHCP-Domain-Search			119	octets
+# SIP-Servers DHCP Option
+ATTRIBUTE	DHCP-SIP-Servers-DHCP-Option		120	octets
+# Classless Static Route Option
+ATTRIBUTE	DHCP-Classless-Static-Route		121	octets
+# CableLabs Client Configuration
+ATTRIBUTE	DHCP-CCC				122	octets
+# 16 GeoConf Option
+ATTRIBUTE	DHCP-GeoConf-Option			123	octets
+
+# Vendor Class
+#
+# String name that defines the vendor space used for the TLV's
+# in option 125.
+#
+ATTRIBUTE	DHCP-V-I-Vendor-Class			124	octets
+# Vendor-Specific
+ATTRIBUTE	DHCP-V-I-Vendor-Specific		125	octets # tlv
+ATTRIBUTE	DHCP-Etherboot				128	ether
+# (for IP Phone software load)
+ATTRIBUTE	DHCP-TFTP-Server-IP-Address		128	octets
+
+ATTRIBUTE	DHCP-Call-Server-IP-address		129	octets
+
+ATTRIBUTE	DHCP-Ethernet-Interface			130	octets
+
+ATTRIBUTE	DHCP-Vendor-Discrimination-Str		130	octets
+
+ATTRIBUTE	DHCP-Remote-Stats-Svr-IP-Address	131	octets
+
+ATTRIBUTE	DHCP-IEEE-802.1Q-L2-Priority		132	octets
+
+ATTRIBUTE	DHCP-IEEE-802.1P-VLAN-ID		133	octets
+
+ATTRIBUTE	DHCP-Diffserv-Code-Point		134	octets
+
+ATTRIBUTE	DHCP-HTTP-Proxy				135	octets
+
+ATTRIBUTE	DHCP-Cisco-TFTP-Server-IP-Addresses	150	ipaddr array
+
+ATTRIBUTE	DHCP-End-Of-Options			255	byte
+
+VALUE	DHCP-Opcode			Client-Message		1
+VALUE	DHCP-Opcode			Server-Message		2
+
+VALUE	DHCP-Message-Type		DHCP-Do-Not-Respond	0
+VALUE	DHCP-Message-Type		DHCP-Discover		1
+VALUE	DHCP-Message-Type		DHCP-Offer		2
+VALUE	DHCP-Message-Type		DHCP-Request		3
+VALUE	DHCP-Message-Type		DHCP-Decline		4
+VALUE	DHCP-Message-Type		DHCP-Ack		5
+VALUE	DHCP-Message-Type		DHCP-NAK		6
+VALUE	DHCP-Message-Type		DHCP-Release		7
+VALUE	DHCP-Message-Type		DHCP-Inform		8
+VALUE	DHCP-Message-Type		DHCP-Force-Renew	9
+
+VALUE	DHCP-Parameter-Request-List	DHCP-Subnet-Mask	1
+VALUE	DHCP-Parameter-Request-List	DHCP-Time-Offset	2
+VALUE	DHCP-Parameter-Request-List	DHCP-Router-Address	3
+VALUE	DHCP-Parameter-Request-List	DHCP-Time-Server	4
+VALUE	DHCP-Parameter-Request-List	DHCP-IEN-116-Name-Server 5
+VALUE	DHCP-Parameter-Request-List	DHCP-Domain-Name-Server	6
+VALUE	DHCP-Parameter-Request-List	DHCP-Log-Server		7
+VALUE	DHCP-Parameter-Request-List	DHCP-Quotes-Server	8
+VALUE	DHCP-Parameter-Request-List	DHCP-LPR-Server		9
+VALUE	DHCP-Parameter-Request-List	DHCP-Impress-Server	10
+VALUE	DHCP-Parameter-Request-List	DHCP-RLP-Server		11
+VALUE	DHCP-Parameter-Request-List	DHCP-Hostname		12
+VALUE	DHCP-Parameter-Request-List	DHCP-Boot-File-Size	13
+VALUE	DHCP-Parameter-Request-List	DHCP-Merit-Dump-File	14
+VALUE	DHCP-Parameter-Request-List	DHCP-Domain-Name	15
+VALUE	DHCP-Parameter-Request-List	DHCP-Swap-Server	16
+VALUE	DHCP-Parameter-Request-List	DHCP-Root-Path		17
+VALUE	DHCP-Parameter-Request-List	DHCP-Bootp-Extensions-Path 18
+VALUE	DHCP-Parameter-Request-List	DHCP-IP-Forward-Enable	19
+VALUE	DHCP-Parameter-Request-List	DHCP-Source-Route-Enable 20
+VALUE	DHCP-Parameter-Request-List	DHCP-Policy-Filter	21
+VALUE	DHCP-Parameter-Request-List	DHCP-Max-Datagram-Reassembly-Sz 22
+VALUE	DHCP-Parameter-Request-List	DHCP-Default-IP-TTL	23
+VALUE	DHCP-Parameter-Request-List	DHCP-Path-MTU-Aging-Timeout 24
+VALUE	DHCP-Parameter-Request-List	DHCP-Path-MTU-Plateau-Table 25
+VALUE	DHCP-Parameter-Request-List	DHCP-Interface-MTU-Size	26
+VALUE	DHCP-Parameter-Request-List	DHCP-All-Subnets-Are-Local 27
+VALUE	DHCP-Parameter-Request-List	DHCP-Broadcast-Address	28
+VALUE	DHCP-Parameter-Request-List	DHCP-Perform-Mask-Discovery 29
+VALUE	DHCP-Parameter-Request-List	DHCP-Provide-Mask-To-Others 30
+VALUE	DHCP-Parameter-Request-List	DHCP-Perform-Router-Discovery 31
+VALUE	DHCP-Parameter-Request-List	DHCP-Router-Solicitation-Address 32
+VALUE	DHCP-Parameter-Request-List	DHCP-Static-Routes	33
+VALUE	DHCP-Parameter-Request-List	DHCP-Trailer-Encapsulation 34
+VALUE	DHCP-Parameter-Request-List	DHCP-ARP-Cache-Timeout	35
+VALUE	DHCP-Parameter-Request-List	DHCP-Ethernet-Encapsulation 36
+VALUE	DHCP-Parameter-Request-List	DHCP-Default-TCP-TTL	37
+VALUE	DHCP-Parameter-Request-List	DHCP-Keep-Alive-Interval 38
+VALUE	DHCP-Parameter-Request-List	DHCP-Keep-Alive-Garbage	39
+VALUE	DHCP-Parameter-Request-List	DHCP-NIS-Domain-Name	40
+VALUE	DHCP-Parameter-Request-List	DHCP-NIS-Servers	41
+VALUE	DHCP-Parameter-Request-List	DHCP-NTP-Servers	42
+VALUE	DHCP-Parameter-Request-List	DHCP-Vendor		43
+VALUE	DHCP-Parameter-Request-List	DHCP-NETBIOS-Name-Servers 44
+VALUE	DHCP-Parameter-Request-List	DHCP-NETBIOS-Dgm-Dist-Servers 45
+VALUE	DHCP-Parameter-Request-List	DHCP-NETBIOS-Node-Type	46
+VALUE	DHCP-Parameter-Request-List	DHCP-NETBIOS		47
+VALUE	DHCP-Parameter-Request-List	DHCP-X-Window-Font-Server 48
+VALUE	DHCP-Parameter-Request-List	DHCP-X-Window-Display-Mgr 49
+VALUE	DHCP-Parameter-Request-List	DHCP-Requested-IP-Address 50
+VALUE	DHCP-Parameter-Request-List	DHCP-IP-Address-Lease-Time 51
+VALUE	DHCP-Parameter-Request-List	DHCP-Overload		52
+VALUE	DHCP-Parameter-Request-List	DHCP-Message-Type	53
+VALUE	DHCP-Parameter-Request-List	DHCP-DHCP-Server-Identifier 54
+VALUE	DHCP-Parameter-Request-List	DHCP-Parameter-Request-List 55
+VALUE	DHCP-Parameter-Request-List	DHCP-DHCP-Error-Message	56
+VALUE	DHCP-Parameter-Request-List	DHCP-DHCP-Maximum-Msg-Size 57
+VALUE	DHCP-Parameter-Request-List	DHCP-Renewal-Time	58
+VALUE	DHCP-Parameter-Request-List	DHCP-Rebinding-Time	59
+VALUE	DHCP-Parameter-Request-List	DHCP-Class-Identifier	60
+VALUE	DHCP-Parameter-Request-List	DHCP-Client-Identifier	61
+VALUE	DHCP-Parameter-Request-List	DHCP-Netware-Domain-Name 62
+VALUE	DHCP-Parameter-Request-List	DHCP-Netware-Sub-Options 63
+VALUE	DHCP-Parameter-Request-List	DHCP-NIS-Client-Domain-Name 64
+VALUE	DHCP-Parameter-Request-List	DHCP-NIS-Server-Address	65
+VALUE	DHCP-Parameter-Request-List	DHCP-TFTP-Server-Name	66
+VALUE	DHCP-Parameter-Request-List	DHCP-Boot-File-Name	67
+VALUE	DHCP-Parameter-Request-List	DHCP-Home-Agent-Address	68
+VALUE	DHCP-Parameter-Request-List	DHCP-SMTP-Server-Address 69
+VALUE	DHCP-Parameter-Request-List	DHCP-POP3-Server-Address 70
+VALUE	DHCP-Parameter-Request-List	DHCP-NNTP-Server-Address 71
+VALUE	DHCP-Parameter-Request-List	DHCP-WWW-Server-Address	72
+VALUE	DHCP-Parameter-Request-List	DHCP-Finger-Server-Address 73
+VALUE	DHCP-Parameter-Request-List	DHCP-IRC-Server-Address	74
+VALUE	DHCP-Parameter-Request-List	DHCP-StreetTalk-Server-Address 75
+VALUE	DHCP-Parameter-Request-List	DHCP-STDA-Server-Address 76
+VALUE	DHCP-Parameter-Request-List	DHCP-User-Class		77
+VALUE	DHCP-Parameter-Request-List	DHCP-Directory-Agent	78
+VALUE	DHCP-Parameter-Request-List	DHCP-Service-Scope	79
+VALUE	DHCP-Parameter-Request-List	DHCP-Rapid-Commit	80
+VALUE	DHCP-Parameter-Request-List	DHCP-Client-FQDN	81
+VALUE	DHCP-Parameter-Request-List	DHCP-Relay-Agent-Information 82
+VALUE	DHCP-Parameter-Request-List	DHCP-iSNS		83
+VALUE	DHCP-Parameter-Request-List	DHCP-NDS-Servers	85
+VALUE	DHCP-Parameter-Request-List	DHCP-NDS-Tree-Name	86
+VALUE	DHCP-Parameter-Request-List	DHCP-NDS-Context	87
+VALUE	DHCP-Parameter-Request-List	DHCP-Authentication	90
+VALUE	DHCP-Parameter-Request-List	DHCP-Client-Last-Txn-Time 91
+VALUE	DHCP-Parameter-Request-List	DHCP-associated-ip	92
+VALUE	DHCP-Parameter-Request-List	DHCP-Client-System	93
+VALUE	DHCP-Parameter-Request-List	DHCP-Client-NDI		94
+VALUE	DHCP-Parameter-Request-List	DHCP-LDAP		95
+VALUE	DHCP-Parameter-Request-List	DHCP-UUID/GUID		97
+VALUE	DHCP-Parameter-Request-List	DHCP-User-Auth		98
+VALUE	DHCP-Parameter-Request-List	DHCP-Netinfo-Address	112
+VALUE	DHCP-Parameter-Request-List	DHCP-Netinfo-Tag	113
+VALUE	DHCP-Parameter-Request-List	DHCP-URL		114
+VALUE	DHCP-Parameter-Request-List	DHCP-Auto-Config	116
+VALUE	DHCP-Parameter-Request-List	DHCP-Name-Service-Search 117
+VALUE	DHCP-Parameter-Request-List	DHCP-Subnet-Selection-Option 118
+VALUE	DHCP-Parameter-Request-List	DHCP-Domain-Search	119
+VALUE	DHCP-Parameter-Request-List	DHCP-SIP-Servers-DHCP-Option 120
+VALUE	DHCP-Parameter-Request-List	DHCP-Classless-Static-Route 121
+VALUE	DHCP-Parameter-Request-List	DHCP-CCC		122
+VALUE	DHCP-Parameter-Request-List	DHCP-GeoConf-Option	123
+VALUE	DHCP-Parameter-Request-List	DHCP-V-I-Vendor-Class	124
+VALUE	DHCP-Parameter-Request-List	DHCP-V-I-Vendor-Specific 125
+VALUE	DHCP-Parameter-Request-List	DHCP-Etherboot		128
+VALUE	DHCP-Parameter-Request-List	DHCP-TFTP-Server-IP-Address 128
+VALUE	DHCP-Parameter-Request-List	DHCP-Call-Server-IP-address 129
+VALUE	DHCP-Parameter-Request-List	DHCP-Ethernet-Interface	130
+VALUE	DHCP-Parameter-Request-List	DHCP-Vendor-Discrimination-Str 130
+VALUE	DHCP-Parameter-Request-List	DHCP-Remote-Stats-Svr-IP-Address 131
+VALUE	DHCP-Parameter-Request-List	DHCP-IEEE-802.1P-VLAN-ID 132
+VALUE	DHCP-Parameter-Request-List	DHCP-IEEE-802.1Q-L2-Priority 133
+VALUE	DHCP-Parameter-Request-List	DHCP-Diffserv-Code-Point 134
+VALUE	DHCP-Parameter-Request-List	DHCP-HTTP-Proxy		135
+
+END-VENDOR	DHCP
diff --git a/src/plugins/vbng/etc/dictionary.merit b/src/plugins/vbng/etc/dictionary.merit
new file mode 100644
index 0000000..7d675e5
--- /dev/null
+++ b/src/plugins/vbng/etc/dictionary.merit
@@ -0,0 +1,17 @@
+#
+#	Experimental extensions, configuration only (for check-items)
+#	Names/numbers as per the MERIT extensions (if possible).
+#
+ATTRIBUTE	NAS-Identifier		32	string
+ATTRIBUTE	Proxy-State		33	string
+ATTRIBUTE	Login-LAT-Service	34	string
+ATTRIBUTE	Login-LAT-Node		35	string
+ATTRIBUTE	Login-LAT-Group		36	string
+ATTRIBUTE	Framed-AppleTalk-Link	37	integer
+ATTRIBUTE	Framed-AppleTalk-Network 38	integer
+ATTRIBUTE	Framed-AppleTalk-Zone	39	string
+ATTRIBUTE       Acct-Input-Packets	47	integer
+ATTRIBUTE       Acct-Output-Packets	48	integer
+# 8 is a MERIT extension.
+VALUE		Service-Type		Authenticate-Only	8
+
diff --git a/src/plugins/vbng/etc/dictionary.sip b/src/plugins/vbng/etc/dictionary.sip
new file mode 100644
index 0000000..149fa4c
--- /dev/null
+++ b/src/plugins/vbng/etc/dictionary.sip
@@ -0,0 +1,77 @@
+#
+# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl
+#
+#	This file contains dictionary translations for parsing
+#	requests and generating responses.  All transactions are
+#	composed of Attribute/Value Pairs.  The value of each attribute
+#	is specified as one of 4 data types.  Valid data types are:
+#
+#	string - 0-253 octets
+#	ipaddr - 4 octets in network byte order
+#	integer - 32 bit value in big endian order (high byte first)
+#	date - 32 bit value in big endian order - seconds since
+#					00:00:00 GMT,  Jan.  1,  1970
+#
+#	Enumerated values are stored in the user file with dictionary
+#	VALUE translations for easy administration.
+#
+#	Example:
+#
+#	ATTRIBUTE	  VALUE
+#	---------------   -----
+#	Framed-Protocol = PPP
+#	7		= 1	(integer encoding)
+#
+
+#
+#	Experimental SIP Attributes/Values (draft-sterman-aaa-sip-00.txt etc)
+#
+ATTRIBUTE	Sip-Method		101	integer
+ATTRIBUTE	Sip-Response-Code	102	integer
+ATTRIBUTE	Sip-CSeq		103	string
+ATTRIBUTE	Sip-To-Tag		104	string
+ATTRIBUTE	Sip-From-Tag		105	string
+ATTRIBUTE	Sip-Branch-ID		106	string
+ATTRIBUTE	Sip-Translated-Request-URI	107	string
+ATTRIBUTE	Sip-Source-IP-Address	108	ipaddr
+ATTRIBUTE	Sip-Source-Port		109	integer
+ATTRIBUTE	Sip-User-ID		110	string
+ATTRIBUTE	Sip-User-Realm		111	string
+ATTRIBUTE	Sip-User-Nonce		112	string
+ATTRIBUTE	Sip-User-Method		113	string
+ATTRIBUTE	Sip-User-Digest-URI	114	string
+ATTRIBUTE	Sip-User-Nonce-Count	115	string
+ATTRIBUTE	Sip-User-QOP		116	string
+ATTRIBUTE	Sip-User-Opaque		117	string
+ATTRIBUTE	Sip-User-Response	118	string
+ATTRIBUTE	Sip-User-CNonce		119	string
+ATTRIBUTE	Sip-URI-User		208	string
+ATTRIBUTE	Sip-Req-URI		210	string
+ATTRIBUTE	Sip-CC			212	string
+ATTRIBUTE	Sip-RPId		213	string
+ATTRIBUTE	Digest-Response		206	string
+ATTRIBUTE	Digest-Attributes	207	string
+ATTRIBUTE	Digest-Realm		1063	string
+ATTRIBUTE	Digest-Nonce		1064	string
+ATTRIBUTE	Digest-Method		1065	string
+ATTRIBUTE	Digest-URI		1066	string
+ATTRIBUTE	Digest-QOP		1067	string
+ATTRIBUTE	Digest-Algorithm	1068	string
+ATTRIBUTE	Digest-Body-Digest	1069	string
+ATTRIBUTE	Digest-CNonce		1070	string
+ATTRIBUTE	Digest-Nonce-Count	1071	string
+ATTRIBUTE	Digest-User-Name	1072	string
+
+VALUE		Service-Type		SIP			15
+
+VALUE		Sip-Method		Other			0
+VALUE		Sip-Method		Invite			1
+VALUE		Sip-Method		Cancel			2
+VALUE		Sip-Method		Ack			3
+VALUE		Sip-Method		Bye			4
+
+VALUE		Sip-Response-Code	Other			0
+VALUE		Sip-Response-Code	Invite			1
+VALUE		Sip-Response-Code	Cancel			2
+VALUE		Sip-Response-Code	Ack			3
+VALUE		Sip-Response-Code	Bye			4
diff --git a/src/plugins/vbng/etc/issue b/src/plugins/vbng/etc/issue
new file mode 100644
index 0000000..6254487
--- /dev/null
+++ b/src/plugins/vbng/etc/issue
@@ -0,0 +1,5 @@
+(\I)
+-----------------------------------------------------
+\S \R (\N) (port \L)
+-----------------------------------------------------
+
diff --git a/src/plugins/vbng/etc/port-id-map b/src/plugins/vbng/etc/port-id-map
new file mode 100644
index 0000000..9088a0b
--- /dev/null
+++ b/src/plugins/vbng/etc/port-id-map
@@ -0,0 +1,24 @@
+#
+# port-id-map
+#
+# This file describes the ttyname to port id mapping. The port id
+# is reported as part of a RADIUS authentication or accouting request.
+#
+#ttyname (as returned by ttyname(3))	port-id
+/dev/tty1	1
+/dev/tty2	2
+/dev/tty3	3
+/dev/tty4	4
+/dev/tty5	5
+/dev/tty6	6
+/dev/tty7	7
+/dev/tty8	8
+/dev/ttyS0	9
+/dev/ttyS1	10
+/dev/ttyS2	11
+/dev/ttyS3	12
+/dev/ttyS4	13
+/dev/ttyS5	14
+/dev/ttyS6	15
+/dev/ttyS7	16
+ 
\ No newline at end of file
diff --git a/src/plugins/vbng/etc/radiusclient.conf b/src/plugins/vbng/etc/radiusclient.conf
new file mode 100644
index 0000000..3a315b4
--- /dev/null
+++ b/src/plugins/vbng/etc/radiusclient.conf
@@ -0,0 +1,92 @@
+# General settings
+
+# specify which authentication comes first respectively which
+# authentication is used. possible values are: "radius" and "local".
+# if you specify "radius,local" then the RADIUS server is asked
+# first then the local one. if only one keyword is specified only
+# this server is asked.
+auth_order	radius,local
+
+# maximum login tries a user has
+login_tries	4
+
+# timeout for all login tries
+# if this time is exceeded the user is kicked out
+login_timeout	60
+
+# name of the nologin file which when it exists disables logins.
+# it may be extended by the ttyname which will result in
+# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
+# logins on /dev/ttyS2)
+nologin /etc/nologin
+
+# name of the issue file. it's only display when no username is passed
+# on the radlogin command line
+issue	/usr/local/etc/radiusclient/issue
+
+# RADIUS settings
+
+# RADIUS server to use for authentication requests. this config
+# item can appear more then one time. if multiple servers are
+# defined they are tried in a round robin fashion if one
+# server is not answering.
+# optionally you can specify a the port number on which is remote
+# RADIUS listens separated by a colon from the hostname. if
+# no port is specified /etc/services is consulted of the radius
+# service. if this fails also a compiled in default is used.
+authserver 	localhost
+
+# RADIUS server to use for accouting requests. All that I
+# said for authserver applies, too. 
+#
+acctserver 	localhost
+
+# file holding shared secrets used for the communication
+# between the RADIUS client and server
+servers		/usr/local/etc/radiusclient/servers
+
+# dictionary of allowed attributes and values
+# just like in the normal RADIUS distributions
+dictionary 	/usr/local/etc/radiusclient/dictionary
+
+# program to call for a RADIUS authenticated login
+login_radius	/usr/local/sbin/login.radius
+
+# file which holds sequence number for communication with the
+# RADIUS server
+seqfile		/var/run/radius.seq
+
+# file which specifies mapping between ttyname and NAS-Port attribute
+mapfile		/usr/local/etc/radiusclient/port-id-map
+
+# default authentication realm to append to all usernames if no
+# realm was explicitly specified by the user
+# the radiusd directly form Livingston doesnt use any realms, so leave
+# it blank then
+default_realm
+
+# time to wait for a reply from the RADIUS server
+radius_timeout	10
+
+# resend request this many times before trying the next server
+radius_retries	3
+
+# The length of time in seconds that we skip a nonresponsive RADIUS
+# server for transaction requests.  Server(s) being in the "dead" state
+# are tried only after all other non-dead servers have been tried and
+# failed or timeouted.  The deadtime interval starts when the server
+# does not respond to an authentication/accounting request transmissions. 
+# When the interval expires, the "dead" server would be re-tried again,
+# and if it's still down then it will be considered "dead" for another
+# such interval and so on. This option is no-op if there is only one
+# server in the list. Set to 0 in order to disable the feature.
+radius_deadtime	0
+
+# local address from which radius packets have to be sent
+bindaddr *
+
+# LOCAL settings
+
+# program to execute for local login
+# it must support the -f flag for preauthenticated login
+login_local	/bin/login
diff --git a/src/plugins/vbng/etc/radiusclient.conf.in b/src/plugins/vbng/etc/radiusclient.conf.in
new file mode 100644
index 0000000..fdf62e6
--- /dev/null
+++ b/src/plugins/vbng/etc/radiusclient.conf.in
@@ -0,0 +1,92 @@
+# General settings
+
+# specify which authentication comes first respectively which
+# authentication is used. possible values are: "radius" and "local".
+# if you specify "radius,local" then the RADIUS server is asked
+# first then the local one. if only one keyword is specified only
+# this server is asked.
+auth_order	radius,local
+
+# maximum login tries a user has
+login_tries	4
+
+# timeout for all login tries
+# if this time is exceeded the user is kicked out
+login_timeout	60
+
+# name of the nologin file which when it exists disables logins.
+# it may be extended by the ttyname which will result in
+# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
+# logins on /dev/ttyS2)
+nologin /etc/nologin
+
+# name of the issue file. it's only display when no username is passed
+# on the radlogin command line
+issue	@pkgsysconfdir@/issue
+
+# RADIUS settings
+
+# RADIUS server to use for authentication requests. this config
+# item can appear more then one time. if multiple servers are
+# defined they are tried in a round robin fashion if one
+# server is not answering.
+# optionally you can specify a the port number on which is remote
+# RADIUS listens separated by a colon from the hostname. if
+# no port is specified /etc/services is consulted of the radius
+# service. if this fails also a compiled in default is used.
+authserver 	localhost
+
+# RADIUS server to use for accouting requests. All that I
+# said for authserver applies, too. 
+#
+acctserver 	localhost
+
+# file holding shared secrets used for the communication
+# between the RADIUS client and server
+servers		@pkgsysconfdir@/servers
+
+# dictionary of allowed attributes and values
+# just like in the normal RADIUS distributions
+dictionary 	@pkgsysconfdir@/dictionary
+
+# program to call for a RADIUS authenticated login
+login_radius	@sbindir@/login.radius
+
+# file which holds sequence number for communication with the
+# RADIUS server
+seqfile		/var/run/radius.seq
+
+# file which specifies mapping between ttyname and NAS-Port attribute
+mapfile		@pkgsysconfdir@/port-id-map
+
+# default authentication realm to append to all usernames if no
+# realm was explicitly specified by the user
+# the radiusd directly form Livingston doesnt use any realms, so leave
+# it blank then
+default_realm
+
+# time to wait for a reply from the RADIUS server
+radius_timeout	10
+
+# resend request this many times before trying the next server
+radius_retries	3
+
+# The length of time in seconds that we skip a nonresponsive RADIUS
+# server for transaction requests.  Server(s) being in the "dead" state
+# are tried only after all other non-dead servers have been tried and
+# failed or timeouted.  The deadtime interval starts when the server
+# does not respond to an authentication/accounting request transmissions. 
+# When the interval expires, the "dead" server would be re-tried again,
+# and if it's still down then it will be considered "dead" for another
+# such interval and so on. This option is no-op if there is only one
+# server in the list. Set to 0 in order to disable the feature.
+radius_deadtime	0
+
+# local address from which radius packets have to be sent
+bindaddr *
+
+# LOCAL settings
+
+# program to execute for local login
+# it must support the -f flag for preauthenticated login
+login_local	/bin/login
diff --git a/src/plugins/vbng/etc/servers b/src/plugins/vbng/etc/servers
new file mode 100644
index 0000000..50eddd3
--- /dev/null
+++ b/src/plugins/vbng/etc/servers
@@ -0,0 +1,10 @@
+## Server Name or Client/Server pair		Key		
+## ----------------				---------------
+#
+#portmaster.elemental.net			hardlyasecret
+#portmaster2.elemental.net			donttellanyone
+#
+## uncomment the following line for simple testing of radlogin
+## with freeradius-server
+#
+#localhost/localhost				testing123
diff --git a/src/plugins/vbng/include/freeradius-client.h b/src/plugins/vbng/include/freeradius-client.h
new file mode 100644
index 0000000..96c7546
--- /dev/null
+++ b/src/plugins/vbng/include/freeradius-client.h
@@ -0,0 +1,528 @@
+/*
+ * $Id: freeradius-client.h,v 1.18 2010/06/15 09:22:51 aland Exp $
+ *
+ * Copyright (C) 1995,1996,1997,1998 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#ifndef FREERADIUS_CLIENT_H
+#define FREERADIUS_CLIENT_H
+
+#ifdef CP_DEBUG
+#define		DEBUG(args, ...)	rc_log(## args)
+#else
+#define		DEBUG(args, ...)	;
+#endif
+
+#include	<sys/types.h>
+/*
+ * Include for C99 uintX_t defines is stdint.h on most systems.  Solaris uses
+ * inttypes.h instead.  Comment out the stdint include if you get an error,
+ * and uncomment the inttypes.h include.
+ */
+#include	<stdint.h>
+/* #include	<inttypes.h> */
+#include	<stdio.h>
+#include	<time.h>
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+#define AUTH_VECTOR_LEN		16
+#define AUTH_PASS_LEN		(3 * 16) /* multiple of 16 */
+#define AUTH_ID_LEN		64
+#define AUTH_STRING_LEN		253	 /* maximum of 253 */
+
+#define	BUFFER_LEN		8192
+
+#define NAME_LENGTH		32
+#define	GETSTR_LENGTH		128	/* must be bigger than AUTH_PASS_LEN */
+
+#define	MAX_SECRET_LENGTH	(3 * 16) /* MUST be multiple of 16 */
+
+#define	VENDOR(x)		(((x) >> 16) & 0xffff)
+#define	ATTRID(x)		((x) & 0xffff)
+
+#define PW_MAX_MSG_SIZE		4096
+
+/* codes for radius_buildreq, radius_getport, etc. */
+#define AUTH			0
+#define ACCT			1
+
+/* defines for config.c */
+
+#define SERVER_MAX 8
+
+#define AUTH_LOCAL_FST	(1<<0)
+#define AUTH_RADIUS_FST (1<<1)
+#define AUTH_LOCAL_SND  (1<<2)
+#define AUTH_RADIUS_SND (1<<3)
+
+typedef struct server {
+	int max;
+	char *name[SERVER_MAX];
+	uint16_t port[SERVER_MAX];
+	char *secret[SERVER_MAX];
+	double deadtime_ends[SERVER_MAX];
+} SERVER;
+
+typedef struct pw_auth_hdr
+{
+	uint8_t          code;
+	uint8_t          id;
+	uint16_t         length;
+	uint8_t          vector[AUTH_VECTOR_LEN];
+	uint8_t          data[2];
+} AUTH_HDR;
+
+struct rc_conf
+{
+	struct _option		*config_options;
+	uint32_t 			this_host_ipaddr;
+	uint32_t			*this_host_bind_ipaddr;
+	struct map2id_s		*map2id_list;
+	struct dict_attr	*dictionary_attributes;
+	struct dict_value	*dictionary_values;
+	struct dict_vendor	*dictionary_vendors;
+	char			buf[GETSTR_LENGTH];
+	char			buf1[14];
+	char			ifname[512];
+};
+
+typedef struct rc_conf rc_handle;
+
+#define AUTH_HDR_LEN			20
+#define CHAP_VALUE_LENGTH		16
+
+#define PW_AUTH_UDP_PORT		1645
+#define PW_ACCT_UDP_PORT		1646
+
+#define PW_TYPE_STRING			0
+#define PW_TYPE_INTEGER			1
+#define PW_TYPE_IPADDR			2
+#define PW_TYPE_DATE			3
+#define PW_TYPE_IPV6ADDR		4
+#define PW_TYPE_IPV6PREFIX		5
+
+/* standard RADIUS codes */
+
+#define	PW_ACCESS_REQUEST		1
+#define	PW_ACCESS_ACCEPT		2
+#define	PW_ACCESS_REJECT		3
+#define	PW_ACCOUNTING_REQUEST		4
+#define	PW_ACCOUNTING_RESPONSE		5
+#define	PW_ACCOUNTING_STATUS		6
+#define	PW_PASSWORD_REQUEST		7
+#define	PW_PASSWORD_ACK			8
+#define	PW_PASSWORD_REJECT		9
+#define	PW_ACCOUNTING_MESSAGE		10
+#define	PW_ACCESS_CHALLENGE		11
+#define	PW_STATUS_SERVER		12
+#define	PW_STATUS_CLIENT		13
+
+
+/* standard RADIUS attribute-value pairs */
+
+#define	PW_USER_NAME			1	/* string */
+#define	PW_USER_PASSWORD		2	/* string */
+#define	PW_CHAP_PASSWORD		3	/* string */
+#define	PW_NAS_IP_ADDRESS		4	/* ipaddr */
+#define	PW_NAS_PORT			5	/* integer */
+#define	PW_SERVICE_TYPE			6	/* integer */
+#define	PW_FRAMED_PROTOCOL		7	/* integer */
+#define	PW_FRAMED_IP_ADDRESS		8	/* ipaddr */
+#define	PW_FRAMED_IP_NETMASK		9	/* ipaddr */
+#define	PW_FRAMED_ROUTING		10	/* integer */
+#define	PW_FILTER_ID		        11	/* string */
+#define	PW_FRAMED_MTU			12	/* integer */
+#define	PW_FRAMED_COMPRESSION		13	/* integer */
+#define	PW_LOGIN_IP_HOST		14	/* ipaddr */
+#define	PW_LOGIN_SERVICE		15	/* integer */
+#define	PW_LOGIN_PORT			16	/* integer */
+#define	PW_OLD_PASSWORD			17	/* string */ /* deprecated */
+#define	PW_REPLY_MESSAGE		18	/* string */
+#define	PW_LOGIN_CALLBACK_NUMBER	19	/* string */
+#define	PW_FRAMED_CALLBACK_ID		20	/* string */
+#define	PW_EXPIRATION			21	/* date */ /* deprecated */
+#define	PW_FRAMED_ROUTE			22	/* string */
+#define	PW_FRAMED_IPX_NETWORK		23	/* integer */
+#define	PW_STATE			24	/* string */
+#define	PW_CLASS			25	/* string */
+#define	PW_VENDOR_SPECIFIC		26	/* string */
+#define	PW_SESSION_TIMEOUT		27	/* integer */
+#define	PW_IDLE_TIMEOUT			28	/* integer */
+#define	PW_TERMINATION_ACTION		29	/* integer */
+#define	PW_CALLED_STATION_ID            30      /* string */
+#define	PW_CALLING_STATION_ID           31      /* string */
+#define	PW_NAS_IDENTIFIER		32	/* string */
+#define	PW_PROXY_STATE			33	/* string */
+#define	PW_LOGIN_LAT_SERVICE		34	/* string */
+#define	PW_LOGIN_LAT_NODE		35	/* string */
+#define	PW_LOGIN_LAT_GROUP		36	/* string */
+#define	PW_FRAMED_APPLETALK_LINK	37	/* integer */
+#define	PW_FRAMED_APPLETALK_NETWORK	38	/* integer */
+#define	PW_FRAMED_APPLETALK_ZONE	39	/* string */
+#define	PW_EVENT_TIMESTAMP		55	/* integer */
+#define	PW_CHAP_CHALLENGE               60      /* string */
+#define	PW_NAS_PORT_TYPE                61      /* integer */
+#define	PW_PORT_LIMIT                   62      /* integer */
+#define PW_LOGIN_LAT_PORT               63      /* string */
+#define PW_CONNECT_INFO                 77      /* string */
+#define PW_MESSAGE_AUTHENTICATOR        80      /* string */
+
+/* RFC3162 IPv6 attributes */
+
+#define PW_NAS_IPV6_ADDRESS             95      /* string */
+#define PW_FRAMED_INTERFACE_ID          96      /* string */
+#define PW_FRAMED_IPV6_PREFIX           97      /* string */
+#define PW_LOGIN_IPV6_HOST              98      /* string */
+#define PW_FRAMED_IPV6_ROUTE            99      /* string */
+#define PW_FRAMED_IPV6_POOL             100     /* string */
+
+/* RFC6911 IPv6 attributes */
+#define PW_FRAMED_IPV6_ADDRESS		168	/* ipaddr6 */
+#define PW_DNS_SERVER_IPV6_ADDRESS	169	/* ipaddr6 */
+#define PW_ROUTE_IPV6_INFORMATION	170	/* ipv6prefix */
+
+/*	Accounting */
+
+#define	PW_ACCT_STATUS_TYPE		40	/* integer */
+#define	PW_ACCT_DELAY_TIME		41	/* integer */
+#define	PW_ACCT_INPUT_OCTETS		42	/* integer */
+#define	PW_ACCT_OUTPUT_OCTETS		43	/* integer */
+#define	PW_ACCT_SESSION_ID		44	/* string */
+#define	PW_ACCT_AUTHENTIC		45	/* integer */
+#define	PW_ACCT_SESSION_TIME		46	/* integer */
+#define	PW_ACCT_INPUT_PACKETS		47	/* integer */
+#define	PW_ACCT_OUTPUT_PACKETS		48	/* integer */
+#define PW_ACCT_TERMINATE_CAUSE		49	/* integer */
+#define PW_ACCT_MULTI_SESSION_ID	50	/* string */
+#define PW_ACCT_LINK_COUNT		51	/* integer */
+#define PW_ACCT_INPUT_GIGAWORDS		52	/* integer */
+#define PW_ACCT_OUTPUT_GIGAWORDS	53	/* integer */
+
+/* 	Experimental SIP-specific attributes (draft-sterman-aaa-sip-00.txt etc) */
+
+#define	PW_DIGEST_RESPONSE		206	/* string */
+#define	PW_DIGEST_ATTRIBUTES		207	/* string */
+#define	PW_DIGEST_REALM			1063	/* string */
+#define	PW_DIGEST_NONCE			1064	/* string */
+#define	PW_DIGEST_METHOD		1065	/* string */
+#define	PW_DIGEST_URI			1066	/* string */
+#define	PW_DIGEST_QOP			1067	/* string */
+#define	PW_DIGEST_ALGORITHM		1068	/* string */
+#define	PW_DIGEST_BODY_DIGEST		1069	/* string */
+#define	PW_DIGEST_CNONCE		1070	/* string */
+#define	PW_DIGEST_NONCE_COUNT		1071	/* string */
+#define	PW_DIGEST_USER_NAME		1072	/* string */
+
+/*	Merit Experimental Extensions */
+
+#define PW_USER_ID                      222     /* string */
+#define PW_USER_REALM                   223     /* string */
+
+/*	Integer Translations */
+
+/*	SERVICE TYPES	*/
+
+#define	PW_LOGIN			1
+#define	PW_FRAMED			2
+#define	PW_CALLBACK_LOGIN		3
+#define	PW_CALLBACK_FRAMED		4
+#define	PW_OUTBOUND			5
+#define	PW_ADMINISTRATIVE		6
+#define PW_NAS_PROMPT                   7
+#define PW_AUTHENTICATE_ONLY		8
+#define PW_CALLBACK_NAS_PROMPT          9
+
+/*	FRAMED PROTOCOLS	*/
+
+#define	PW_PPP				1
+#define	PW_SLIP				2
+#define PW_ARA                          3
+#define PW_GANDALF                      4
+#define PW_XYLOGICS                     5
+
+/*	FRAMED ROUTING VALUES	*/
+
+#define	PW_NONE				0
+#define	PW_BROADCAST			1
+#define	PW_LISTEN			2
+#define	PW_BROADCAST_LISTEN		3
+
+/*	FRAMED COMPRESSION TYPES	*/
+
+#define	PW_VAN_JACOBSON_TCP_IP		1
+#define	PW_IPX_HEADER_COMPRESSION	2
+
+/*	LOGIN SERVICES	*/
+
+#define PW_TELNET                       0
+#define PW_RLOGIN                       1
+#define PW_TCP_CLEAR                    2
+#define PW_PORTMASTER                   3
+#define PW_LAT                          4
+#define PW_X25_PAD                      5
+#define PW_X25_T3POS                    6
+
+/*	TERMINATION ACTIONS	*/
+
+#define	PW_DEFAULT			0
+#define	PW_RADIUS_REQUEST		1
+
+/*	PROHIBIT PROTOCOL  */
+
+#define PW_DUMB		0	/* 1 and 2 are defined in FRAMED PROTOCOLS */
+#define PW_AUTH_ONLY	3
+#define PW_ALL		255
+
+/*	ACCOUNTING STATUS TYPES    */
+
+#define PW_STATUS_START		1
+#define PW_STATUS_STOP		2
+#define PW_STATUS_ALIVE		3
+#define PW_STATUS_MODEM_START	4
+#define PW_STATUS_MODEM_STOP	5
+#define PW_STATUS_CANCEL	6
+#define PW_ACCOUNTING_ON	7
+#define PW_ACCOUNTING_OFF	8
+
+/*      ACCOUNTING TERMINATION CAUSES   */
+
+#define PW_USER_REQUEST         1
+#define PW_LOST_CARRIER         2
+#define PW_LOST_SERVICE         3
+#define PW_ACCT_IDLE_TIMEOUT    4
+#define PW_ACCT_SESSION_TIMEOUT 5
+#define PW_ADMIN_RESET          6
+#define PW_ADMIN_REBOOT         7
+#define PW_PORT_ERROR           8
+#define PW_NAS_ERROR            9
+#define PW_NAS_REQUEST          10
+#define PW_NAS_REBOOT           11
+#define PW_PORT_UNNEEDED        12
+#define PW_PORT_PREEMPTED       13
+#define PW_PORT_SUSPENDED       14
+#define PW_SERVICE_UNAVAILABLE  15
+#define PW_CALLBACK             16
+#define PW_USER_ERROR           17
+#define PW_HOST_REQUEST         18
+
+/*     NAS PORT TYPES    */
+
+#define PW_ASYNC		0
+#define PW_SYNC			1
+#define PW_ISDN_SYNC		2
+#define PW_ISDN_SYNC_V120	3
+#define PW_ISDN_SYNC_V110	4
+#define PW_VIRTUAL		5
+
+/*	   AUTHENTIC TYPES */
+#define PW_RADIUS	1
+#define PW_LOCAL	2
+#define PW_REMOTE	3
+
+/* Server data structures */
+
+typedef struct dict_attr
+{
+	char              name[NAME_LENGTH + 1];	/* attribute name */
+	int               value;			/* attribute index */
+	int               type;				/* string, int, etc. */
+	struct dict_attr *next;
+} DICT_ATTR;
+
+typedef struct dict_value
+{
+	char               attrname[NAME_LENGTH +1];
+	char               name[NAME_LENGTH + 1];
+	int                value;
+	struct dict_value *next;
+} DICT_VALUE;
+
+typedef struct dict_vendor
+{
+	char		   vendorname[NAME_LENGTH +1];
+	int		   vendorpec;
+	struct dict_vendor *next;
+} DICT_VENDOR;
+
+typedef struct value_pair
+{
+	char               name[NAME_LENGTH + 1];
+	int                attribute;
+	int                type;
+	uint32_t           lvalue;
+	char               strvalue[AUTH_STRING_LEN + 1];
+	struct value_pair *next;
+} VALUE_PAIR;
+
+/* don't change this, as it has to be the same as in the Merit radiusd code */
+#define MGMT_POLL_SECRET	"Hardlyasecret"
+
+/* 	Define return codes from "SendServer" utility */
+
+#define BADRESP_RC	-2
+#define ERROR_RC	-1
+#define OK_RC		0
+#define TIMEOUT_RC	1
+#define REJECT_RC	2
+
+typedef struct send_data /* Used to pass information to sendserver() function */
+{
+	uint8_t        code;		/* RADIUS packet code */
+	uint8_t        seq_nbr;		/* Packet sequence number */
+	char           *server;		/* Name/addrress of RADIUS server */
+	int            svc_port;	/* RADIUS protocol destination port */
+	char	       *secret;		/* Shared secret of RADIUS server */
+	int            timeout;		/* Session timeout in seconds */
+	int	       retries;
+	VALUE_PAIR     *send_pairs;     /* More a/v pairs to send */
+	VALUE_PAIR     *receive_pairs;  /* Where to place received a/v pairs */
+} SEND_DATA;
+
+#ifndef MIN
+#define MIN(a, b)     ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)     ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX	1024
+#endif
+
+typedef struct env
+{
+	int maxsize, size;
+	char **env;
+} ENV;
+
+#define ENV_SIZE	128
+
+__BEGIN_DECLS
+
+/*	Function prototypes	*/
+
+/*	avpair.c		*/
+
+VALUE_PAIR *rc_avpair_add(rc_handle const *, VALUE_PAIR **, int, void const *, int, int);
+int rc_avpair_assign(VALUE_PAIR *, void const *, int);
+VALUE_PAIR *rc_avpair_new(rc_handle const *, int, void const *, int, int);
+VALUE_PAIR *rc_avpair_gen(rc_handle const *, VALUE_PAIR *, unsigned char const *, int, int);
+VALUE_PAIR *rc_avpair_get(VALUE_PAIR *, int, int);
+void rc_avpair_insert(VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *);
+void rc_avpair_free(VALUE_PAIR *);
+int rc_avpair_parse(rc_handle const *, char const *, VALUE_PAIR **);
+int rc_avpair_tostr(rc_handle const *, VALUE_PAIR *, char *, int, char *, int);
+char *rc_avpair_log(rc_handle const *, VALUE_PAIR *, char *buf, size_t buf_len);
+VALUE_PAIR *rc_avpair_readin(rc_handle const *, FILE *);
+
+/*	buildreq.c		*/
+
+void rc_buildreq(rc_handle const *, SEND_DATA *, int, char *, unsigned short, char *, int, int);
+unsigned char rc_get_id();
+int rc_auth(rc_handle *, uint32_t, VALUE_PAIR *, VALUE_PAIR **, char *);
+int rc_auth_proxy(rc_handle *, VALUE_PAIR *, VALUE_PAIR **, char *);
+int rc_acct(rc_handle *, uint32_t, VALUE_PAIR *);
+int rc_acct_proxy(rc_handle *, VALUE_PAIR *);
+int rc_check(rc_handle *, char *, char *, unsigned short, char *);
+
+int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
+    char *msg, int add_nas_port, int request_type);
+
+/*	clientid.c		*/
+
+int rc_read_mapfile(rc_handle *, char const *);
+uint32_t rc_map2id(rc_handle const *, char const *);
+void rc_map2id_free(rc_handle *);
+
+/*	config.c		*/
+
+rc_handle *rc_read_config(char const *);
+char *rc_conf_str(rc_handle const *, char const *);
+int rc_conf_int(rc_handle const *, char const *);
+SERVER *rc_conf_srv(rc_handle const *, char const *);
+int rc_find_server(rc_handle const *, char const *, uint32_t *, char *);
+void rc_config_free(rc_handle *);
+int rc_add_config(rc_handle *, char const *, char const *, char const *, int);
+rc_handle *rc_config_init(rc_handle *);
+int test_config(rc_handle const *, char const *);
+
+/*	dict.c			*/
+
+int rc_read_dictionary(rc_handle *, char const *);
+DICT_ATTR *rc_dict_getattr(rc_handle const *, int);
+DICT_ATTR *rc_dict_findattr(rc_handle const *, char const *);
+DICT_VALUE *rc_dict_findval(rc_handle const *, char const *);
+DICT_VENDOR *rc_dict_findvend(rc_handle const *, char const *);
+DICT_VENDOR *rc_dict_getvend(rc_handle const *, int);
+DICT_VALUE * rc_dict_getval(rc_handle const *, uint32_t, char const *);
+void rc_dict_free(rc_handle *);
+
+/*	ip_util.c		*/
+
+struct hostent *rc_gethostbyname(char const *);
+struct hostent *rc_gethostbyaddr(char const *, size_t, int);
+uint32_t rc_get_ipaddr(char const *);
+int rc_good_ipaddr(char const *);
+char const *rc_ip_hostname(uint32_t);
+unsigned short rc_getport(int);
+int rc_own_hostname(char *, int);
+uint32_t rc_own_ipaddress(rc_handle *);
+uint32_t rc_own_bind_ipaddress(rc_handle *);
+struct sockaddr;
+int rc_get_srcaddr(struct sockaddr *, struct sockaddr *);
+
+
+/*	log.c			*/
+
+void rc_openlog(char const *);
+void rc_log(int, char const *, ...);
+
+/*	sendserver.c		*/
+
+int rc_send_server(rc_handle *, SEND_DATA *, char *);
+
+/*	util.c			*/
+
+void rc_str2tm(char const *, struct tm *);
+char *rc_getifname(rc_handle *, char const *);
+char *rc_getstr(rc_handle *, char const *, int);
+void rc_mdelay(int);
+char *rc_mksid(rc_handle *);
+rc_handle *rc_new(void);
+void rc_destroy(rc_handle *);
+char *rc_fgetln(FILE *, size_t *);
+double rc_getctime(void);
+
+/*	env.c			*/
+
+struct env *rc_new_env(int);
+void rc_free_env(struct env *);
+int rc_add_env(struct env *, char const *, char const *);
+int rc_import_env(struct env *, char const **);
+
+/* md5.c			*/
+
+void rc_md5_calc(unsigned char *, unsigned char const *, unsigned int);
+
+__END_DECLS
+
+#endif /* FREERADIUS_CLIENT_H */
diff --git a/src/plugins/vbng/include/includes.h b/src/plugins/vbng/include/includes.h
new file mode 100644
index 0000000..908f0e7
--- /dev/null
+++ b/src/plugins/vbng/include/includes.h
@@ -0,0 +1,182 @@
+/*
+ * $Id: includes.h,v 1.6 2007/06/21 18:07:22 cparker Exp $
+ *
+ * Copyright (C) 1997 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include "config.h"
+
+/* AIX requires this to be the first thing in the file.  */
+#ifndef __GNUC__
+# if HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+#   pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+     char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+# include <stdarg.h>
+#else
+# include <stdarg.h>
+# ifndef HAVE_STRCHR
+#  define strchr index
+#  define strrchr rindex
+# endif
+#endif
+
+/* I realize that this is ugly and unsafe.. :( */
+#ifndef HAVE_SNPRINTF
+# define snprintf(buf, len, format, ...) sprintf(buf, format, __VA_ARGS__)
+#endif
+#ifndef HAVE_VSNPRINTF
+# define vsnprintf(buf, len, format, ap) vsprintf(buf, format, ap)
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX        1024
+#endif
+
+#ifndef UCHAR_MAX
+# ifdef  __STDC__
+#  define UCHAR_MAX       255U
+# else
+#  define UCHAR_MAX       255
+# endif
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if defined(HAVE_SIGNAL_H)
+# include <signal.h>
+#endif
+#if defined(HAVE_SYS_SIGNAL_H)
+# include <sys/signal.h>
+#endif
+
+#ifdef NEED_SIG_PROTOTYPES
+int sigemptyset(sigset_t *);
+int sigaddset(sigset_t *, int);
+int sigprocmask (int, sigset_t *, sigset_t *);
+#endif
+
+#if HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#if defined(HAVE_SHADOW_H) && defined(HAVE_SHADOW_PASSWORDS)
+# include <shadow.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+/*
+ * prefer srandom/random over srand/rand as there generator has a
+ * better distribution of the numbers on certain systems.
+ * on Linux both generators are identical.
+ */
+#ifndef HAVE_RANDOM
+# ifdef HAVE_RAND
+# define srandom        srand
+# define random         rand
+# endif
+#endif
+
+/* rlib/lock.c */
+int do_lock_exclusive(FILE *);
+int do_unlock(FILE *);
diff --git a/src/plugins/vbng/include/messages.h b/src/plugins/vbng/include/messages.h
new file mode 100644
index 0000000..9a5f0e8
--- /dev/null
+++ b/src/plugins/vbng/include/messages.h
@@ -0,0 +1,53 @@
+/*
+ * $Id: messages.h,v 1.2 2004/02/23 20:10:39 sobomax Exp $
+ *
+ * Copyright (C) 1995,1996 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+/*
+ * Only messages that the user gets under normal use are in here.
+ * Error messages and such are still in the source code.
+ */
+
+#ifndef MESSAGES_H
+#define MESSAGES_H
+
+/* radlogin.c */
+
+#define SC_LOGIN	 "login: "
+#define SC_PASSWORD	 "Password: "
+
+#define SC_TIMEOUT	 "\r\nlogin timed out after %d seconds. Bye.\r\n"
+#define SC_EXCEEDED	 "Maximum login tries exceeded. Go away!\r\n"
+
+#define SC_RADIUS_OK	 "RADIUS: Authentication OK\r\n"
+#define SC_RADIUS_FAILED "RADIUS: Authentication failure\r\n"
+
+#define SC_LOCAL_OK	 "local: Authentication OK\r\n"
+#define SC_LOCAL_FAILED	 "local: Authentication failure\r\n"
+#define SC_NOLOGIN	 "\r\nSystem closed for maintenance. Try again later...\r\n"
+
+#define SC_SERVER_REPLY	 "RADIUS: %s"
+
+#define SC_DEFAULT_ISSUE "(\\I)\r\n\r\n\\S \\R (\\N) (port \\L)\r\n\r\n"
+
+/* radacct.c */
+
+#define SC_ACCT_OK	 "RADIUS accounting OK\r\n"
+#define SC_ACCT_FAILED	 "RADIUS accounting failed (RC=%i)\r\n"
+
+/* radstatus.c */
+
+#define SC_STATUS_FAILED	"RADIUS: Status failure\r\n"
+
+#endif /* MESSAGES_H */
diff --git a/src/plugins/vbng/include/pathnames.h b/src/plugins/vbng/include/pathnames.h
new file mode 100644
index 0000000..0256d47
--- /dev/null
+++ b/src/plugins/vbng/include/pathnames.h
@@ -0,0 +1,28 @@
+/*
+ * $Id: pathnames.h,v 1.2 2004/02/23 20:10:39 sobomax Exp $
+ *
+ * Copyright (C) 1995,1996 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#ifndef PATHNAMES_H
+#define PATHNAMES_H
+
+#define _PATH_DEV_URANDOM	"/dev/urandom"		/* Linux only */
+#define _PATH_ETC_ISSUE		"/etc/issue"
+
+/* normally defined in the Makefile */
+#ifndef _PATH_ETC_RADIUSCLIENT_CONF
+#define _PATH_ETC_RADIUSCLIENT_CONF       "/etc/radiusclient.conf"
+#endif
+
+#endif /* PATHNAMES_H */
diff --git a/src/plugins/vbng/lib/avpair.c b/src/plugins/vbng/lib/avpair.c
new file mode 100644
index 0000000..8ce2a8e
--- /dev/null
+++ b/src/plugins/vbng/lib/avpair.c
@@ -0,0 +1,874 @@
+/*
+ * $Id: avpair.c,v 1.26 2010/06/15 09:22:52 aland Exp $
+ *
+ * Copyright (C) 1995 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+/*
+ * Function: rc_avpair_add
+ *
+ * Purpose: add an attribute-value pair to the given list.
+ *
+ * Returns: pointer to added a/v pair upon success, NULL pointer upon failure.
+ *
+ * Remarks: Always appends the new pair to the end of the list.
+ *
+ */
+
+VALUE_PAIR *rc_avpair_add (rc_handle const *rh, VALUE_PAIR **list, int attrid, void const *pval, int len, int vendorpec)
+{
+	VALUE_PAIR     *vp;
+
+	vp = rc_avpair_new (rh, attrid, pval, len, vendorpec);
+
+	if (vp != NULL)
+	{
+		rc_avpair_insert (list, NULL, vp);
+	}
+
+	return vp;
+
+}
+
+/*
+ * Function: rc_avpair_assign
+ *
+ * Purpose: assign the given value to an attribute-value pair.
+ *
+ * Returns:  0 on success,
+ *	    -1 on failure.
+ *
+ */
+
+int rc_avpair_assign (VALUE_PAIR *vp, void const *pval, int len)
+{
+
+	switch (vp->type)
+	{
+		case PW_TYPE_STRING:
+			if (len == -1)
+				len = (uint32_t)strlen((char const *)pval);
+			if (len > AUTH_STRING_LEN) {
+		        	rc_log(LOG_ERR, "rc_avpair_assign: bad attribute length");
+		        	return -1;
+			}
+			memcpy(vp->strvalue, (char const *)pval, len);
+			vp->strvalue[len] = '\0';
+			vp->lvalue = len;
+			break;
+
+		case PW_TYPE_DATE:
+		case PW_TYPE_INTEGER:
+	        case PW_TYPE_IPADDR:
+			vp->lvalue = * (uint32_t *) pval;
+			break;
+	        case PW_TYPE_IPV6ADDR:
+			if (len != 16) {
+		        	rc_log(LOG_ERR, "rc_avpair_assign: bad IPv6 length");
+		        	return -1;
+			}
+			memcpy(vp->strvalue, (char const *)pval, len);
+			vp->lvalue = len;
+			break;
+
+	        case PW_TYPE_IPV6PREFIX:
+			if (len < 2 || len > 18) {
+		        	rc_log(LOG_ERR, "rc_avpair_assign: bad IPv6 prefix length");
+		        	return -1;
+			}
+			memcpy(vp->strvalue, (char const *)pval, len);
+			vp->lvalue = len;
+			break;
+
+		default:
+			rc_log(LOG_ERR, "rc_avpair_assign: unknown attribute %d", vp->type);
+			return -1;
+	}
+	return 0;
+}
+
+/*
+ * Function: rc_avpair_new
+ *
+ * Purpose: make a new attribute-value pair with given parameters.
+ *
+ * Returns: pointer to generated a/v pair when successful, NULL when failure.
+ *
+ */
+
+VALUE_PAIR *rc_avpair_new (rc_handle const *rh, int attrid, void const *pval, int len, int vendorpec)
+{
+	VALUE_PAIR     *vp = NULL;
+	DICT_ATTR      *pda;
+
+	attrid = attrid | (vendorpec << 16);
+	if ((pda = rc_dict_getattr (rh, attrid)) == NULL)
+	{
+		rc_log(LOG_ERR,"rc_avpair_new: unknown attribute %d", attrid);
+		return NULL;
+	}
+	if (vendorpec != 0 && rc_dict_getvend(rh, vendorpec) == NULL)
+	{
+		rc_log(LOG_ERR,"rc_avpair_new: unknown Vendor-Id %d", vendorpec);
+		return NULL;
+	}
+	if ((vp = malloc (sizeof (VALUE_PAIR))) != NULL)
+	{
+		strncpy (vp->name, pda->name, sizeof (vp->name));
+		vp->attribute = attrid;
+		vp->next = NULL;
+		vp->type = pda->type;
+		if (rc_avpair_assign (vp, pval, len) == 0)
+		{
+			/* XXX: Fix up Digest-Attributes */
+			switch (vp->attribute) {
+			case PW_DIGEST_REALM:
+			case PW_DIGEST_NONCE:
+			case PW_DIGEST_METHOD:
+			case PW_DIGEST_URI:
+			case PW_DIGEST_QOP:
+			case PW_DIGEST_ALGORITHM:
+			case PW_DIGEST_BODY_DIGEST:
+			case PW_DIGEST_CNONCE:
+			case PW_DIGEST_NONCE_COUNT:
+			case PW_DIGEST_USER_NAME:
+				/* overlapping! */
+				if (vp->lvalue > AUTH_STRING_LEN - 2)
+					vp->lvalue = AUTH_STRING_LEN - 2;
+				memmove(&vp->strvalue[2], &vp->strvalue[0], vp->lvalue);
+				vp->strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1;
+				vp->lvalue += 2;
+				vp->strvalue[1] = vp->lvalue;
+				vp->strvalue[vp->lvalue] = '\0';
+				vp->attribute = PW_DIGEST_ATTRIBUTES;
+			default:
+				break;
+			}
+			return vp;
+		}
+		free (vp);
+		vp = NULL;
+	}
+	else
+	{
+		rc_log(LOG_CRIT,"rc_avpair_new: out of memory");
+	}
+
+	return vp;
+}
+
+/*
+ *
+ * Function: rc_avpair_gen
+ *
+ * Purpose: takes attribute/value pairs from buffer and builds a
+ *	    value_pair list using allocated memory. Uses recursion.
+ *
+ * Returns: value_pair list or NULL on failure
+ */
+
+VALUE_PAIR *
+rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr,
+    int length, int vendorpec)
+{
+	int attribute, attrlen, x_len;
+	unsigned char const *x_ptr;
+	uint32_t lvalue;
+	DICT_ATTR *attr;
+	VALUE_PAIR *rpair;
+	char buffer[(AUTH_STRING_LEN * 2) + 1];
+	/* For hex string conversion. */
+	char hex[3];
+
+	if (length < 2) {
+		rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
+		    "invalid length");
+		goto shithappens;
+	}
+	attrlen = ptr[1];
+	if (length < attrlen || attrlen < 2) {
+		rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
+		    "invalid length");
+		goto shithappens;
+	}
+
+	/* Advance to the next attribute and process recursively */
+	if (length != attrlen) {
+		pair = rc_avpair_gen(rh, pair, ptr + attrlen, length - attrlen,
+		    vendorpec);
+		if (pair == NULL)
+			return NULL;
+	}
+
+	/* Actual processing */
+	attribute = ptr[0] | (vendorpec << 16);
+	ptr += 2;
+	attrlen -= 2;
+
+	/* VSA */
+	if (attribute == PW_VENDOR_SPECIFIC) {
+		if (attrlen < 4) {
+			rc_log(LOG_ERR, "rc_avpair_gen: received VSA "
+			    "attribute with invalid length");
+			goto shithappens;
+		}
+		memcpy(&lvalue, ptr, 4);
+		vendorpec = ntohl(lvalue);
+		if (rc_dict_getvend(rh, vendorpec) == NULL) {
+			/* Warn and skip over the unknown VSA */
+			rc_log(LOG_WARNING, "rc_avpair_gen: received VSA "
+			    "attribute with unknown Vendor-Id %d", vendorpec);
+			return pair;
+		}
+		/* Process recursively */
+		return rc_avpair_gen(rh, pair, ptr + 4, attrlen - 4,
+		    vendorpec);
+	}
+
+	/* Normal */
+	attr = rc_dict_getattr(rh, attribute);
+	if (attr == NULL) {
+		buffer[0] = '\0';	/* Initial length. */
+		x_ptr = ptr;
+		for (x_len = attrlen; x_len > 0; x_len--, x_ptr++) {
+			snprintf(hex, sizeof(hex), "%2.2X", x_ptr[0]);
+			strcat(buffer, hex);
+		}
+		if (vendorpec == 0) {
+			rc_log(LOG_WARNING, "rc_avpair_gen: received "
+			    "unknown attribute %d of length %d: 0x%s",
+			    attribute, attrlen + 2, buffer);
+		} else {
+			rc_log(LOG_WARNING, "rc_avpair_gen: received "
+			    "unknown VSA attribute %d, vendor %d of "
+			    "length %d: 0x%s", attribute & 0xffff,
+			    VENDOR(attribute), attrlen + 2, buffer);
+		}
+		goto shithappens;
+	}
+
+	rpair = malloc(sizeof(*rpair));
+	if (rpair == NULL) {
+		rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
+		goto shithappens;
+	}
+	memset(rpair, '\0', sizeof(*rpair));
+
+	/* Insert this new pair at the beginning of the list */
+	rpair->next = pair;
+	pair = rpair;
+	strcpy(pair->name, attr->name);
+	pair->attribute = attr->value;
+	pair->type = attr->type;
+
+	switch (attr->type) {
+	case PW_TYPE_STRING:
+		memcpy(pair->strvalue, (char *)ptr, (size_t)attrlen);
+		pair->strvalue[attrlen] = '\0';
+		pair->lvalue = attrlen;
+		break;
+
+	case PW_TYPE_INTEGER:
+		if (attrlen != 4) {
+			rc_log(LOG_ERR, "rc_avpair_gen: received INT "
+			    "attribute with invalid length");
+			goto shithappens;
+		}
+	case PW_TYPE_IPADDR:
+		if (attrlen != 4) {
+			rc_log(LOG_ERR, "rc_avpair_gen: received IPADDR"
+			    " attribute with invalid length");
+			goto shithappens;
+		}
+		memcpy((char *)&lvalue, (char *)ptr, 4);
+		pair->lvalue = ntohl(lvalue);
+		break;
+	case PW_TYPE_IPV6ADDR:
+		if (attrlen != 16) {
+			rc_log(LOG_ERR, "rc_avpair_gen: received IPV6ADDR"
+			    " attribute with invalid length");
+			goto shithappens;
+		}
+		memcpy(pair->strvalue, (char *)ptr, 16);
+		pair->lvalue = attrlen;
+		break;
+	case PW_TYPE_IPV6PREFIX:
+		if (attrlen > 18 || attrlen < 2) {
+			rc_log(LOG_ERR, "rc_avpair_gen: received IPV6PREFIX"
+			    " attribute with invalid length: %d", attrlen);
+			goto shithappens;
+		}
+		memcpy(pair->strvalue, (char *)ptr, attrlen);
+		pair->lvalue = attrlen;
+		break;
+	case PW_TYPE_DATE:
+		if (attrlen != 4) {
+			rc_log(LOG_ERR, "rc_avpair_gen: received DATE "
+			    "attribute with invalid length");
+			goto shithappens;
+		}
+
+	default:
+		rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type",
+		    attr->name);
+		goto shithappens;
+	}
+	return pair;
+
+shithappens:
+	while (pair != NULL) {
+		rpair = pair->next;
+		free(pair);
+		pair = rpair;
+	}
+	return NULL;
+}
+
+/*
+ * Function: rc_avpair_get
+ *
+ * Purpose: Find the first attribute value-pair (which matches the given
+ *          attribute) from the specified value-pair list.
+ *
+ * Returns: found value_pair
+ *
+ */
+
+VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, int attrid, int vendorpec)
+{
+	for (; vp != NULL && !(ATTRID(vp->attribute) == ATTRID(attrid) &&
+	    VENDOR(vp->attribute) == vendorpec); vp = vp->next)
+	{
+		continue;
+	}
+	return vp;
+}
+
+/*
+ * Function: rc_avpair_insert
+ *
+ * Purpose: Given the address of an existing list "a" and a pointer
+ *	    to an entry "p" in that list, add the value pair "b" to
+ *	    the "a" list after the "p" entry.  If "p" is NULL, add
+ *	    the value pair "b" to the end of "a".
+ *
+ */
+
+void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b)
+{
+	VALUE_PAIR     *this_node = NULL;
+	VALUE_PAIR     *vp;
+
+	if (b->next != NULL)
+	{
+		rc_log(LOG_CRIT, "rc_avpair_insert: value pair (0x%p) next ptr. (0x%p) not NULL", b, b->next);
+		abort ();
+	}
+
+	if (*a == NULL)
+	{
+		*a = b;
+		return;
+	}
+
+	vp = *a;
+
+	if ( p == NULL) /* run to end of "a" list */
+	{
+		while (vp != NULL)
+		{
+			this_node = vp;
+			vp = vp->next;
+		}
+	}
+	else /* look for the "p" entry in the "a" list */
+	{
+		this_node = *a;
+		while (this_node != NULL)
+		{
+			if (this_node == p)
+			{
+				break;
+			}
+			this_node = this_node->next;
+		}
+	}
+
+	b->next = this_node->next;
+	this_node->next = b;
+
+	return;
+}
+
+/*
+ * Function: rc_avpair_free
+ *
+ * Purpose: frees all value_pairs in the list
+ *
+ */
+
+void rc_avpair_free (VALUE_PAIR *pair)
+{
+	VALUE_PAIR     *next;
+
+	while (pair != NULL)
+	{
+		next = pair->next;
+		free (pair);
+		pair = next;
+	}
+}
+
+/*
+ * Function: rc_fieldcpy
+ *
+ * Purpose: Copy a data field from the buffer.  Advance the buffer
+ *          past the data field. Ensure that no more than len - 1
+ *          bytes are copied and that resulting string is terminated
+ *          with '\0'.
+ *
+ */
+
+static void
+rc_fieldcpy(char *string, char const **uptr, char const *stopat, size_t len)
+{
+	char const *ptr, *estring;
+
+	ptr = *uptr;
+	estring = string + len - 1;
+	if (*ptr == '"')
+	{
+		ptr++;
+		while (*ptr != '"' && *ptr != '\0' && *ptr != '\n')
+		{
+			if (string < estring)
+				*string++ = *ptr;
+			ptr++;
+		}
+		if (*ptr == '"')
+		{
+			ptr++;
+		}
+		*string = '\0';
+		*uptr = ptr;
+		return;
+	}
+
+	while (*ptr != '\0' && strchr(stopat, *ptr) == NULL)
+	{
+		if (string < estring)
+			*string++ = *ptr;
+		ptr++;
+	}
+	*string = '\0';
+	*uptr = ptr;
+	return;
+}
+
+
+/*
+ * Function: rc_avpair_parse
+ *
+ * Purpose: parses the buffer to extract the attribute-value pairs.
+ *
+ * Returns: 0 = successful parse of attribute-value pair,
+ *	   -1 = syntax (or other) error detected.
+ *
+ */
+
+#define PARSE_MODE_NAME		0
+#define PARSE_MODE_EQUAL	1
+#define PARSE_MODE_VALUE	2
+#define PARSE_MODE_INVALID	3
+
+int rc_avpair_parse (rc_handle const *rh, char const *buffer, VALUE_PAIR **first_pair)
+{
+	int             mode;
+	char            attrstr[AUTH_ID_LEN];
+	char            valstr[AUTH_STRING_LEN + 1], *p;
+	DICT_ATTR      *attr = NULL;
+	DICT_VALUE     *dval;
+	VALUE_PAIR     *pair;
+	VALUE_PAIR     *link;
+	struct tm      *tm;
+	time_t          timeval;
+
+	mode = PARSE_MODE_NAME;
+	while (*buffer != '\n' && *buffer != '\0')
+	{
+		if (*buffer == ' ' || *buffer == '\t')
+		{
+			buffer++;
+			continue;
+		}
+
+		switch (mode)
+		{
+		    case PARSE_MODE_NAME:		/* Attribute Name */
+			rc_fieldcpy (attrstr, &buffer, " \t\n=,", sizeof(attrstr));
+			if ((attr =
+				rc_dict_findattr (rh, attrstr)) == NULL)
+			{
+				rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute");
+				if (*first_pair) {
+					rc_avpair_free(*first_pair);
+					*first_pair = NULL;
+				}
+				return -1;
+			}
+			mode = PARSE_MODE_EQUAL;
+			break;
+
+		    case PARSE_MODE_EQUAL:		/* Equal sign */
+			if (*buffer == '=')
+			{
+				mode = PARSE_MODE_VALUE;
+				buffer++;
+			}
+			else
+			{
+				rc_log(LOG_ERR, "rc_avpair_parse: missing or misplaced equal sign");
+				if (*first_pair) {
+					rc_avpair_free(*first_pair);
+					*first_pair = NULL;
+				}
+				return -1;
+			}
+			break;
+
+		    case PARSE_MODE_VALUE:		/* Value */
+			rc_fieldcpy (valstr, &buffer, " \t\n,", sizeof(valstr));
+
+			if ((pair = malloc (sizeof (VALUE_PAIR))) == NULL)
+			{
+				rc_log(LOG_CRIT, "rc_avpair_parse: out of memory");
+				if (*first_pair) {
+					rc_avpair_free(*first_pair);
+					*first_pair = NULL;
+				}
+				return -1;
+			}
+			strcpy (pair->name, attr->name);
+			pair->attribute = attr->value;
+			pair->type = attr->type;
+
+			switch (pair->type)
+			{
+
+			    case PW_TYPE_STRING:
+				strcpy (pair->strvalue, valstr);
+				pair->lvalue = (uint32_t)strlen(valstr);
+				break;
+
+			    case PW_TYPE_INTEGER:
+				if (isdigit (*valstr))
+				{
+					pair->lvalue = atoi (valstr);
+				}
+				else
+				{
+					if ((dval = rc_dict_findval (rh, valstr))
+							== NULL)
+					{
+						rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute value: %s", valstr);
+						if (*first_pair) {
+							rc_avpair_free(*first_pair);
+							*first_pair = NULL;
+						}
+						free (pair);
+						return -1;
+					}
+					else
+					{
+						pair->lvalue = dval->value;
+					}
+				}
+				break;
+
+			    case PW_TYPE_IPADDR:
+                                pair->lvalue = rc_get_ipaddr(valstr);
+				break;
+
+			    case PW_TYPE_IPV6ADDR:
+			    	if (inet_pton(AF_INET6, valstr, pair->strvalue) == 0) {
+			    		rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 address %s", valstr);
+			    		free(pair);
+			    		return -1;
+			    	}
+				pair->lvalue = 16;
+				break;
+
+			    case PW_TYPE_IPV6PREFIX:
+			    	p = strchr(valstr, '/');
+			    	if (p == NULL) {
+			    		rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr);
+			    		free(pair);
+			    		return -1;
+			    	}
+			    	*p = 0;
+			    	p++;
+			    	pair->strvalue[0] = 0;
+			    	pair->strvalue[1] = atoi(p);
+
+			    	if (inet_pton(AF_INET6, valstr, pair->strvalue+2) == 0) {
+			    		rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr);
+			    		free(pair);
+			    		return -1;
+			    	}
+				pair->lvalue = 2+16;
+				break;
+
+			    case PW_TYPE_DATE:
+				timeval = time (0);
+				tm = localtime (&timeval);
+				tm->tm_hour = 0;
+				tm->tm_min = 0;
+				tm->tm_sec = 0;
+				rc_str2tm (valstr, tm);
+#ifdef TIMELOCAL
+				pair->lvalue = (uint32_t) timelocal (tm);
+#else	/* TIMELOCAL */
+				pair->lvalue = (uint32_t) mktime (tm);
+#endif	/* TIMELOCAL */
+				break;
+
+			    default:
+				rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute type %d", pair->type);
+				if (*first_pair) {
+					rc_avpair_free(*first_pair);
+					*first_pair = NULL;
+				}
+				free (pair);
+				return -1;
+			}
+
+			/* XXX: Fix up Digest-Attributes */
+			switch (pair->attribute) {
+			case PW_DIGEST_REALM:
+			case PW_DIGEST_NONCE:
+			case PW_DIGEST_METHOD:
+			case PW_DIGEST_URI:
+			case PW_DIGEST_QOP:
+			case PW_DIGEST_ALGORITHM:
+			case PW_DIGEST_BODY_DIGEST:
+			case PW_DIGEST_CNONCE:
+			case PW_DIGEST_NONCE_COUNT:
+			case PW_DIGEST_USER_NAME:
+				/* overlapping! */
+				if (pair->lvalue > AUTH_STRING_LEN - 2)
+					pair->lvalue = AUTH_STRING_LEN - 2;
+				memmove(&pair->strvalue[2], &pair->strvalue[0], pair->lvalue);
+				pair->strvalue[0] = pair->attribute - PW_DIGEST_REALM + 1;
+				pair->lvalue += 2;
+				pair->strvalue[1] = pair->lvalue;
+				pair->strvalue[pair->lvalue] = '\0';
+				pair->attribute = PW_DIGEST_ATTRIBUTES;
+			}
+
+			pair->next = NULL;
+
+			if (*first_pair == NULL)
+			{
+				*first_pair = pair;
+			}
+			else
+			{
+				link = *first_pair;
+				while (link->next != NULL)
+				{
+					link = link->next;
+				}
+				link->next = pair;
+			}
+
+			mode = PARSE_MODE_NAME;
+			break;
+
+		    default:
+			mode = PARSE_MODE_NAME;
+			break;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Function: rc_avpair_tostr
+ *
+ * Purpose: Translate an av_pair into two strings
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ */
+
+int rc_avpair_tostr (rc_handle const *rh, VALUE_PAIR *pair, char *name, int ln, char *value, int lv)
+{
+	DICT_VALUE     *dval;
+	char            buffer[32];
+	struct in_addr  inad;
+	unsigned char         *ptr;
+
+	*name = *value = '\0';
+
+	if (!pair || pair->name[0] == '\0') {
+		rc_log(LOG_ERR, "rc_avpair_tostr: pair is NULL or empty");
+		return -1;
+	}
+
+	strncpy(name, pair->name, (size_t) ln);
+
+	switch (pair->type)
+	{
+	    case PW_TYPE_STRING:
+	    	lv--;
+		ptr = (unsigned char *) pair->strvalue;
+		if (pair->attribute == PW_DIGEST_ATTRIBUTES) {
+			pair->strvalue[*(ptr + 1)] = '\0';
+			ptr += 2;
+		}
+		while (*ptr != '\0')
+		{
+			if (!(isprint (*ptr)))
+			{
+				snprintf (buffer, sizeof(buffer), "\\%03o", *ptr);
+				strncat(value, buffer, (size_t) lv);
+				lv -= 4;
+				if (lv < 0) break;
+			}
+			else
+			{
+				strncat(value, (char *)ptr, 1);
+				lv--;
+				if (lv <= 0) break;
+			}
+			ptr++;
+		}
+		break;
+
+	    case PW_TYPE_INTEGER:
+		dval = rc_dict_getval (rh, pair->lvalue, pair->name);
+		if (dval != NULL)
+		{
+			strncpy(value, dval->name, (size_t) lv-1);
+		}
+		else
+		{
+			snprintf(buffer, sizeof(buffer), "%ld", (long int)pair->lvalue);
+			strncpy(value, buffer, (size_t) lv);
+		}
+		break;
+
+	    case PW_TYPE_IPADDR:
+		inad.s_addr = htonl(pair->lvalue);
+		strncpy (value, inet_ntoa (inad), (size_t) lv-1);
+		break;
+
+	    case PW_TYPE_IPV6ADDR:
+	    	if (inet_ntop(AF_INET6, pair->strvalue, value, lv-1) == NULL)
+	    		return -1;
+		break;
+
+	    case PW_TYPE_IPV6PREFIX: {
+	    	uint8_t ip[16];
+	    	uint8_t txt[48];
+	    	if (pair->lvalue < 2)
+	    		return -1;
+
+	    	memset(ip, 0, sizeof(ip));
+	    	memcpy(ip, pair->strvalue+2, pair->lvalue-2);
+
+	    	if (inet_ntop(AF_INET6, ip, txt, sizeof(txt)) == NULL)
+	    		return -1;
+		snprintf(value, lv-1, "%s/%u", txt, (unsigned)pair->strvalue[1]);
+
+		break;
+	    }
+	    case PW_TYPE_DATE:
+		strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S",
+			  gmtime ((time_t *) & pair->lvalue));
+		strncpy(value, buffer, lv-1);
+		break;
+
+	    default:
+		rc_log(LOG_ERR, "rc_avpair_tostr: unknown attribute type %d", pair->type);
+		return -1;
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Function: rc_avpair_log
+ *
+ * Purpose: format sequence of attribute value pairs into printable
+ * string. The caller should provide a storage buffer and the buffer length.
+ * Returns pointer to provided storage buffer.
+ *
+ */
+char *
+rc_avpair_log(rc_handle const *rh, VALUE_PAIR *pair, char *buf, size_t buf_len)
+{
+	size_t len, nlen;
+	VALUE_PAIR *vp;
+	char name[33], value[256];
+
+	len = 0;
+	for (vp = pair; vp != NULL; vp = vp->next) {
+		if (rc_avpair_tostr(rh, vp, name, sizeof(name), value,
+		    sizeof(value)) == -1)
+		        return NULL;
+		nlen = len + 32 + 3 + strlen(value) + 2 + 2;
+		if(nlen<buf_len-1) {
+			sprintf(buf + len, "%-32s = '%s'\n", name, value);
+		} else return buf;
+		len = nlen - 1;
+	}
+	return buf;
+}
+
+/*
+ * Function: rc_avpair_readin
+ *
+ * Purpose: get a sequence of attribute value pairs from the file input
+ *	    and make them into a list of value_pairs
+ *
+ */
+
+VALUE_PAIR *rc_avpair_readin(rc_handle const *rh, FILE *input)
+{
+	VALUE_PAIR *vp = NULL;
+	char buffer[1024], *q;
+
+	while (fgets(buffer, sizeof(buffer), input) != NULL)
+	{
+		q = buffer;
+
+		while(*q && isspace(*q)) q++;
+
+		if ((*q == '\n') || (*q == '#') || (*q == '\0'))
+			continue;
+
+		if (rc_avpair_parse(rh, q, &vp) < 0) {
+			rc_log(LOG_ERR, "rc_avpair_readin: malformed attribute: %s", buffer);
+			rc_avpair_free(vp);
+			return NULL;
+		}
+	}
+
+	return vp;
+}
diff --git a/src/plugins/vbng/lib/buildreq.c b/src/plugins/vbng/lib/buildreq.c
new file mode 100644
index 0000000..a71b1f9
--- /dev/null
+++ b/src/plugins/vbng/lib/buildreq.c
@@ -0,0 +1,276 @@
+/*
+ * $Id: buildreq.c,v 1.17 2010/02/04 10:27:09 aland Exp $
+ *
+ * Copyright (C) 1995,1997 Lars Fenneberg
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+unsigned char rc_get_id();
+
+/*
+ * Function: rc_buildreq
+ *
+ * Purpose: builds a skeleton RADIUS request using information from the
+ * 	    config file.
+ *
+ */
+
+void rc_buildreq(rc_handle const *rh, SEND_DATA *data, int code, char *server, unsigned short port,
+		 char *secret, int timeout, int retries)
+{
+	data->server = server;
+	data->secret = secret;
+	data->svc_port = port;
+	data->seq_nbr = rc_get_id();
+	data->timeout = timeout;
+	data->retries = retries;
+	data->code = code;
+}
+
+/*
+ * Function: rc_get_id
+ *
+ * Purpose: generate random id
+ *
+ */
+
+unsigned char rc_get_id()
+{
+	return (unsigned char)(random() & UCHAR_MAX);
+}
+
+/*
+ * Function: rc_aaa
+ *
+ * Purpose: Builds an authentication/accounting request for port id client_port
+ *	    with the value_pairs send and submits it to a server
+ *
+ * Returns: received value_pairs in received, messages from the server in msg
+ *	    and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
+    char *msg, int add_nas_port, int request_type)
+{
+	SEND_DATA       data;
+	VALUE_PAIR	*adt_vp = NULL;
+	int		result;
+	int		i, skip_count;
+	SERVER		*aaaserver;
+	int		timeout = rc_conf_int(rh, "radius_timeout");
+	int		retries = rc_conf_int(rh, "radius_retries");
+	int		radius_deadtime = rc_conf_int(rh, "radius_deadtime");
+	double		start_time = 0;
+	double		now = 0;
+	time_t		dtime;
+
+	if (request_type != PW_ACCOUNTING_REQUEST) {
+		aaaserver = rc_conf_srv(rh, "authserver");
+	} else {
+		aaaserver = rc_conf_srv(rh, "acctserver");
+	}
+	if (aaaserver == NULL)
+		return ERROR_RC;
+
+	data.send_pairs = send;
+	data.receive_pairs = NULL;
+
+	if (add_nas_port != 0) {
+		/*
+		 * Fill in NAS-Port
+		 */
+		if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT,
+		    &client_port, 0, 0) == NULL)
+			return ERROR_RC;
+	}
+
+	if (request_type == PW_ACCOUNTING_REQUEST) {
+		/*
+		 * Fill in Acct-Delay-Time
+		 */
+		dtime = 0;
+		now = rc_getctime();
+		adt_vp = rc_avpair_get(data.send_pairs, PW_ACCT_DELAY_TIME, 0);
+		if (adt_vp == NULL) {
+			adt_vp = rc_avpair_add(rh, &(data.send_pairs),
+			    PW_ACCT_DELAY_TIME, &dtime, 0, 0);
+			if (adt_vp == NULL)
+				return ERROR_RC;
+			start_time = now;
+		} else {
+			start_time = now - adt_vp->lvalue;
+		}
+	}
+
+	skip_count = 0;
+	result = ERROR_RC;
+	for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC)
+	    ; i++, now = rc_getctime())
+	{
+		if (aaaserver->deadtime_ends[i] != -1 &&
+		    aaaserver->deadtime_ends[i] > start_time) {
+			skip_count++;
+			continue;
+		}
+		if (data.receive_pairs != NULL) {
+			rc_avpair_free(data.receive_pairs);
+			data.receive_pairs = NULL;
+		}
+		rc_buildreq(rh, &data, request_type, aaaserver->name[i],
+		    aaaserver->port[i], aaaserver->secret[i], timeout, retries);
+
+		if (request_type == PW_ACCOUNTING_REQUEST) {
+			dtime = now - start_time;
+			rc_avpair_assign(adt_vp, &dtime, 0);
+		}
+
+		result = rc_send_server (rh, &data, msg);
+		if (result == TIMEOUT_RC && radius_deadtime > 0)
+			aaaserver->deadtime_ends[i] = start_time + (double)radius_deadtime;
+	}
+	if (result == OK_RC || result == BADRESP_RC || skip_count == 0)
+		goto exit;
+
+	result = ERROR_RC;
+	for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC)
+	    ; i++)
+	{
+		if (aaaserver->deadtime_ends[i] == -1 ||
+		    aaaserver->deadtime_ends[i] <= start_time) {
+			continue;
+		}
+		if (data.receive_pairs != NULL) {
+			rc_avpair_free(data.receive_pairs);
+			data.receive_pairs = NULL;
+		}
+		rc_buildreq(rh, &data, request_type, aaaserver->name[i],
+		    aaaserver->port[i], aaaserver->secret[i], timeout, retries);
+
+		if (request_type == PW_ACCOUNTING_REQUEST) {
+			dtime = rc_getctime() - start_time;
+			rc_avpair_assign(adt_vp, &dtime, 0);
+		}
+
+		result = rc_send_server (rh, &data, msg);
+		if (result != TIMEOUT_RC)
+			aaaserver->deadtime_ends[i] = -1;
+	}
+
+exit:
+	if (request_type != PW_ACCOUNTING_REQUEST) {
+		*received = data.receive_pairs;
+	} else {
+		rc_avpair_free(data.receive_pairs);
+	}
+
+	return result;
+}
+
+/*
+ * Function: rc_auth
+ *
+ * Purpose: Builds an authentication request for port id client_port
+ *          with the value_pairs send and submits it to a server
+ *
+ * Returns: received value_pairs in received, messages from the server in msg (if non-NULL),
+ *          and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_auth(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
+    char *msg)
+{
+
+	return rc_aaa(rh, client_port, send, received, msg, 1, PW_ACCESS_REQUEST);
+}
+
+/*
+ * Function: rc_auth_proxy
+ *
+ * Purpose: Builds an authentication request
+ *	    with the value_pairs send and submits it to a server.
+ *	    Works for a proxy; does not add IP address, and does
+ *	    does not rely on config file.
+ *
+ * Returns: received value_pairs in received, messages from the server in msg (if non-NULL)
+ *	    and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_auth_proxy(rc_handle *rh, VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
+{
+
+	return rc_aaa(rh, 0, send, received, msg, 0, PW_ACCESS_REQUEST);
+}
+
+
+/*
+ * Function: rc_acct
+ *
+ * Purpose: Builds an accounting request for port id client_port
+ *	    with the value_pairs send
+ *
+ * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
+ *	    in by this function, the rest has to be supplied.
+ */
+
+int rc_acct(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send)
+{
+
+	return rc_aaa(rh, client_port, send, NULL, NULL, 1, PW_ACCOUNTING_REQUEST);
+}
+
+/*
+ * Function: rc_acct_proxy
+ *
+ * Purpose: Builds an accounting request with the value_pairs send
+ *
+ */
+
+int rc_acct_proxy(rc_handle *rh, VALUE_PAIR *send)
+{
+
+	return rc_aaa(rh, 0, send, NULL, NULL, 0, PW_ACCOUNTING_REQUEST);
+}
+
+/*
+ * Function: rc_check
+ *
+ * Purpose: ask the server hostname on the specified port for a
+ *	    status message
+ *
+ */
+
+int rc_check(rc_handle *rh, char *host, char *secret, unsigned short port, char *msg)
+{
+	SEND_DATA       data;
+	int		result;
+	uint32_t		service_type;
+	int		timeout = rc_conf_int(rh, "radius_timeout");
+	int		retries = rc_conf_int(rh, "radius_retries");
+
+	data.send_pairs = data.receive_pairs = NULL;
+
+	/*
+	 * Fill in Service-Type
+	 */
+
+	service_type = PW_ADMINISTRATIVE;
+	rc_avpair_add(rh, &(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, 0);
+
+	rc_buildreq(rh, &data, PW_STATUS_SERVER, host, port, secret, timeout, retries);
+	result = rc_send_server (rh, &data, msg);
+
+	rc_avpair_free(data.receive_pairs);
+
+	return result;
+}
diff --git a/src/plugins/vbng/lib/clientid.c b/src/plugins/vbng/lib/clientid.c
new file mode 100644
index 0000000..6901a04
--- /dev/null
+++ b/src/plugins/vbng/lib/clientid.c
@@ -0,0 +1,146 @@
+/*
+ * $Id: clientid.c,v 1.7 2007/07/11 17:29:29 cparker Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+struct map2id_s {
+	char *name;
+	uint32_t id;
+
+	struct map2id_s *next;
+};
+
+/*
+ * Function: rc_read_mapfile
+ *
+ * Purpose: Read in the ttyname to port id map file
+ *
+ * Arguments: the file name of the map file
+ *
+ * Returns: zero on success, negative integer on failure
+ */
+
+int rc_read_mapfile(rc_handle *rh, char const *filename)
+{
+	char buffer[1024];
+	FILE *mapfd;
+	char *c, *name, *id, *q;
+	struct map2id_s *p;
+	int lnr = 0;
+
+        if ((mapfd = fopen(filename,"r")) == NULL)
+        {
+		rc_log(LOG_ERR,"rc_read_mapfile: can't read %s: %s", filename, strerror(errno));
+		return -1;
+	}
+
+#define SKIP(p) while(*p && isspace(*p)) p++;
+
+        while (fgets(buffer, sizeof(buffer), mapfd) != NULL)
+        {
+        	lnr++;
+
+		q = buffer;
+
+                SKIP(q);
+
+                if ((*q == '\n') || (*q == '#') || (*q == '\0'))
+			continue;
+
+		if (( c = strchr(q, ' ')) || (c = strchr(q,'\t'))) {
+
+			*c = '\0'; c++;
+			SKIP(c);
+
+			name = q;
+			id = c;
+
+			if ((p = (struct map2id_s *)malloc(sizeof(*p))) == NULL) {
+				rc_log(LOG_CRIT,"rc_read_mapfile: out of memory");
+				fclose(mapfd);
+				return -1;
+			}
+
+			p->name = strdup(name);
+			p->id = atoi(id);
+			p->next = rh->map2id_list;
+			rh->map2id_list = p;
+
+		} else {
+
+			rc_log(LOG_ERR, "rc_read_mapfile: malformed line in %s, line %d", filename, lnr);
+			fclose(mapfd);
+			return -1;
+
+		}
+	}
+
+#undef SKIP
+
+	fclose(mapfd);
+
+	return 0;
+}
+
+/*
+ * Function: rc_map2id
+ *
+ * Purpose: Map ttyname to port id
+ *
+ * Arguments: full pathname of the tty
+ *
+ * Returns: port id, zero if no entry found
+ */
+
+uint32_t rc_map2id(rc_handle const *rh, char const *name)
+{
+	struct map2id_s *p;
+	char ttyname[PATH_MAX];
+
+	*ttyname = '\0';
+	if (*name != '/')
+		strcpy(ttyname, "/dev/");
+
+	strncat(ttyname, name, sizeof(ttyname)-strlen(ttyname)-1);
+
+	for(p = rh->map2id_list; p; p = p->next)
+		if (!strcmp(ttyname, p->name)) return p->id;
+
+	rc_log(LOG_WARNING,"rc_map2id: can't find tty %s in map database", ttyname);
+
+	return 0;
+}
+
+/*
+ * Function: rc_map2id_free
+ *
+ * Purpose: Free allocated map2id list
+ *
+ * Arguments: Radius Client handle
+ */
+
+void
+rc_map2id_free(rc_handle *rh)
+{
+	struct map2id_s *p, *np;
+
+	if (rh->map2id_list == NULL)
+		return;
+
+	for(p = rh->map2id_list; p != NULL; p = np) {
+		np = p->next;
+		free(p->name);
+		free(p);
+	}
+	rh->map2id_list = NULL;
+}
diff --git a/src/plugins/vbng/lib/config.c b/src/plugins/vbng/lib/config.c
new file mode 100644
index 0000000..1db7860
--- /dev/null
+++ b/src/plugins/vbng/lib/config.c
@@ -0,0 +1,925 @@
+/*
+ * $Id: config.c,v 1.23 2010/04/28 14:26:15 aland Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+#include <options.h>
+
+/*
+ * Function: find_option
+ *
+ * Purpose: find an option in the option list
+ *
+ * Returns: pointer to option on success, NULL otherwise
+ */
+
+static OPTION *find_option(rc_handle const *rh, char const *optname, unsigned int type)
+{
+	int 	i;
+
+	/* there're so few options that a binary search seems not necessary */
+	for (i = 0; i < NUM_OPTIONS; i++) {
+		if (!strcmp(rh->config_options[i].name, optname) &&
+		    (rh->config_options[i].type & type))
+		{
+		    	return &rh->config_options[i];
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Function: set_option_...
+ *
+ * Purpose: set a specific option doing type conversions
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+
+static int set_option_str(char const *filename, int line, OPTION *option, char const *p)
+{
+	if (p) {
+		option->val = (void *) strdup(p);
+		if (option->val == NULL) {
+			rc_log(LOG_CRIT, "read_config: out of memory");
+			return -1;
+		}
+	} else {
+		option->val = NULL;
+	}
+
+	return 0;
+}
+
+static int set_option_int(char const *filename, int line, OPTION *option, char const *p)
+{
+	int *iptr;
+
+	if (p == NULL) {
+		rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line);
+		return -1;
+	}
+
+	if ((iptr = malloc(sizeof(*iptr))) == NULL) {
+		rc_log(LOG_CRIT, "read_config: out of memory");
+		return -1;
+	}
+
+	*iptr = atoi(p);
+	option->val = (void *) iptr;
+
+	return 0;
+}
+
+static int set_option_srv(char const *filename, int line, OPTION *option, char const *p)
+{
+	SERVER *serv;
+	char *p_pointer;
+	char *p_dupe;
+	char *p_save;
+	char *q;
+	char *s;
+	struct servent *svp;
+
+	p_dupe = strdup(p);
+
+	if (p_dupe == NULL) {
+		rc_log(LOG_ERR, "%s: line %d: Invalid option or memory failure", filename, line);
+		return -1;
+	}
+
+	serv = (SERVER *) option->val;
+	if (serv == NULL) {
+		DEBUG(LOG_ERR, "option->val / server is NULL, allocating memory");
+		serv = malloc(sizeof(*serv));
+		if (serv == NULL) {
+			rc_log(LOG_CRIT, "read_config: out of memory");
+			free(p_dupe);
+			return -1;
+		}
+		memset(serv, 0, sizeof(*serv));
+		serv->max = 0;
+	}
+
+	p_pointer = strtok_r(p_dupe, ", \t", &p_save);
+
+	/* Check to see if we have 'servername:port' syntax */
+	if ((q = strchr(p_pointer,':')) != NULL) {
+		*q = '\0';
+		q++;
+
+		/* Check to see if we have 'servername:port:secret' syntax */
+		if((s = strchr(q,':')) != NULL) {
+			*s = '\0';
+			s++;
+			serv->secret[serv->max] = strdup(s);
+			if (serv->secret[serv->max] == NULL) {
+				rc_log(LOG_CRIT, "read_config: out of memory");
+				if (option->val == NULL) {
+					free(p_dupe);
+					free(serv);
+				}
+				return -1;
+			}
+		}
+	}
+	if(q && strlen(q) > 0) {
+		serv->port[serv->max] = atoi(q);
+	} else {
+		if (!strcmp(option->name,"authserver"))
+			if ((svp = getservbyname ("radius", "udp")) == NULL)
+				serv->port[serv->max] = PW_AUTH_UDP_PORT;
+			else
+				serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
+		else if (!strcmp(option->name, "acctserver"))
+			if ((svp = getservbyname ("radacct", "udp")) == NULL)
+				serv->port[serv->max] = PW_ACCT_UDP_PORT;
+			else
+				serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
+		else {
+			rc_log(LOG_ERR, "%s: line %d: no default port for %s", filename, line, option->name);
+			if (option->val == NULL) {
+				free(p_dupe);
+				free(serv);
+			}
+			return -1;
+		}
+	}
+
+	serv->name[serv->max] = strdup(p_pointer);
+	if (serv->name[serv->max] == NULL) {
+		rc_log(LOG_CRIT, "read_config: out of memory");
+		if (option->val == NULL) {
+			free(p_dupe);
+			free(serv);
+		}
+		return -1;
+	}
+	free(p_dupe);
+
+	serv->deadtime_ends[serv->max] = -1;
+	serv->max++;
+
+	if (option->val == NULL)
+		option->val = (void *)serv;
+
+	return 0;
+}
+
+static int set_option_auo(char const *filename, int line, OPTION *option, char const *p)
+{
+	int *iptr;
+	char *p_dupe = NULL;
+	char *p_pointer = NULL;
+	char *p_save = NULL;
+
+	p_dupe = strdup(p);
+
+	if (p_dupe == NULL) {
+		rc_log(LOG_WARNING, "%s: line %d: bogus option value", filename, line);
+		return -1;
+	}
+
+	if ((iptr = malloc(sizeof(iptr))) == NULL) {
+			rc_log(LOG_CRIT, "read_config: out of memory");
+			free(p_dupe);
+			return -1;
+	}
+
+	*iptr = 0;
+	/*if(strstr(p_dupe,", \t") != NULL) {*/
+		p_pointer = strtok_r(p_dupe, ", \t", &p_save);
+	/*}*/
+
+	if (!strncmp(p_pointer, "local", 5))
+			*iptr = AUTH_LOCAL_FST;
+	else if (!strncmp(p_pointer, "radius", 6))
+			*iptr = AUTH_RADIUS_FST;
+	else {
+		rc_log(LOG_ERR,"%s: auth_order: unknown keyword: %s", filename, p);
+		free(iptr);
+		free(p_dupe);
+		return -1;
+	}
+
+	p_pointer = strtok_r(NULL, ", \t", &p_save);
+
+	if (p_pointer && (*p_pointer != '\0')) {
+		if ((*iptr & AUTH_RADIUS_FST) && !strcmp(p_pointer, "local"))
+			*iptr = (*iptr) | AUTH_LOCAL_SND;
+		else if ((*iptr & AUTH_LOCAL_FST) && !strcmp(p_pointer, "radius"))
+			*iptr = (*iptr) | AUTH_RADIUS_SND;
+		else {
+			rc_log(LOG_ERR,"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
+			free(iptr);
+			free(p_dupe);
+			return -1;
+		}
+	}
+
+	option->val = (void *) iptr;
+
+	free(p_dupe);
+	return 0;
+}
+
+
+/* Function: rc_add_config
+ *
+ * Purpose: allow a config option to be added to rc_handle from inside a program
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+
+int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
+{
+	OPTION *option;
+
+	if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
+	{
+		rc_log(LOG_ERR, "ERROR: unrecognized option: %s", option_name);
+		return -1;
+	}
+
+	if (option->status != ST_UNDEF)
+	{
+		rc_log(LOG_ERR, "ERROR: duplicate option: %s", option_name);
+		return -1;
+	}
+
+	switch (option->type) {
+		case OT_STR:
+			if (set_option_str(source, line, option, option_val) < 0) {
+				return -1;
+			}
+			break;
+		case OT_INT:
+			if (set_option_int(source, line, option, option_val) < 0) {
+				return -1;
+			}
+			break;
+		case OT_SRV:
+			if (set_option_srv(source, line, option, option_val) < 0) {
+				return -1;
+			}
+			break;
+		case OT_AUO:
+			if (set_option_auo(source, line, option, option_val) < 0) {
+				return -1;
+			}
+			break;
+		default:
+			rc_log(LOG_CRIT, "rc_add_config: impossible case branch!");
+			abort();
+	}
+	return 0;
+}
+
+/*
+ * Function: rc_config_init
+ *
+ * Purpose: initialize the configuration structure from an external program.  For use when not
+ * running a standalone client that reads from a config file.
+ *
+ * Returns: rc_handle on success, NULL on failure
+ */
+
+rc_handle *
+rc_config_init(rc_handle *rh)
+{
+	int i;
+	SERVER *authservers;
+	SERVER *acctservers;
+	OPTION *acct;
+	OPTION *auth;
+
+        rh->config_options = malloc(sizeof(config_options_default));
+        if (rh->config_options == NULL)
+	{
+                rc_log(LOG_CRIT, "rc_config_init: out of memory");
+		rc_destroy(rh);
+                return NULL;
+        }
+        memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
+
+	acct = find_option(rh, "acctserver", OT_ANY);
+	auth = find_option(rh, "authserver", OT_ANY);
+	authservers = malloc(sizeof(SERVER));
+	acctservers = malloc(sizeof(SERVER));
+
+	if(authservers == NULL || acctservers == NULL)
+	{
+                rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
+		rc_destroy(rh);
+		if(authservers) free(authservers);
+		if(acctservers) free(acctservers);
+                return NULL;
+	}
+
+
+	authservers->max = 0;
+	acctservers->max = 0;
+
+	for(i=0; i < SERVER_MAX; i++)
+	{
+		authservers->name[i] = NULL;
+		authservers->secret[i] = NULL;
+		acctservers->name[i] = NULL;
+		acctservers->secret[i] = NULL;
+	}
+	acct->val = acctservers;
+	auth->val = authservers;
+	return rh;
+}
+
+
+/*
+ * Function: rc_read_config
+ *
+ * Purpose: read the global config file
+ *
+ * Returns: new rc_handle on success, NULL when failure
+ */
+
+rc_handle *
+rc_read_config(char const *filename)
+{
+	FILE *configfd;
+	char buffer[512], *p;
+	OPTION *option;
+	int line;
+	size_t pos;
+	rc_handle *rh;
+
+	srandom((unsigned int)(time(NULL)+getpid()));
+
+	rh = rc_new();
+	if (rh == NULL)
+		return NULL;
+
+        rh->config_options = malloc(sizeof(config_options_default));
+        if (rh->config_options == NULL) {
+                rc_log(LOG_CRIT, "rc_read_config: out of memory");
+		rc_destroy(rh);
+                return NULL;
+        }
+        memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
+
+	if ((configfd = fopen(filename,"r")) == NULL)
+	{
+		rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno));
+		rc_destroy(rh);
+		return NULL;
+	}
+
+	line = 0;
+	while ((fgets(buffer, sizeof(buffer), configfd) != NULL))
+	{
+		line++;
+		p = buffer;
+
+		if ((*p == '\n') || (*p == '#') || (*p == '\0'))
+			continue;
+
+		p[strlen(p)-1] = '\0';
+
+
+		if ((pos = strcspn(p, "\t ")) == 0) {
+			rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p);
+			fclose(configfd);
+			rc_destroy(rh);
+			return NULL;
+		}
+
+		p[pos] = '\0';
+
+		if ((option = find_option(rh, p, OT_ANY)) == NULL) {
+			rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p);
+			fclose(configfd);
+			rc_destroy(rh);
+			return NULL;
+		}
+
+		if (option->status != ST_UNDEF) {
+			rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p);
+			fclose(configfd);
+			rc_destroy(rh);
+			return NULL;
+		}
+
+		p += pos+1;
+		while (isspace(*p))
+			p++;
+		pos = strlen(p) - 1;
+		while(pos != 0 && isspace(p[pos]))
+			pos--;
+		p[pos + 1] = '\0';
+
+		switch (option->type) {
+			case OT_STR:
+				if (set_option_str(filename, line, option, p) < 0) {
+					fclose(configfd);
+					rc_destroy(rh);
+				 	return NULL;
+				}
+				break;
+			case OT_INT:
+				if (set_option_int(filename, line, option, p) < 0) {
+					fclose(configfd);
+					rc_destroy(rh);
+				 	return NULL;
+				}
+				break;
+			case OT_SRV:
+				if (set_option_srv(filename, line, option, p) < 0) {
+					fclose(configfd);
+					rc_destroy(rh);
+				 	return NULL;
+				}
+				break;
+			case OT_AUO:
+				if (set_option_auo(filename, line, option, p) < 0) {
+					fclose(configfd);
+					rc_destroy(rh);
+				 	return NULL;
+				}
+				break;
+			default:
+				rc_log(LOG_CRIT, "rc_read_config: impossible case branch!");
+				abort();
+		}
+	}
+	fclose(configfd);
+
+	if (test_config(rh, filename) == -1) {
+		rc_destroy(rh);
+		return NULL;
+	}
+	return rh;
+}
+
+/*
+ * Function: rc_conf_str, rc_conf_int, rc_conf_src
+ *
+ * Purpose: get the value of a config option
+ *
+ * Returns: config option value
+ */
+
+char *rc_conf_str(rc_handle const *rh, char const *optname)
+{
+	OPTION *option;
+
+	option = find_option(rh, optname, OT_STR);
+
+	if (option != NULL) {
+		return (char *)option->val;
+	} else {
+		rc_log(LOG_CRIT, "rc_conf_str: unkown config option requested: %s", optname);
+		abort();
+		return NULL;
+	}
+}
+
+int rc_conf_int(rc_handle const *rh, char const *optname)
+{
+	OPTION *option;
+
+	option = find_option(rh, optname, OT_INT|OT_AUO);
+
+	if (option != NULL) {
+		if (option->val) {
+			return *((int *)option->val);
+		} else {
+			rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname);
+			return 0;
+		}
+	} else {
+		rc_log(LOG_CRIT, "rc_conf_int: unkown config option requested: %s", optname);
+		abort();
+		return 0;
+	}
+}
+
+SERVER *rc_conf_srv(rc_handle const *rh, char const *optname)
+{
+	OPTION *option;
+
+	option = find_option(rh, optname, OT_SRV);
+
+	if (option != NULL) {
+		return (SERVER *)option->val;
+	} else {
+		rc_log(LOG_CRIT, "rc_conf_srv: unkown config option requested: %s", optname);
+		abort();
+		return NULL;
+	}
+}
+
+/*
+ * Function: test_config
+ *
+ * Purpose: test the configuration the user supplied
+ *
+ * Returns: 0 on success, -1 when failure
+ */
+
+int test_config(rc_handle const *rh, char const *filename)
+{
+#if 0
+	struct stat st;
+	char	    *file;
+#endif
+
+	if (!(rc_conf_srv(rh, "authserver")->max))
+	{
+		rc_log(LOG_ERR,"%s: no authserver specified", filename);
+		return -1;
+	}
+	if (!(rc_conf_srv(rh, "acctserver")->max))
+	{
+		rc_log(LOG_ERR,"%s: no acctserver specified", filename);
+		return -1;
+	}
+	if (!rc_conf_str(rh, "servers"))
+	{
+		rc_log(LOG_ERR,"%s: no servers file specified", filename);
+		return -1;
+	}
+	if (!rc_conf_str(rh, "dictionary"))
+	{
+		rc_log(LOG_ERR,"%s: no dictionary specified", filename);
+		return -1;
+	}
+
+	if (rc_conf_int(rh, "radius_timeout") <= 0)
+	{
+		rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
+		return -1;
+	}
+	if (rc_conf_int(rh, "radius_retries") <= 0)
+	{
+		rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
+		return -1;
+	}
+	if (rc_conf_int(rh, "radius_deadtime") < 0)
+	{
+		rc_log(LOG_ERR,"%s: radius_deadtime is illegal", filename);
+		return -1;
+	}
+#if 0
+	file = rc_conf_str(rh, "login_local");
+	if (stat(file, &st) == 0)
+	{
+		if (!S_ISREG(st.st_mode)) {
+			rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file);
+			return -1;
+		}
+	} else {
+		rc_log(LOG_ERR,"%s: file not found: %s", filename, file);
+		return -1;
+	}
+	file = rc_conf_str(rh, "login_radius");
+	if (stat(file, &st) == 0)
+	{
+		if (!S_ISREG(st.st_mode)) {
+			rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file);
+			return -1;
+		}
+	} else {
+		rc_log(LOG_ERR,"%s: file not found: %s", filename, file);
+		return -1;
+	}
+#endif
+
+	if (rc_conf_int(rh, "login_tries") <= 0)
+	{
+		rc_log(LOG_ERR,"%s: login_tries <= 0 is illegal", filename);
+		return -1;
+	}
+	if (rc_conf_str(rh, "seqfile") == NULL)
+	{
+		rc_log(LOG_ERR,"%s: seqfile not specified", filename);
+		return -1;
+	}
+	if (rc_conf_int(rh, "login_timeout") <= 0)
+	{
+		rc_log(LOG_ERR,"%s: login_timeout <= 0 is illegal", filename);
+		return -1;
+	}
+	if (rc_conf_str(rh, "mapfile") == NULL)
+	{
+		rc_log(LOG_ERR,"%s: mapfile not specified", filename);
+		return -1;
+	}
+	if (rc_conf_str(rh, "nologin") == NULL)
+	{
+		rc_log(LOG_ERR,"%s: nologin not specified", filename);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Function: rc_find_match
+ *
+ * Purpose: see if ip_addr is one of the ip addresses of hostname
+ *
+ * Returns: 0 on success, -1 when failure
+ *
+ */
+
+static int find_match (uint32_t *ip_addr, char const *hostname)
+{
+
+	uint32_t           addr;
+	char          **paddr;
+	struct hostent *hp;
+
+	if (rc_good_ipaddr (hostname) == 0)
+	{
+		if (*ip_addr == ntohl(inet_addr (hostname)))
+		{
+			return 0;
+		}
+		return -1;
+	}
+
+	if ((hp = rc_gethostbyname(hostname)) == NULL)
+	{
+		return -1;
+	}
+
+	for (paddr = hp->h_addr_list; *paddr; paddr++)
+	{
+		addr = ** (uint32_t **) paddr;
+		if (ntohl(addr) == *ip_addr)
+		{
+			return 0;
+		}
+	}
+	return -1;
+}
+
+/*
+ * Function: rc_ipaddr_local
+ *
+ * Purpose: checks if provided address is local address
+ *
+ * Returns: 0 if local, 1 if not local, -1 on failure
+ *
+ */
+
+static int
+rc_ipaddr_local(uint32_t ip_addr)
+{
+	int temp_sock, res, serrno;
+	struct sockaddr_in sin;
+
+	temp_sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (temp_sock == -1)
+		return -1;
+	memset(&sin, '\0', sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = htonl(ip_addr);
+	sin.sin_port = htons(0);
+	res = bind(temp_sock, (struct sockaddr *)&sin, sizeof(sin));
+	serrno = errno;
+	close(temp_sock);
+	if (res == 0)
+		return 0;
+	if (serrno == EADDRNOTAVAIL)
+		return 1;
+	return -1;
+}
+
+/*
+ * Function: rc_is_myname
+ *
+ * Purpose: check if provided name refers to ourselves
+ *
+ * Returns: 0 if yes, 1 if no and -1 on failure
+ *
+ */
+
+static int
+rc_is_myname(char const *hostname)
+{
+	uint32_t 	addr;
+	char 	**paddr;
+	struct 	hostent *hp;
+	int	res;
+
+	if (rc_good_ipaddr(hostname) == 0)
+		return rc_ipaddr_local(ntohl(inet_addr(hostname)));
+
+	if ((hp = rc_gethostbyname(hostname)) == NULL)
+		return -1;
+	for (paddr = hp->h_addr_list; *paddr; paddr++) {
+		addr = **(uint32_t **)paddr;
+		res = rc_ipaddr_local(ntohl(addr));
+		if (res == 0 || res == -1)
+			return res;
+	}
+	return 1;
+}
+
+/*
+ * Function: rc_find_server
+ *
+ * Purpose: locate a server in the rh config or if not found, check for a servers file
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ */
+
+int rc_find_server (rc_handle const *rh, char const *server_name, uint32_t *ip_addr, char *secret)
+{
+	int		i;
+	size_t          len;
+	int             result = 0;
+	FILE           *clientfd;
+	char           *h;
+	char           *s;
+	char            buffer[128];
+	char            hostnm[AUTH_ID_LEN + 1];
+	char	       *buffer_save;
+	char	       *hostnm_save;
+	SERVER	       *authservers;
+	SERVER	       *acctservers;
+
+	/* Lookup the IP address of the radius server */
+	if ((*ip_addr = rc_get_ipaddr (server_name)) == (uint32_t) 0)
+		return -1;
+
+	/* Check to see if the server secret is defined in the rh config */
+	if( (authservers = rc_conf_srv(rh, "authserver")) != NULL )
+	{
+		for( i = 0; i < authservers->max; i++ )
+		{
+			if( (strncmp(server_name, authservers->name[i], strlen(server_name)) == 0) &&
+			    (authservers->secret[i] != NULL) )
+			{
+				memset (secret, '\0', MAX_SECRET_LENGTH);
+				len = strlen (authservers->secret[i]);
+				if (len > MAX_SECRET_LENGTH)
+				{
+					len = MAX_SECRET_LENGTH;
+				}
+				strncpy (secret, authservers->secret[i], (size_t) len);
+				secret[MAX_SECRET_LENGTH] = '\0';
+				return 0;
+			}
+		}
+	}
+
+	if( (acctservers = rc_conf_srv(rh, "acctserver")) != NULL )
+	{
+		for( i = 0; i < acctservers->max; i++ )
+		{
+			if( (strncmp(server_name, acctservers->name[i], strlen(server_name)) == 0) &&
+			    (acctservers->secret[i] != NULL) )
+			{
+				memset (secret, '\0', MAX_SECRET_LENGTH);
+				len = strlen (acctservers->secret[i]);
+				if (len > MAX_SECRET_LENGTH)
+				{
+					len = MAX_SECRET_LENGTH;
+				}
+				strncpy (secret, acctservers->secret[i], (size_t) len);
+				secret[MAX_SECRET_LENGTH] = '\0';
+				return 0;
+			}
+		}
+	}
+
+	/* We didn't find it in the rh_config or the servername is too long so look for a
+	 * servers file to define the secret(s)
+	 */
+
+	if ((clientfd = fopen (rc_conf_str(rh, "servers"), "r")) == NULL)
+	{
+		rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers"));
+		return -1;
+	}
+
+	while (fgets (buffer, sizeof (buffer), clientfd) != NULL)
+	{
+		if (*buffer == '#')
+			continue;
+
+		if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */
+			continue;
+
+		memset (hostnm, '\0', AUTH_ID_LEN);
+		len = strlen (h);
+		if (len > AUTH_ID_LEN)
+		{
+			len = AUTH_ID_LEN;
+		}
+		strncpy (hostnm, h, (size_t) len);
+		hostnm[AUTH_ID_LEN] = '\0';
+
+		if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */
+			continue;
+
+		memset (secret, '\0', MAX_SECRET_LENGTH);
+		len = strlen (s);
+		if (len > MAX_SECRET_LENGTH)
+		{
+			len = MAX_SECRET_LENGTH;
+		}
+		strncpy (secret, s, (size_t) len);
+		secret[MAX_SECRET_LENGTH] = '\0';
+
+		if (!strchr (hostnm, '/')) /* If single name form */
+		{
+			if (find_match (ip_addr, hostnm) == 0)
+			{
+				result++;
+				break;
+			}
+		}
+		else /* <name1>/<name2> "paired" form */
+		{
+			strtok_r(hostnm, "/", &hostnm_save);
+			if (rc_is_myname(hostnm) == 0)
+			{	     /* If we're the 1st name, target is 2nd */
+				if (find_match (ip_addr, hostnm_save) == 0)
+				{
+					result++;
+					break;
+				}
+			}
+			else	/* If we were 2nd name, target is 1st name */
+			{
+				if (find_match (ip_addr, hostnm) == 0)
+				{
+					result++;
+					break;
+				}
+			}
+		}
+	}
+	fclose (clientfd);
+	if (result == 0)
+	{
+		memset (buffer, '\0', sizeof (buffer));
+		memset (secret, '\0', MAX_SECRET_LENGTH);
+		rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s",
+			 server_name, rc_conf_str(rh, "servers"));
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Function: rc_config_free
+ *
+ * Purpose: Free allocated config values
+ *
+ * Arguments: Radius Client handle
+ */
+
+void
+rc_config_free(rc_handle *rh)
+{
+	int i, j;
+	SERVER *serv;
+
+	if (rh->config_options == NULL)
+		return;
+
+	for (i = 0; i < NUM_OPTIONS; i++) {
+		if (rh->config_options[i].val == NULL)
+			continue;
+		if (rh->config_options[i].type == OT_SRV) {
+		        serv = (SERVER *)rh->config_options[i].val;
+			for (j = 0; j < serv->max; j++){
+				free(serv->name[j]);
+				if(serv->secret[j]) free(serv->secret[j]);
+			}
+			free(serv);
+		} else {
+			free(rh->config_options[i].val);
+		}
+	}
+	free(rh->config_options);
+	rh->config_options = NULL;
+}
diff --git a/src/plugins/vbng/lib/dict.c b/src/plugins/vbng/lib/dict.c
new file mode 100644
index 0000000..84dbba0
--- /dev/null
+++ b/src/plugins/vbng/lib/dict.c
@@ -0,0 +1,519 @@
+/*
+ * $Id: dict.c,v 1.10 2007/07/11 17:29:29 cparker Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+/*
+ * Function: rc_read_dictionary
+ *
+ * Purpose: Initialize the dictionary.  Read all ATTRIBUTES into
+ *	    the dictionary_attributes list.  Read all VALUES into
+ *	    the dictionary_values list.
+ *
+ */
+
+int rc_read_dictionary (rc_handle *rh, char const *filename)
+{
+	FILE           *dictfd;
+	char            dummystr[AUTH_ID_LEN];
+	char            namestr[AUTH_ID_LEN];
+	char            valstr[AUTH_ID_LEN];
+	char            attrstr[AUTH_ID_LEN];
+	char            typestr[AUTH_ID_LEN];
+	char		optstr[AUTH_ID_LEN];
+	char		*cp, *ifilename;
+	int             line_no;
+	DICT_ATTR      *attr;
+	DICT_VALUE     *dval;
+	DICT_VENDOR    *dvend;
+	char            buffer[256];
+	int             value;
+	int             type;
+	unsigned attr_vendorspec = 0;
+
+	if ((dictfd = fopen (filename, "r")) == NULL)
+	{
+		rc_log(LOG_ERR, "rc_read_dictionary: couldn't open dictionary %s: %s",
+				filename, strerror(errno));
+		return -1;
+	}
+
+	line_no = 0;
+	while (fgets (buffer, sizeof (buffer), dictfd) != NULL)
+	{
+		line_no++;
+
+		/* Skip empty space */
+		if (*buffer == '#' || *buffer == '\0' || *buffer == '\n' || \
+		    *buffer == '\r')
+		{
+			continue;
+		}
+
+		/* Strip out comments */
+		cp = strchr(buffer, '#');
+		if (cp != NULL)
+		{
+			*cp = '\0';
+		}
+
+		if (strncmp (buffer, "ATTRIBUTE", 9) == 0)
+		{
+			optstr[0] = '\0';
+			/* Read the ATTRIBUTE line */
+			if (sscanf (buffer, "%63s%63s%63s%63s%63s", dummystr, namestr,
+				    valstr, typestr, optstr) < 4)
+			{
+				rc_log(LOG_ERR, "rc_read_dictionary: invalid attribute on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			/*
+			 * Validate all entries
+			 */
+			if (strlen (namestr) > NAME_LENGTH)
+			{
+				rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			if (!isdigit (*valstr))
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid value on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+			value = atoi (valstr);
+
+			if (strcmp (typestr, "string") == 0)
+			{
+				type = PW_TYPE_STRING;
+			}
+			else if (strcmp (typestr, "integer") == 0)
+			{
+				type = PW_TYPE_INTEGER;
+			}
+			else if (strcmp (typestr, "ipaddr") == 0)
+			{
+				type = PW_TYPE_IPADDR;
+			}
+			else if (strcmp (typestr, "ipv6addr") == 0)
+			{
+				type = PW_TYPE_IPV6ADDR;
+			}
+			else if (strcmp (typestr, "ipv6prefix") == 0)
+			{
+				type = PW_TYPE_IPV6PREFIX;
+			}
+			else if (strcmp (typestr, "date") == 0)
+			{
+				type = PW_TYPE_DATE;
+			}
+			else
+			{
+				rc_log(LOG_ERR,
+				  "rc_read_dictionary: invalid type on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			dvend = NULL;
+			if (optstr[0] != '\0') {
+				char *cp1;
+				for (cp1 = optstr; cp1 != NULL; cp1 = cp) {
+					cp = strchr(cp1, ',');
+					if (cp != NULL) {
+						*cp = '\0';
+						cp++;
+					}
+					if (strncmp(cp1, "vendor=", 7) == 0)
+						cp1 += 7;
+					dvend = rc_dict_findvend(rh, cp1);
+					if (dvend == NULL) {
+						rc_log(LOG_ERR,
+						 "rc_read_dictionary: unknown Vendor-Id %s on line %d of dictionary %s",
+							 cp1, line_no, filename);
+						fclose(dictfd);
+						return -1;
+					}
+				}
+			}
+
+			/* Create a new attribute for the list */
+			if ((attr = malloc (sizeof (DICT_ATTR))) == NULL)
+			{
+				rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
+				fclose(dictfd);
+				return -1;
+			}
+			strcpy (attr->name, namestr);
+			attr->value = value | (attr_vendorspec << 16);
+			attr->type = type;
+
+			if (dvend != NULL) {
+				attr->value = value | (dvend->vendorpec << 16);
+			} else {
+				attr->value = value | (attr_vendorspec << 16);
+			}
+
+			/* Insert it into the list */
+			attr->next = rh->dictionary_attributes;
+			rh->dictionary_attributes = attr;
+		}
+		else if (strncmp (buffer, "VALUE", 5) == 0)
+		{
+			/* Read the VALUE line */
+			if (sscanf (buffer, "%63s%63s%63s%63s", dummystr, attrstr,
+				    namestr, valstr) != 4)
+			{
+				rc_log(LOG_ERR,
+			   "rc_read_dictionary: invalid value entry on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			/*
+			 * Validate all entries
+			 */
+			if (strlen (attrstr) > NAME_LENGTH)
+			{
+				rc_log(LOG_ERR,
+		      "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			if (strlen (namestr) > NAME_LENGTH)
+			{
+				rc_log(LOG_ERR,
+			   "rc_read_dictionary: invalid name length on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			if (!isdigit (*valstr))
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid value on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+			value = atoi (valstr);
+
+			/* Create a new VALUE entry for the list */
+			if ((dval = malloc (sizeof (DICT_VALUE))) == NULL)
+			{
+				rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
+				fclose(dictfd);
+				return -1;
+			}
+			strcpy (dval->attrname, attrstr);
+			strcpy (dval->name, namestr);
+			dval->value = value;
+
+			/* Insert it into the list */
+			dval->next = rh->dictionary_values;
+			rh->dictionary_values = dval;
+		}
+                else if (strncmp (buffer, "$INCLUDE", 8) == 0)
+                {
+			/* Read the $INCLUDE line */
+			if (sscanf (buffer, "%63s%63s", dummystr, namestr) != 2)
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid include entry on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+			ifilename = namestr;
+			/* Append directory if necessary */
+			if (namestr[0] != '/') {
+				cp = strrchr(filename, '/');
+				if (cp != NULL) {
+					ifilename = alloca(AUTH_ID_LEN);
+					*cp = '\0';
+					snprintf(ifilename, AUTH_ID_LEN, "%s/%s", filename, namestr);
+					*cp = '/';
+				}
+			}
+			if (rc_read_dictionary(rh, ifilename) < 0)
+			{
+				fclose(dictfd);
+				return -1;
+			}
+		}
+		else if (strncmp (buffer, "END-VENDOR", 10) == 0)
+		{
+			attr_vendorspec = 0;
+		}
+		else if (strncmp (buffer, "BEGIN-VENDOR", 12) == 0)
+		{
+			DICT_VENDOR *v;
+			/* Read the vendor name */
+			if (sscanf (buffer+12, "%63s", dummystr) != 1)
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			v = rc_dict_findvend(rh, dummystr);
+			if (v == NULL) {
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: unknown Vendor %s on line %d of dictionary %s",
+					 dummystr, line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			attr_vendorspec = v->vendorpec;
+		}
+		else if (strncmp (buffer, "VENDOR", 6) == 0)
+		{
+			/* Read the VALUE line */
+			if (sscanf (buffer, "%63s%63s%63s", dummystr, attrstr, valstr) != 3)
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			/* Validate all entries */
+			if (strlen (attrstr) > NAME_LENGTH)
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+
+			if (!isdigit (*valstr))
+			{
+				rc_log(LOG_ERR,
+				 "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
+					 line_no, filename);
+				fclose(dictfd);
+				return -1;
+			}
+			value = atoi (valstr);
+
+			/* Create a new VENDOR entry for the list */
+			dvend = malloc(sizeof(DICT_VENDOR));
+			if (dvend == NULL)
+			{
+				rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
+				fclose(dictfd);
+				return -1;
+			}
+			strcpy (dvend->vendorname, attrstr);
+			dvend->vendorpec = value;
+
+			/* Insert it into the list */
+			dvend->next = rh->dictionary_vendors;
+			rh->dictionary_vendors = dvend;
+                }
+	}
+	fclose (dictfd);
+	return 0;
+}
+
+/*
+ * Function: rc_dict_getattr
+ *
+ * Purpose: Return the full attribute structure based on the
+ *	    attribute id number.
+ *
+ */
+
+DICT_ATTR *rc_dict_getattr (rc_handle const *rh, int attribute)
+{
+	DICT_ATTR      *attr;
+
+	attr = rh->dictionary_attributes;
+	while (attr != NULL)
+	{
+		if (attr->value == attribute)
+		{
+			return attr;
+		}
+		attr = attr->next;
+	}
+	return NULL;
+}
+
+/*
+ * Function: rc_dict_findattr
+ *
+ * Purpose: Return the full attribute structure based on the
+ *	    attribute name.
+ *
+ */
+
+DICT_ATTR *rc_dict_findattr (rc_handle const *rh, char const *attrname)
+{
+	DICT_ATTR      *attr;
+
+	attr = rh->dictionary_attributes;
+	while (attr != NULL)
+	{
+		if (strcasecmp (attr->name, attrname) == 0)
+		{
+			return attr;
+		}
+		attr = attr->next;
+	}
+	return NULL;
+}
+
+
+/*
+ * Function: rc_dict_findval
+ *
+ * Purpose: Return the full value structure based on the
+ *         value name.
+ *
+ */
+
+DICT_VALUE *rc_dict_findval (rc_handle const *rh, char const *valname)
+{
+	DICT_VALUE     *val;
+
+	val = rh->dictionary_values;
+	while (val != NULL)
+	{
+		if (strcasecmp (val->name, valname) == 0)
+		{
+			return val;
+		}
+		val = val->next;
+	}
+	return NULL;
+}
+
+/*
+ * Function: rc_dict_findvend
+ *
+ * Purpose: Return the full vendor structure based on the
+ *          vendor name.
+ *
+ */
+
+DICT_VENDOR *
+rc_dict_findvend(rc_handle const *rh, char const *vendorname)
+{
+	DICT_VENDOR	*vend;
+
+	for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next)
+		if (strcasecmp(vend->vendorname, vendorname) == 0)
+			return vend;
+	return NULL;
+}
+
+/*
+ * Function: rc_dict_getvend
+ *
+ * Purpose: Return the full vendor structure based on the
+ *          vendor id number.
+ *
+ */
+
+DICT_VENDOR *
+rc_dict_getvend (rc_handle const *rh, int vendorpec)
+{
+        DICT_VENDOR      *vend;
+
+	for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next)
+		if (vend->vendorpec == vendorpec)
+			return vend;
+	return NULL;
+}
+
+/*
+ * Function: dict_getval
+ *
+ * Purpose: Return the full value structure based on the
+ *          actual value and the associated attribute name.
+ *
+ */
+
+DICT_VALUE *
+rc_dict_getval (rc_handle const *rh, uint32_t value, char const *attrname)
+{
+	DICT_VALUE     *val;
+
+	val = rh->dictionary_values;
+	while (val != NULL)
+	{
+		if (strcmp (val->attrname, attrname) == 0 &&
+				val->value == value)
+		{
+			return val;
+		}
+		val = val->next;
+	}
+	return NULL;
+}
+
+/*
+ * Function: rc_dict_free
+ *
+ * Purpose: Free allocated av lists
+ *
+ * Arguments: Radius Client handle
+ */
+
+void
+rc_dict_free(rc_handle *rh)
+{
+	DICT_ATTR	*attr, *nattr;
+	DICT_VALUE	*val, *nval;
+	DICT_VENDOR	*vend, *nvend;
+
+	for (attr = rh->dictionary_attributes; attr != NULL; attr = nattr) {
+		nattr = attr->next;
+		free(attr);
+	}
+	for (val = rh->dictionary_values; val != NULL; val = nval) {
+		nval = val->next;
+		free(val);
+	}
+	for (vend = rh->dictionary_vendors; vend != NULL; vend = nvend) {
+		nvend = vend->next;
+		free(vend);
+	}
+	rh->dictionary_attributes = NULL;
+	rh->dictionary_values = NULL;
+	rh->dictionary_vendors = NULL;
+}
diff --git a/src/plugins/vbng/lib/env.c b/src/plugins/vbng/lib/env.c
new file mode 100644
index 0000000..03dccf9
--- /dev/null
+++ b/src/plugins/vbng/lib/env.c
@@ -0,0 +1,147 @@
+/*
+ * $Id: env.c,v 1.6 2007/06/21 18:07:23 cparker Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+/*
+ * Function: rc_new_env
+ *
+ * Purpose: allocate space for a new environment
+ *
+ */
+
+ENV *rc_new_env(int size)
+{
+	ENV *p;
+
+	if (size < 1)
+		return NULL;
+
+	if ((p = malloc(sizeof(*p))) == NULL)
+		return NULL;
+
+	if ((p->env = malloc(size * sizeof(char *))) == NULL)
+	{
+		rc_log(LOG_CRIT, "rc_new_env: out of memory");
+		free(p);
+		return NULL;
+	}
+
+	p->env[0] = NULL;
+
+	p->size = 0;
+	p->maxsize = size;
+
+	return p;
+}
+
+/*
+ * Function: rc_free_env
+ *
+ * Purpose: free the space used by an env structure
+ *
+ */
+
+void rc_free_env(ENV *env)
+{
+	free(env->env);
+	free(env);
+}
+
+/*
+ * Function: rc_add_env
+ *
+ * Purpose: add an environment entry
+ *
+ */
+
+int rc_add_env(ENV *env, char const *name, char const *value)
+{
+	int i;
+	size_t len;
+	char *new_env;
+
+	for (i = 0; env->env[i] != NULL; i++)
+	{
+		if (strncmp(env->env[i], name, MAX(strchr(env->env[i], '=') - env->env[i], (int)strlen(name))) == 0)
+			break;
+	}
+
+	if (env->env[i])
+	{
+		len = strlen(name)+strlen(value)+2;
+		if ((new_env = realloc(env->env[i], len)) == NULL)
+			return -1;
+
+		env->env[i] = new_env;
+
+		snprintf(env->env[i], len, "%s=%s", name, value);
+	} else {
+		if (env->size == (env->maxsize-1)) {
+			rc_log(LOG_CRIT, "rc_add_env: not enough space for environment (increase ENV_SIZE)");
+			return -1;
+		}
+
+		len = strlen(name)+strlen(value)+2;
+		if ((env->env[env->size] = malloc(len)) == NULL) {
+			rc_log(LOG_CRIT, "rc_add_env: out of memory");
+			return -1;
+		}
+
+		snprintf(env->env[env->size], len, "%s=%s", name, value);
+
+		env->size++;
+
+		env->env[env->size] = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * Function: rc_import_env
+ *
+ * Purpose: imports an array of null-terminated strings
+ *
+ */
+
+int rc_import_env(ENV *env, char const **import)
+{
+	char *es;
+
+	while (*import)
+	{
+		es = strchr(*import, '=');
+
+		if (!es)
+		{
+			import++;
+			continue;
+		}
+
+		/* ok, i grant thats not very clean... */
+		*es = '\0';
+
+		if (rc_add_env(env, *import, es+1) < 0)
+		{
+			*es = '=';
+			return -1;
+		}
+
+		*es = '=';
+
+		import++;
+	}
+
+	return 0;
+}
diff --git a/src/plugins/vbng/lib/ip_util.c b/src/plugins/vbng/lib/ip_util.c
new file mode 100644
index 0000000..d686a59
--- /dev/null
+++ b/src/plugins/vbng/lib/ip_util.c
@@ -0,0 +1,390 @@
+/*
+ * $Id: ip_util.c,v 1.14 2010/03/17 18:57:01 aland Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+#define HOSTBUF_SIZE 1024
+
+#if !defined(SA_LEN)
+#define SA_LEN(sa) \
+  (((sa)->sa_family == AF_INET) ? \
+    sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
+#endif
+
+
+static __thread size_t	hostbuflen=HOSTBUF_SIZE;
+static __thread	char	*tmphostbuf=NULL;
+
+/*
+ * Function: rc_gethostbyname
+ *
+ * Purpose: threadsafe replacement for gethostbyname.
+ *
+ * Returns: NULL on failure, hostent pointer on success
+ */
+
+struct hostent *rc_gethostbyname(char const *hostname)
+{
+	struct 	hostent *hp;
+#ifdef GETHOSTBYNAME_R
+#if defined (GETHOSTBYNAMERSTYLE_SYSV) || defined (GETHOSTBYNAMERSTYLE_GNU)
+	struct 	hostent hostbuf;
+	int	res;
+	int	herr;
+	
+	if(!tmphostbuf) tmphostbuf = malloc(hostbuflen);
+#endif
+#endif
+
+#ifdef GETHOSTBYNAME_R
+#if defined (GETHOSTBYNAMERSTYLE_GNU)
+	while ((res = gethostbyname_r(hostname, &hostbuf, tmphostbuf, hostbuflen, &hp, &herr)) == ERANGE)
+	{
+		/* Enlarge the buffer */
+		hostbuflen *= 2;
+		tmphostbuf = realloc(tmphostbuf, hostbuflen);
+	}
+	if(res) return NULL;
+#elif defined (GETHOSTBYNAMERSTYLE_SYSV)
+	hp = gethostbyname_r(hostname, &hostbuf, tmphostbuf, hostbuflen, &herr);
+#else
+	hp = gethostbyname(hostname);
+#endif
+#else
+	hp = gethostbyname(hostname);
+#endif
+
+	if (hp == NULL) {
+		return NULL;
+	}
+	return hp;
+} 
+
+/*
+ * Function: rc_gethostbyname
+ *
+ * Purpose: threadsafe replacement for gethostbyname.
+ *
+ * Returns: NULL on failure, hostent pointer on success
+ */
+
+struct hostent *rc_gethostbyaddr(char const *addr, size_t length, int format)
+{
+	struct 	hostent *hp;
+#ifdef GETHOSTBYADDR_R
+#if defined (GETHOSTBYADDRRSTYLE_SYSV) || defined (GETHOSTBYADDRRSTYLE_GNU)
+	struct	hostent hostbuf;
+	int	res;
+	int	herr;
+	
+	if(!tmphostbuf) tmphostbuf = malloc(hostbuflen);
+#endif
+#endif
+
+#ifdef GETHOSTBYADDR_R
+#if defined (GETHOSTBYADDRRSTYLE_GNU)
+	while ((res = gethostbyaddr_r(addr, length, format, &hostbuf, tmphostbuf, hostbuflen, 
+					&hp, &herr)) == ERANGE)
+	{
+		/* Enlarge the buffer */
+		hostbuflen *= 2;
+		tmphostbuf = realloc(tmphostbuf, hostbuflen);
+	}
+	if(res) return NULL;
+#elif GETHOSTBYADDRSTYLE_SYSV
+	hp = gethostbyaddr_r(addr, length, format, &hostbuf, tmphostbuf, hostbuflen, &herr);
+#else
+	hp = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
+#endif
+#else
+	hp = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
+#endif
+
+	if (hp == NULL) {
+		return NULL;
+	}
+	return hp;
+} 
+
+/*
+ * Function: rc_get_ipaddr
+ *
+ * Purpose: return an IP address in host long notation from a host
+ *          name or address in dot notation.
+ *
+ * Returns: 0 on failure
+ */
+
+uint32_t rc_get_ipaddr (char const *host)
+{
+	struct 	hostent *hp;
+
+	if (rc_good_ipaddr (host) == 0)
+	{
+		return ntohl(inet_addr (host));
+	}
+	else if ((hp = rc_gethostbyname(host)) == NULL)
+	{
+		rc_log(LOG_ERR,"rc_get_ipaddr: couldn't resolve hostname: %s", host);
+		return (uint32_t)0;
+	}
+	return ntohl((*(uint32_t *) hp->h_addr));
+}
+
+/*
+ * Function: rc_good_ipaddr
+ *
+ * Purpose: check for valid IP address in standard dot notation.
+ *
+ * Returns: 0 on success, -1 when failure
+ *
+ */
+
+int rc_good_ipaddr (char const *addr)
+{
+	int             dot_count;
+	int             digit_count;
+
+	if (addr == NULL)
+		return -1;
+
+	dot_count = 0;
+	digit_count = 0;
+	while (*addr != '\0' && *addr != ' ')
+	{
+		if (*addr == '.')
+		{
+			dot_count++;
+			digit_count = 0;
+		}
+		else if (!isdigit (*addr))
+		{
+			dot_count = 5;
+		}
+		else
+		{
+			digit_count++;
+			if (digit_count > 3)
+			{
+				dot_count = 5;
+			}
+		}
+		addr++;
+	}
+	if (dot_count != 3)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+/*
+ * Function: rc_ip_hostname
+ *
+ * Purpose: Return a printable host name (or IP address in dot notation)
+ *	    for the supplied IP address.
+ *
+ */
+
+char const *rc_ip_hostname (uint32_t h_ipaddr)
+{
+	struct hostent  *hp;
+	uint32_t           n_ipaddr = htonl (h_ipaddr);
+
+	if ((hp = rc_gethostbyaddr ((char *) &n_ipaddr, sizeof (struct in_addr),
+			    AF_INET)) == NULL) {
+		rc_log(LOG_ERR,"rc_ip_hostname: couldn't look up host by addr: %08lX", h_ipaddr);
+	}
+
+	return (hp == NULL) ? "unknown" : hp->h_name;
+}
+
+/*
+ * Function: rc_getport
+ *
+ * Purpose: get the port number for the supplied request type
+ *
+ */
+
+unsigned short rc_getport(int type)
+{
+	struct servent *svp;
+
+	if ((svp = getservbyname ((type==AUTH)?"radius":"radacct", "udp")) == NULL)
+	{
+		return (type==AUTH) ? PW_AUTH_UDP_PORT : PW_ACCT_UDP_PORT;
+	} else {
+		return ntohs ((unsigned short) svp->s_port);
+	}
+}
+
+/*
+ * Function: rc_own_hostname
+ *
+ * Purpose: get the hostname of this machine
+ *
+ * Returns  -1 on failure, 0 on success
+ *
+ */
+
+int
+rc_own_hostname(char *hostname, int len)
+{
+#ifdef HAVE_UNAME
+	struct	utsname uts;
+#endif
+
+#if defined(HAVE_UNAME)
+	if (uname(&uts) < 0)
+	{
+		rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname");
+		return -1;
+	}
+	strncpy(hostname, uts.nodename, len);
+#elif defined(HAVE_GETHOSTNAME)
+	if (gethostname(hostname, len) < 0)
+	{
+		rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname");
+		return -1;
+	}
+#elif defined(HAVE_SYSINFO)
+	if (sysinfo(SI_HOSTNAME, hostname, len) < 0)
+	{
+		rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname");
+		return -1;
+	}
+#else
+	return -1;
+#endif
+
+	return 0;
+}
+
+/*
+ * Function: rc_own_ipaddress
+ *
+ * Purpose: get the IP address of this host in host order
+ *
+ * Returns: IP address on success, 0 on failure
+ *
+ */
+
+uint32_t rc_own_ipaddress(rc_handle *rh)
+{
+	char hostname[256];
+
+	if (!rh->this_host_ipaddr) {
+		if (rc_conf_str(rh, "bindaddr") == NULL ||
+		    strcmp(rc_conf_str(rh, "bindaddr"), "*") == 0) {
+			if (rc_own_hostname(hostname, sizeof(hostname)) < 0)
+				return 0;
+		} else {
+			strncpy(hostname, rc_conf_str(rh, "bindaddr"), sizeof(hostname));
+			hostname[sizeof(hostname) - 1] = '\0';
+		}
+		if ((rh->this_host_ipaddr = rc_get_ipaddr (hostname)) == 0) {
+			rc_log(LOG_ERR, "rc_own_ipaddress: couldn't get own IP address");
+			return 0;
+		}
+	}
+
+	return rh->this_host_ipaddr;
+}
+
+/*
+ * Function: rc_own_bind_ipaddress
+ *
+ * Purpose: get the IP address to be used as a source address
+ *          for sending requests in host order
+ *
+ * Returns: IP address
+ *
+ */
+
+uint32_t rc_own_bind_ipaddress(rc_handle *rh)
+{
+	char hostname[256];
+	uint32_t rval;
+
+	if (rh->this_host_bind_ipaddr != NULL)
+		return *rh->this_host_bind_ipaddr;
+
+	rh->this_host_bind_ipaddr = malloc(sizeof(*rh->this_host_bind_ipaddr));
+	if (rh->this_host_bind_ipaddr == NULL)
+		rc_log(LOG_CRIT, "rc_own_bind_ipaddress: out of memory");
+	if (rc_conf_str(rh, "bindaddr") == NULL ||
+	    strcmp(rc_conf_str(rh, "bindaddr"), "*") == 0) {
+		rval = INADDR_ANY;
+	} else {
+		strncpy(hostname, rc_conf_str(rh, "bindaddr"), sizeof(hostname));
+		hostname[sizeof(hostname) - 1] = '\0';
+		if ((rval = rc_get_ipaddr (hostname)) == 0) {
+			rc_log(LOG_ERR, "rc_own_ipaddress: couldn't get IP address from bindaddr");
+			rval = INADDR_ANY;
+		}
+	}
+	if (rh->this_host_bind_ipaddr != NULL)
+		*rh->this_host_bind_ipaddr = rval;
+
+	return rval;
+}
+
+/*
+ * Function: rc_get_srcaddr
+ *
+ * Purpose: given remote address find local address which the
+ *          system will use as a source address for sending
+ *          datagrams to that remote address
+ *
+ * Returns: 0 in success, -1 on failure, address is filled into
+ *          the first argument.
+ *
+ */
+int
+rc_get_srcaddr(struct sockaddr *lia, struct sockaddr *ria)
+{
+	int temp_sock;
+	socklen_t namelen;
+
+	temp_sock = socket(ria->sa_family, SOCK_DGRAM, 0);
+	if (temp_sock == -1) {
+		rc_log(LOG_ERR, "rc_get_srcaddr: socket: %s", strerror(errno));
+		return -1;
+	}
+
+	if (connect(temp_sock, ria, SA_LEN(ria)) != 0) {
+		rc_log(LOG_ERR, "rc_get_srcaddr: connect: %s",
+		    strerror(errno));
+		close(temp_sock);
+		return -1;
+	}
+
+	namelen = SA_LEN(ria);
+	if (getsockname(temp_sock, lia, &namelen) != 0) {
+		rc_log(LOG_ERR, "rc_get_srcaddr: getsockname: %s",
+		    strerror(errno));
+		close(temp_sock);
+		return -1;
+	}
+
+	close(temp_sock);
+	return 0;
+}
diff --git a/src/plugins/vbng/lib/log.c b/src/plugins/vbng/lib/log.c
new file mode 100644
index 0000000..09b01a2
--- /dev/null
+++ b/src/plugins/vbng/lib/log.c
@@ -0,0 +1,57 @@
+/*
+ * $Id: log.c,v 1.5 2007/06/21 18:07:23 cparker Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+/*
+ * Function: rc_openlog
+ *
+ * Purpose: open log
+ *
+ * Arguments: identification string
+ *
+ * Returns: nothing
+ *
+ */
+
+void rc_openlog(char const *ident)
+{
+#ifndef _MSC_VER /* TODO: Fix me */
+	openlog(ident, LOG_PID, RC_LOG_FACILITY);
+#endif
+}
+
+/*
+ * Function: rc_log
+ *
+ * Purpose: log information
+ *
+ * Arguments: priority (just like syslog), rest like printf
+ *
+ * Returns: nothing
+ *
+ */
+
+void rc_log(int prio, char const *format, ...)
+{
+	char buff[1024];
+	va_list ap;
+
+	va_start(ap,format);
+    vsnprintf(buff, sizeof(buff), format, ap);
+    va_end(ap);
+
+#ifndef _MSC_VER /* TODO: Fix me */
+	syslog(prio, "%s", buff);
+#endif
+}
diff --git a/src/plugins/vbng/lib/md5.c b/src/plugins/vbng/lib/md5.c
new file mode 100644
index 0000000..2344fb9
--- /dev/null
+++ b/src/plugins/vbng/lib/md5.c
@@ -0,0 +1,251 @@
+#include "md5.h"
+
+/*	The below was retrieved from
+ *	http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.c?rev=1.1
+ *	with the following changes:
+ *	#includes commented out.
+ *	Support context->count as uint32_t[2] instead of uint64_t
+ *	u_int* to uint*
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/*#include <sys/param.h>*/
+/*#include <sys/systm.h>*/
+/*#include <crypto/md5.h>*/
+
+#define PUT_64BIT_LE(cp, value) do {				\
+	(cp)[7] = (value)[1] >> 24;					\
+	(cp)[6] = (value)[1] >> 16;					\
+	(cp)[5] = (value)[1] >> 8;					\
+	(cp)[4] = (value)[1];						\
+	(cp)[3] = (value)[0] >> 24;					\
+	(cp)[2] = (value)[0] >> 16;					\
+	(cp)[1] = (value)[0] >> 8;					\
+	(cp)[0] = (value)[0]; } while (0)
+
+#define PUT_32BIT_LE(cp, value) do {					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(MD5_CTX *ctx)
+{
+	ctx->count[0] = 0;
+	ctx->count[1] = 0;
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(MD5_CTX *ctx, uint8_t const *input, size_t len)
+{
+	size_t have, need;
+
+	/* Check how many bytes we already have and how many more we need. */
+	have = (size_t)((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
+	need = MD5_BLOCK_LENGTH - have;
+
+	/* Update bitcount */
+/*	ctx->count += (uint64_t)len << 3;*/
+	if ((ctx->count[0] += ((uint32_t)len << 3)) < (uint32_t)len) {
+	/* Overflowed ctx->count[0] */
+		ctx->count[1]++;
+	}
+	ctx->count[1] += ((uint32_t)len >> 29);
+
+
+
+	if (len >= need) {
+		if (have != 0) {
+			memcpy(ctx->buffer + have, input, need);
+			MD5Transform(ctx->state, ctx->buffer);
+			input += need;
+			len -= need;
+			have = 0;
+		}
+
+		/* Process data in MD5_BLOCK_LENGTH-byte chunks. */
+		while (len >= MD5_BLOCK_LENGTH) {
+			MD5Transform(ctx->state, input);
+			input += MD5_BLOCK_LENGTH;
+			len -= MD5_BLOCK_LENGTH;
+		}
+	}
+
+	/* Handle any remaining bytes of data. */
+	if (len != 0)
+		memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
+{
+	uint8_t count[8];
+	size_t padlen;
+	int i;
+
+	/* Convert count to 8 bytes in little endian order. */
+	PUT_64BIT_LE(count, ctx->count);
+
+	/* Pad out to 56 mod 64. */
+	padlen = MD5_BLOCK_LENGTH -
+	    ((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
+	if (padlen < 1 + 8)
+		padlen += MD5_BLOCK_LENGTH;
+	MD5Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
+	MD5Update(ctx, count, 8);
+
+	if (digest != NULL) {
+		for (i = 0; i < 4; i++)
+			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+	}
+	memset(ctx, 0, sizeof(*ctx));	/* in case it's sensitive */
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32_t state[4], uint8_t const block[MD5_BLOCK_LENGTH])
+{
+	uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+
+	for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
+		in[a] = (uint32_t)(
+		    (uint32_t)(block[a * 4 + 0]) |
+		    (uint32_t)(block[a * 4 + 1]) <<  8 |
+		    (uint32_t)(block[a * 4 + 2]) << 16 |
+		    (uint32_t)(block[a * 4 + 3]) << 24);
+	}
+
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+
+	MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
+	MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
+	MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
+	MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
+	MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
+	MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
+	MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
+	MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
+	MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
+	MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
+	MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
+	MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
+	MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
diff --git a/src/plugins/vbng/lib/md5.h b/src/plugins/vbng/lib/md5.h
new file mode 100644
index 0000000..fcbaf91
--- /dev/null
+++ b/src/plugins/vbng/lib/md5.h
@@ -0,0 +1,86 @@
+/*
+ * md5.h        Structures and prototypes for md5.
+ *
+ * Version:     $Id: md5.h,v 1.2 2007/06/21 18:07:24 cparker Exp $
+ * License:	BSD, but largely derived from a public domain source.
+ *
+ */
+
+#ifndef _RCRAD_MD5_H
+#define _RCRAD_MD5_H
+
+#include "config.h"
+
+#ifdef HAVE_NETTLE
+
+#include <nettle/md5-compat.h>
+
+#else
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include <string.h>
+/*
+ *  FreeRADIUS Client defines to ensure globally unique MD5 function names,
+ *  so that we don't pick up vendor-specific broken MD5 libraries.
+ */
+#define MD5_CTX		librad_MD5_CTX
+#define MD5Init		librad_MD5Init
+#define MD5Update	librad_MD5Update
+#define MD5Final	librad_MD5Final
+#define MD5Transform	librad_MD5Transform
+
+/*  The below was retrieved from
+ *  http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.h?rev=1.1
+ *  With the following changes: uint64_t => uint32_t[2]
+ *  Commented out #include <sys/cdefs.h>
+ *  Commented out the __BEGIN and __END _DECLS, and the __attributes.
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+
+#define	MD5_BLOCK_LENGTH		64
+#define	MD5_DIGEST_LENGTH		16
+
+typedef struct MD5Context {
+	uint32_t state[4];			/* state */
+	uint32_t count[2];			/* number of bits, mod 2^64 */
+	uint8_t buffer[MD5_BLOCK_LENGTH];	/* input buffer */
+} MD5_CTX;
+
+/* include <sys/cdefs.h> */
+
+/* __BEGIN_DECLS */
+void	 MD5Init(MD5_CTX *);
+void	 MD5Update(MD5_CTX *, uint8_t const *, size_t)
+/*		__attribute__((__bounded__(__string__,2,3)))*/;
+void	 MD5Final(uint8_t [MD5_DIGEST_LENGTH], MD5_CTX *)
+/*		__attribute__((__bounded__(__minbytes__,1,MD5_DIGEST_LENGTH)))*/;
+void	 MD5Transform(uint32_t [4], uint8_t const [MD5_BLOCK_LENGTH])
+/*		__attribute__((__bounded__(__minbytes__,1,4)))*/
+/*		__attribute__((__bounded__(__minbytes__,2,MD5_BLOCK_LENGTH)))*/;
+/* __END_DECLS */
+
+#endif /* HAVE_NETTLE */
+
+#endif /* _RCRAD_MD5_H */
diff --git a/src/plugins/vbng/lib/options.h b/src/plugins/vbng/lib/options.h
new file mode 100644
index 0000000..05b66df
--- /dev/null
+++ b/src/plugins/vbng/lib/options.h
@@ -0,0 +1,57 @@
+/*
+ * $Id: options.h,v 1.6 2008/03/05 16:35:20 cparker Exp $
+ *
+ * Copyright (C) 1996 Lars Fenneberg
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#define OPTION_LEN	64
+
+/* ids for different option types */
+#define OT_STR		(1<<0)	  /* string */
+#define OT_INT		(1<<1)	  /* integer */
+#define OT_SRV		(1<<2)	  /* server list */
+#define OT_AUO		(1<<3)    /* authentication order */
+
+#define OT_ANY		((unsigned int)~0) /* used internally */
+
+/* status types */
+#define ST_UNDEF	(1<<0)	  /* option is undefined */
+
+typedef struct _option {
+	char name[OPTION_LEN];	  /* name of the option */
+	int type, status;	  /* type and status    */
+	void *val;		  /* pointer to option value */
+} OPTION;
+
+static OPTION config_options_default[] = {
+/* internally used options */
+{"config_file",		OT_STR, ST_UNDEF, NULL},
+/* General options */
+{"auth_order",	 	OT_AUO, ST_UNDEF, NULL},
+{"login_tries",	 	OT_INT, ST_UNDEF, NULL},
+{"login_timeout",	OT_INT, ST_UNDEF, NULL},
+{"nologin",		OT_STR, ST_UNDEF, NULL},
+{"issue",		OT_STR, ST_UNDEF, NULL},
+/* RADIUS specific options */
+{"authserver",		OT_SRV, ST_UNDEF, NULL},
+{"acctserver",		OT_SRV, ST_UNDEF, NULL},
+{"servers",		OT_STR, ST_UNDEF, NULL},
+{"dictionary",		OT_STR, ST_UNDEF, NULL},
+{"login_radius",	OT_STR, ST_UNDEF, NULL},
+{"seqfile",		OT_STR, ST_UNDEF, NULL},
+{"mapfile",		OT_STR, ST_UNDEF, NULL},
+{"default_realm",	OT_STR, ST_UNDEF, NULL},
+{"radius_timeout",	OT_INT, ST_UNDEF, NULL},
+{"radius_retries",	OT_INT,	ST_UNDEF, NULL},
+{"radius_deadtime",	OT_INT, ST_UNDEF, NULL},
+{"bindaddr",		OT_STR, ST_UNDEF, NULL},
+/* local options */
+{"login_local",		OT_STR, ST_UNDEF, NULL},
+};
+
+#define	NUM_OPTIONS	((sizeof(config_options_default))/(sizeof(config_options_default[0])))
diff --git a/src/plugins/vbng/lib/rc-md5.c b/src/plugins/vbng/lib/rc-md5.c
new file mode 100644
index 0000000..be9fbcb
--- /dev/null
+++ b/src/plugins/vbng/lib/rc-md5.c
@@ -0,0 +1,24 @@
+/* MD5 message-digest algorithm */
+
+/* This file is licensed under the BSD License, but is largely derived from
+ * public domain source code
+ */
+
+/*
+ *  FORCE MD5 TO USE OUR MD5 HEADER FILE!
+ *
+ *  If we don't do this, it might pick up the systems broken MD5.
+ *  - Alan DeKok <aland@ox.org>
+ */
+#include "rc-md5.h"
+
+void rc_md5_calc(unsigned char *output, unsigned char const *input,
+		     size_t inlen)
+{
+	MD5_CTX	context;
+
+	MD5Init(&context);
+	MD5Update(&context, input, inlen);
+	MD5Final(output, &context);
+}
+
diff --git a/src/plugins/vbng/lib/rc-md5.h b/src/plugins/vbng/lib/rc-md5.h
new file mode 100644
index 0000000..a30f16d
--- /dev/null
+++ b/src/plugins/vbng/lib/rc-md5.h
@@ -0,0 +1,27 @@
+/*
+ * md5.h        Structures and prototypes for md5.
+ *
+ * Version:     $Id: md5.h,v 1.2 2007/06/21 18:07:24 cparker Exp $
+ * License:	BSD
+ *
+ */
+
+#ifndef _RC_MD5_H
+#define _RC_MD5_H
+
+#include "config.h"
+
+#ifdef HAVE_NETTLE
+
+#include <nettle/md5-compat.h>
+
+#else
+
+#include "md5.h"
+
+#endif /* HAVE_NETTLE */
+
+void rc_md5_calc(unsigned char *output, unsigned char const *input,
+		     size_t inputlen);
+
+#endif /* _RC_MD5_H */
diff --git a/src/plugins/vbng/lib/sendserver.c b/src/plugins/vbng/lib/sendserver.c
new file mode 100644
index 0000000..bfdd9a2
--- /dev/null
+++ b/src/plugins/vbng/lib/sendserver.c
@@ -0,0 +1,631 @@
+/*
+ * $Id: sendserver.c,v 1.30 2010/06/15 09:22:52 aland Exp $
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <poll.h>
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+#include <pathnames.h>
+
+#define	SA(p)	((struct sockaddr *)(p))
+
+static void rc_random_vector (unsigned char *);
+static int rc_check_reply (AUTH_HDR *, int, char const *, unsigned char const *, unsigned char);
+
+/*
+ * Function: rc_pack_list
+ *
+ * Purpose: Packs an attribute value pair list into a buffer.
+ *
+ * Returns: Number of octets packed.
+ *
+ */
+
+static int rc_pack_list (VALUE_PAIR *vp, char *secret, AUTH_HDR *auth)
+{
+	int             length, i, pc, padded_length;
+	int             total_length = 0;
+	size_t			secretlen;
+	uint32_t           lvalue, vendor;
+	unsigned char   passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
+	unsigned char   md5buf[256];
+	unsigned char   *buf, *vector, *vsa_length_ptr;
+
+	buf = auth->data;
+
+	while (vp != NULL)
+	{
+		vsa_length_ptr = NULL;
+		if (VENDOR(vp->attribute) != 0) {
+			*buf++ = PW_VENDOR_SPECIFIC;
+			vsa_length_ptr = buf;
+			*buf++ = 6;
+			vendor = htonl(VENDOR(vp->attribute));
+			memcpy(buf, &vendor, sizeof(uint32_t));
+			buf += 4;
+			total_length += 6;
+		}
+		*buf++ = (vp->attribute & 0xff);
+
+		switch (vp->attribute)
+		{
+		 case PW_USER_PASSWORD:
+
+		  /* Encrypt the password */
+
+		  /* Chop off password at AUTH_PASS_LEN */
+		  length = vp->lvalue;
+		  if (length > AUTH_PASS_LEN)
+			length = AUTH_PASS_LEN;
+
+		  /* Calculate the padded length */
+		  padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1);
+
+		  /* Record the attribute length */
+		  *buf++ = padded_length + 2;
+		  if (vsa_length_ptr != NULL) *vsa_length_ptr += padded_length + 2;
+
+		  /* Pad the password with zeros */
+		  memset ((char *) passbuf, '\0', AUTH_PASS_LEN);
+		  memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
+
+		  secretlen = strlen (secret);
+		  vector = (unsigned char *)auth->vector;
+		  for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN)
+		  {
+		  	/* Calculate the MD5 digest*/
+		  	strcpy ((char *) md5buf, secret);
+		  	memcpy ((char *) md5buf + secretlen, vector,
+		  		  AUTH_VECTOR_LEN);
+		  	rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
+
+		        /* Remeber the start of the digest */
+		  	vector = buf;
+
+			/* Xor the password into the MD5 digest */
+			for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++)
+		  	{
+				*buf++ ^= passbuf[pc];
+		  	}
+		  }
+
+		  total_length += padded_length + 2;
+
+		  break;
+#if 0
+		 case PW_CHAP_PASSWORD:
+
+		  *buf++ = CHAP_VALUE_LENGTH + 2;
+		  if (vsa_length_ptr != NULL) *vsa_length_ptr += CHAP_VALUE_LENGTH + 2;
+
+		  /* Encrypt the Password */
+		  length = vp->lvalue;
+		  if (length > CHAP_VALUE_LENGTH)
+		  {
+			length = CHAP_VALUE_LENGTH;
+		  }
+		  memset ((char *) passbuf, '\0', CHAP_VALUE_LENGTH);
+		  memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
+
+		  /* Calculate the MD5 Digest */
+		  secretlen = strlen (secret);
+		  strcpy ((char *) md5buf, secret);
+		  memcpy ((char *) md5buf + secretlen, (char *) auth->vector,
+		  	  AUTH_VECTOR_LEN);
+		  rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
+
+		  /* Xor the password into the MD5 digest */
+		  for (i = 0; i < CHAP_VALUE_LENGTH; i++)
+		  {
+			*buf++ ^= passbuf[i];
+		  }
+		  total_length += CHAP_VALUE_LENGTH + 2;
+
+		  break;
+#endif
+		 default:
+		  switch (vp->type)
+		  {
+		    case PW_TYPE_STRING:
+			length = vp->lvalue;
+			*buf++ = length + 2;
+			if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
+			memcpy (buf, vp->strvalue, (size_t) length);
+			buf += length;
+			total_length += length + 2;
+			break;
+
+		    case PW_TYPE_IPV6ADDR:
+			length = 16;
+			if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
+			memcpy (buf, vp->strvalue, (size_t) length);
+			buf += length;
+			total_length += length + 2;
+			break;
+
+		    case PW_TYPE_IPV6PREFIX:
+			length = vp->lvalue;
+			if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
+			memcpy (buf, vp->strvalue, (size_t) length);
+			buf += length;
+			total_length += length + 2;
+			break;
+
+		    case PW_TYPE_INTEGER:
+		    case PW_TYPE_IPADDR:
+		    case PW_TYPE_DATE:
+			*buf++ = sizeof (uint32_t) + 2;
+			if (vsa_length_ptr != NULL) *vsa_length_ptr += sizeof(uint32_t) + 2;
+			lvalue = htonl (vp->lvalue);
+			memcpy (buf, (char *) &lvalue, sizeof (uint32_t));
+			buf += sizeof (uint32_t);
+			total_length += sizeof (uint32_t) + 2;
+			break;
+
+		    default:
+			break;
+		  }
+		  break;
+		}
+		vp = vp->next;
+	}
+	return total_length;
+}
+
+/* Function strappend
+ *
+ * Purpose: appends a string to the provided buffer
+ */
+static void strappend(char *dest, unsigned max_size, int *pos, const char *src)
+{
+	unsigned len = strlen(src) + 1;
+
+	if (*pos == -1)
+		return;
+
+	if (len + *pos > max_size) {
+		*pos = -1;
+		return;
+	}
+
+	memcpy(&dest[*pos], src, len);
+	*pos += len-1;
+	return;
+}
+
+/*
+ * Function: rc_send_server
+ *
+ * Purpose: send a request to a RADIUS server and wait for the reply
+ *
+ */
+
+int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg)
+{
+	int             sockfd;
+	struct sockaddr_in sinlocal;
+	struct sockaddr_in sinremote;
+	AUTH_HDR       *auth, *recv_auth;
+	uint32_t           auth_ipaddr, nas_ipaddr;
+	char           *server_name;	/* Name of server to query */
+	socklen_t       salen;
+	int             result = 0;
+	int             total_length;
+	int             length, pos;
+	int             retry_max;
+	size_t			secretlen;
+	char            secret[MAX_SECRET_LENGTH + 1];
+	unsigned char   vector[AUTH_VECTOR_LEN];
+	char            recv_buffer[BUFFER_LEN];
+	char            send_buffer[BUFFER_LEN];
+	int		retries;
+	VALUE_PAIR 	*vp;
+	struct pollfd	pfd;
+	double		start_time, timeout;
+
+	server_name = data->server;
+	if (server_name == NULL || server_name[0] == '\0')
+		return ERROR_RC;
+
+	if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && \
+	    (vp->lvalue == PW_ADMINISTRATIVE))
+	{
+		strcpy(secret, MGMT_POLL_SECRET);
+		if ((auth_ipaddr = rc_get_ipaddr(server_name)) == 0)
+			return ERROR_RC;
+	}
+	else
+	{
+		if(data->secret != NULL)
+		{
+			strncpy(secret, data->secret, MAX_SECRET_LENGTH);
+		}
+		/*
+		else
+		{
+		*/
+		if (rc_find_server (rh, server_name, &auth_ipaddr, secret) != 0)
+		{
+			rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name);
+			return ERROR_RC;
+		}
+		/*}*/
+	}
+
+	DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name);
+
+	sockfd = socket (AF_INET, SOCK_DGRAM, 0);
+	if (sockfd < 0)
+	{
+		memset (secret, '\0', sizeof (secret));
+		rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno));
+		return ERROR_RC;
+	}
+
+	memset((char *)&sinlocal, '\0', sizeof(sinlocal));
+	sinlocal.sin_family = AF_INET;
+	sinlocal.sin_addr.s_addr = htonl(rc_own_bind_ipaddress(rh));
+	sinlocal.sin_port = htons((unsigned short) 0);
+	if (bind(sockfd, SA(&sinlocal), sizeof(sinlocal)) < 0)
+	{
+		close (sockfd);
+		memset (secret, '\0', sizeof (secret));
+		rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno));
+		return ERROR_RC;
+	}
+
+	retry_max = data->retries;	/* Max. numbers to try for reply */
+	retries = 0;			/* Init retry cnt for blocking call */
+
+	memset ((char *)&sinremote, '\0', sizeof(sinremote));
+	sinremote.sin_family = AF_INET;
+	sinremote.sin_addr.s_addr = htonl (auth_ipaddr);
+	sinremote.sin_port = htons ((unsigned short) data->svc_port);
+
+	/*
+	 * Fill in NAS-IP-Address (if needed)
+	 */
+	if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL) {
+		if (sinlocal.sin_addr.s_addr == htonl(INADDR_ANY)) {
+			if (rc_get_srcaddr(SA(&sinlocal), SA(&sinremote)) != 0) {
+				close (sockfd);
+				memset (secret, '\0', sizeof (secret));
+				return ERROR_RC;
+			}
+		}
+		nas_ipaddr = ntohl(sinlocal.sin_addr.s_addr);
+		rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS,
+		    &nas_ipaddr, 0, 0);
+	}
+
+	/* Build a request */
+	auth = (AUTH_HDR *) send_buffer;
+	auth->code = data->code;
+	auth->id = data->seq_nbr;
+
+	if (data->code == PW_ACCOUNTING_REQUEST)
+	{
+		total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
+
+		auth->length = htons ((unsigned short) total_length);
+
+		memset((char *) auth->vector, 0, AUTH_VECTOR_LEN);
+		secretlen = strlen (secret);
+		memcpy ((char *) auth + total_length, secret, secretlen);
+		rc_md5_calc (vector, (unsigned char *) auth, total_length + secretlen);
+		memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
+	}
+	else
+	{
+		rc_random_vector (vector);
+		memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
+
+		total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
+
+		auth->length = htons ((unsigned short) total_length);
+	}
+
+	DEBUG(LOG_ERR, "DEBUG: local %s : 0, remote %s : %u\n", 
+		inet_ntoa(sinlocal.sin_addr),
+		inet_ntoa(sinremote.sin_addr), data->svc_port);
+
+	for (;;)
+	{
+		sendto (sockfd, (char *) auth, (unsigned int) total_length, (int) 0,
+			SA(&sinremote), sizeof (struct sockaddr_in));
+
+		pfd.fd = sockfd;
+		pfd.events = POLLIN;
+		pfd.revents = 0;
+		start_time = rc_getctime();
+		for (timeout = data->timeout; timeout > 0;
+		    timeout -= rc_getctime() - start_time) {
+			result = poll(&pfd, 1, timeout * 1000);
+			if (result != -1 || errno != EINTR)
+				break;
+		}
+		if (result == -1)
+		{
+			rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno));
+			memset (secret, '\0', sizeof (secret));
+			close (sockfd);
+			return ERROR_RC;
+		}
+		if (result == 1 && (pfd.revents & POLLIN) != 0)
+			break;
+
+		/*
+		 * Timed out waiting for response.  Retry "retry_max" times
+		 * before giving up.  If retry_max = 0, don't retry at all.
+		 */
+		if (retries++ >= retry_max)
+		{
+			rc_log(LOG_ERR,
+				"rc_send_server: no reply from RADIUS server %s:%u, %s",
+				 rc_ip_hostname (auth_ipaddr), data->svc_port, inet_ntoa(sinremote.sin_addr));
+			close (sockfd);
+			memset (secret, '\0', sizeof (secret));
+			return TIMEOUT_RC;
+		}
+	}
+	salen = sizeof(sinremote);
+	length = recvfrom (sockfd, (char *) recv_buffer,
+			   (int) sizeof (recv_buffer),
+			   (int) 0, SA(&sinremote), &salen);
+
+	if (length <= 0)
+	{
+		rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name,\
+			 data->svc_port, strerror(errno));
+		close (sockfd);
+		memset (secret, '\0', sizeof (secret));
+		return ERROR_RC;
+	}
+
+	recv_auth = (AUTH_HDR *)recv_buffer;
+
+	if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) {
+		rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short",
+		    server_name, data->svc_port);
+		close(sockfd);
+		memset(secret, '\0', sizeof(secret));
+		return ERROR_RC;
+	}
+
+	result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr);
+
+	length = ntohs(recv_auth->length)  - AUTH_HDR_LEN;
+	if (length > 0) {
+		data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data,
+		    length, 0);
+	} else {
+		data->receive_pairs = NULL;
+	}
+
+	close (sockfd);
+	memset (secret, '\0', sizeof (secret));
+
+	if (result != OK_RC) return result;
+
+	if (msg) {
+		*msg = '\0';
+		pos = 0;
+		vp = data->receive_pairs;
+		while (vp)
+		{
+			if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0)))
+			{
+				strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue);
+				strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n");
+				vp = vp->next;
+			}
+		}
+	}
+
+	if ((recv_auth->code == PW_ACCESS_ACCEPT) ||
+		(recv_auth->code == PW_PASSWORD_ACK) ||
+		(recv_auth->code == PW_ACCOUNTING_RESPONSE))
+	{
+		result = OK_RC;
+	}
+	else if ((recv_auth->code == PW_ACCESS_REJECT) ||
+		(recv_auth->code == PW_PASSWORD_REJECT))
+	{
+		result = REJECT_RC;
+	}
+	else
+	{
+		result = BADRESP_RC;
+	}
+
+	return result;
+}
+
+/*
+ * Function: rc_check_reply
+ *
+ * Purpose: verify items in returned packet.
+ *
+ * Returns:	OK_RC       -- upon success,
+ *		BADRESP_RC  -- if anything looks funny.
+ *
+ */
+
+static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char const *secret, unsigned char const *vector, uint8_t seq_nbr)
+{
+	int             secretlen;
+	int             totallen;
+	unsigned char   calc_digest[AUTH_VECTOR_LEN];
+	unsigned char   reply_digest[AUTH_VECTOR_LEN];
+#ifdef DIGEST_DEBUG
+	uint8_t		*ptr;
+#endif
+
+	totallen = ntohs (auth->length);
+	secretlen = (int)strlen (secret);
+
+	/* Do sanity checks on packet length */
+	if ((totallen < 20) || (totallen > 4096))
+	{
+		rc_log(LOG_ERR, "rc_check_reply: received RADIUS server response with invalid length");
+		return BADRESP_RC;
+	}
+
+	/* Verify buffer space, should never trigger with current buffer size and check above */
+	if ((totallen + secretlen) > bufferlen)
+	{
+		rc_log(LOG_ERR, "rc_check_reply: not enough buffer space to verify RADIUS server response");
+		return BADRESP_RC;
+	}
+
+	/* Verify that id (seq. number) matches what we sent */
+	if (auth->id != seq_nbr)
+	{
+		rc_log(LOG_ERR, "rc_check_reply: received non-matching id in RADIUS server response");
+		return BADRESP_RC;
+	}
+
+	/* Verify the reply digest */
+	memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN);
+	memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
+	memcpy ((char *) auth + totallen, secret, secretlen);
+#ifdef DIGEST_DEBUG
+        rc_log(LOG_ERR, "Calculating digest on:");
+        for (ptr = (u_char *)auth; ptr < ((u_char *)auth) + totallen + secretlen; ptr += 32) {
+                char buf[65];
+                int i;
+
+                buf[0] = '\0';
+                for (i = 0; i < 32; i++) {
+                        if (ptr + i >= ((u_char *)auth) + totallen + secretlen)
+                                break;
+                        sprintf(buf + i * 2, "%.2X", ptr[i]);
+                }
+                rc_log(LOG_ERR, "  %s", buf);
+        }
+#endif
+	rc_md5_calc (calc_digest, (unsigned char *) auth, totallen + secretlen);
+#ifdef DIGEST_DEBUG
+	rc_log(LOG_ERR, "Calculated digest is:");
+        for (ptr = (u_char *)calc_digest; ptr < ((u_char *)calc_digest) + 16; ptr += 32) {
+                char buf[65];
+                int i;
+
+                buf[0] = '\0';
+                for (i = 0; i < 32; i++) {
+                        if (ptr + i >= ((u_char *)calc_digest) + 16)
+                                break;
+                        sprintf(buf + i * 2, "%.2X", ptr[i]);
+                }
+                rc_log(LOG_ERR, "  %s", buf);
+        }
+	rc_log(LOG_ERR, "Reply digest is:");
+        for (ptr = (u_char *)reply_digest; ptr < ((u_char *)reply_digest) + 16; ptr += 32) {
+                char buf[65];
+                int i;
+
+                buf[0] = '\0';
+                for (i = 0; i < 32; i++) {
+                        if (ptr + i >= ((u_char *)reply_digest) + 16)
+                                break;
+                        sprintf(buf + i * 2, "%.2X", ptr[i]);
+                }
+                rc_log(LOG_ERR, "  %s", buf);
+        }
+#endif
+
+	if (memcmp ((char *) reply_digest, (char *) calc_digest,
+		    AUTH_VECTOR_LEN) != 0)
+	{
+#ifdef RADIUS_116
+		/* the original Livingston radiusd v1.16 seems to have
+		   a bug in digest calculation with accounting requests,
+		   authentication request are ok. i looked at the code
+		   but couldn't find any bugs. any help to get this
+		   kludge out are welcome. preferably i want to
+		   reproduce the calculation bug here to be compatible
+		   to stock Livingston radiusd v1.16.	-lf, 03/14/96
+		 */
+		if (auth->code == PW_ACCOUNTING_RESPONSE)
+			return OK_RC;
+#endif
+		rc_log(LOG_ERR, "rc_check_reply: received invalid reply digest from RADIUS server");
+		return BADRESP_RC;
+	}
+
+	return OK_RC;
+
+}
+
+/*
+ * Function: rc_random_vector
+ *
+ * Purpose: generates a random vector of AUTH_VECTOR_LEN octets.
+ *
+ * Returns: the vector (call by reference)
+ *
+ */
+
+static void rc_random_vector (unsigned char *vector)
+{
+	int             randno;
+	int             i;
+#if defined(HAVE_GETENTROPY)
+	if (getentropy(vector, AUTH_VECTOR_LEN) >= 0) {
+		return;
+	} /* else fall through */
+#elif defined(HAVE_DEV_URANDOM)
+	int		fd;
+
+/* well, I added this to increase the security for user passwords.
+   we use /dev/urandom here, as /dev/random might block and we don't
+   need that much randomness. BTW, great idea, Ted!     -lf, 03/18/95	*/
+
+	if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0)
+	{
+		unsigned char *pos;
+		int readcount;
+
+		i = AUTH_VECTOR_LEN;
+		pos = vector;
+		while (i > 0)
+		{
+			readcount = read(fd, (char *)pos, i);
+			if (readcount >= 0) {
+				pos += readcount;
+				i -= readcount;
+			} else {
+				if (errno != EINTR && errno != EAGAIN)
+					goto fallback;
+			}
+		}
+
+		close(fd);
+		return;
+	} /* else fall through */
+#endif
+ fallback:
+	for (i = 0; i < AUTH_VECTOR_LEN;)
+	{
+		randno = random ();
+		memcpy ((char *) vector, (char *) &randno, sizeof (int));
+		vector += sizeof (int);
+		i += sizeof (int);
+	}
+
+	return;
+}
diff --git a/src/plugins/vbng/lib/util.c b/src/plugins/vbng/lib/util.c
new file mode 100644
index 0000000..aa7c057
--- /dev/null
+++ b/src/plugins/vbng/lib/util.c
@@ -0,0 +1,347 @@
+/*
+ * $Id: util.c,v 1.10 2010/02/04 10:31:41 aland Exp $
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ *
+ * Copyright (C) 1995,1996,1997 Lars Fenneberg
+ *
+ * Copyright 1992 Livingston Enterprises, Inc.
+ *
+ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
+ * and Merit Network, Inc. All Rights Reserved
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <sys/time.h>
+
+#include <config.h>
+#include <includes.h>
+#include <freeradius-client.h>
+
+#define	RC_BUFSIZ	1024
+
+/*
+ * Function: rc_str2tm
+ *
+ * Purpose: Turns printable string into correct tm struct entries.
+ *
+ */
+
+static char const * months[] =
+		{
+			"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+			"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+		};
+
+void rc_str2tm (char const *valstr, struct tm *tm)
+{
+	int             i;
+
+	/* Get the month */
+	for (i = 0; i < 12; i++)
+	{
+		if (strncmp (months[i], valstr, 3) == 0)
+		{
+			tm->tm_mon = i;
+			i = 13;
+		}
+	}
+
+	/* Get the Day */
+	tm->tm_mday = atoi (&valstr[4]);
+
+	/* Now the year */
+	tm->tm_year = atoi (&valstr[7]) - 1900;
+}
+
+/*
+ * Function: rc_getifname
+ *
+ * Purpose: get the network interface name associated with this tty
+ *
+ */
+
+char *rc_getifname(rc_handle *rh, char const *tty)
+{
+#if defined(BSD4_4) || defined(linux)
+	int		fd;
+
+	if ((fd = open(tty, O_RDWR|O_NDELAY)) < 0) {
+		rc_log(LOG_ERR, "rc_getifname: can't open %s: %s", tty, strerror(errno));
+		return NULL;
+	}
+#endif
+
+#ifdef BSD4_4
+	strcpy(rh->ifname,ttyname(fd));
+	if (strlen(rh->ifname) < 1) {
+		rc_log(LOG_ERR, "rc_getifname: can't get attached interface of %s: %s", tty, strerror(errno));
+		close(fd);
+		return NULL;
+	}
+#elif linux
+	if (ioctl(fd, SIOCGIFNAME, rh->ifname) < 0) {
+		rc_log(LOG_ERR, "rc_getifname: can't ioctl %s: %s", tty, strerror(errno));
+		close(fd);
+		return NULL;
+	}
+#else
+	return NULL;
+#endif
+
+#if defined(BSD4_4) || defined(linux)
+	close(fd);
+	return rh->ifname;
+#endif
+}
+
+/*
+ * Function: rc_getstr
+ *
+ * Purpose: Reads in a string from the user (with or witout echo)
+ *
+ */
+#ifndef _MSC_VER
+char *rc_getstr (rc_handle *rh, char const *prompt, int do_echo)
+{
+	int             in, out;
+	char           *p;
+	struct termios  term_old, term_new;
+	int		is_term, flags, old_flags;
+	char		c;
+	int		flushed = 0;
+	sigset_t        newset;
+	sigset_t        oldset;
+
+	in = fileno(stdin);
+	out = fileno(stdout);
+
+	(void) sigemptyset (&newset);
+	(void) sigaddset (&newset, SIGINT);
+	(void) sigaddset (&newset, SIGTSTP);
+	(void) sigaddset (&newset, SIGQUIT);
+
+	(void) sigprocmask (SIG_BLOCK, &newset, &oldset);
+
+	if ((is_term = isatty(in)))
+	{
+
+		(void) tcgetattr (in, &term_old);
+		term_new = term_old;
+		if (do_echo)
+			term_new.c_lflag |= ECHO;
+		else
+			term_new.c_lflag &= ~ECHO;
+
+		if (tcsetattr (in, TCSAFLUSH, &term_new) == 0)
+			flushed = 1;
+
+	}
+	else
+	{
+		is_term = 0;
+		if ((flags = fcntl(in, F_GETFL, 0)) >= 0) {
+			old_flags = flags;
+			flags |= O_NONBLOCK;
+
+			fcntl(in, F_SETFL, flags);
+
+			while (read(in, &c, 1) > 0)
+				/* nothing */;
+
+			fcntl(in, F_SETFL, old_flags);
+
+			flushed = 1;
+		}
+	}
+
+	(void)write(out, prompt, strlen(prompt));
+
+	/* well, this looks ugly, but it handles the following end of line
+	   markers: \r \r\0 \r\n \n \n\r, at least at a second pass */
+
+	p = rh->buf;
+	for (;;)
+	{
+		if (read(in, &c, 1) <= 0)
+			return NULL;
+
+		if (!flushed && ((c == '\0') || (c == '\r') || (c == '\n'))) {
+			flushed = 1;
+			continue;
+		}
+
+		if ((c == '\r') || (c == '\n'))
+			break;
+
+		flushed = 1;
+
+		if (p < rh->buf + GETSTR_LENGTH)
+		{
+			if (do_echo && !is_term)
+				(void)write(out, &c, 1);
+			*p++ = c;
+		}
+	}
+
+	*p = '\0';
+
+	if (!do_echo || !is_term) (void)write(out, "\r\n", 2);
+
+	if (is_term)
+		tcsetattr (in, TCSAFLUSH, &term_old);
+	else {
+		if ((flags = fcntl(in, F_GETFL, 0)) >= 0) {
+			old_flags = flags;
+			flags |= O_NONBLOCK;
+
+			fcntl(in, F_SETFL, flags);
+
+			while (read(in, &c, 1) > 0)
+				/* nothing */;
+
+			fcntl(in, F_SETFL, old_flags);
+		}
+	}
+
+	(void) sigprocmask (SIG_SETMASK, &oldset, NULL);
+
+	return rh->buf;
+}
+#endif
+void rc_mdelay(int msecs)
+{
+	struct timeval tv;
+
+	tv.tv_sec = (int) msecs / 1000;
+	tv.tv_usec = (msecs % 1000) * 1000;
+
+	select(0, NULL, NULL, NULL, &tv);
+}
+
+/*
+ * Function: rc_mksid
+ *
+ * Purpose: generate a quite unique string
+ *
+ * Remarks: not that unique at all...
+ *
+ */
+
+char *
+rc_mksid (rc_handle *rh)
+{
+  snprintf (rh->buf1, sizeof(rh->buf1), "%08lX%04X", (unsigned long int) time (NULL), (unsigned int) getpid ());
+  return rh->buf1;
+}
+
+/*
+ * Function: rc_new
+ *
+ * Purpose: Initialises new Radius Client handle
+ *
+ */
+
+rc_handle *
+rc_new(void)
+{
+	rc_handle *rh;
+
+	rh = malloc(sizeof(*rh));
+	if (rh == NULL) {
+                rc_log(LOG_CRIT, "rc_new: out of memory");
+                return NULL;
+        }
+	memset(rh, 0, sizeof(*rh));
+	return rh;
+}
+
+/*
+ * Function: rc_destroy
+ *
+ * Purpose: Destroys Radius Client handle reclaiming all memory
+ *
+ */
+
+void
+rc_destroy(rc_handle *rh)
+{
+
+	rc_map2id_free(rh);
+	rc_dict_free(rh);
+	rc_config_free(rh);
+	if (rh->this_host_bind_ipaddr != NULL)
+		free(rh->this_host_bind_ipaddr);
+	free(rh);
+}
+
+/*
+ * Function: rc_fgetln
+ *
+ * Purpose: Get next line from the stream.
+ *
+ */
+
+char *
+rc_fgetln(FILE *fp, size_t *len)
+{
+	static char *buf = NULL;
+	static size_t bufsiz = 0;
+	char *ptr;
+
+	if (buf == NULL) {
+		bufsiz = RC_BUFSIZ;
+		if ((buf = malloc(bufsiz)) == NULL)
+			return NULL;
+	}
+
+	if (fgets(buf, (int)bufsiz, fp) == NULL)
+		return NULL;
+	*len = 0;
+
+	while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
+		size_t nbufsiz = bufsiz + RC_BUFSIZ;
+		char *nbuf = realloc(buf, nbufsiz);
+
+		if (nbuf == NULL) {
+			int oerrno = errno;
+			free(buf);
+			errno = oerrno;
+			buf = NULL;
+			return NULL;
+		} else
+			buf = nbuf;
+
+		*len = bufsiz;
+		if (fgets(&buf[bufsiz], RC_BUFSIZ, fp) == NULL)
+			return buf;
+
+		bufsiz = nbufsiz;
+	}
+
+	*len = (ptr - buf) + 1;
+	return buf;
+}
+
+/*
+ * Function: rc_getctime
+ *
+ * Purpose: Get current time (seconds since epoch) expressed as
+ * double-precision floating point number.
+ *
+ */
+
+double
+rc_getctime(void)
+{
+    struct timeval timev;
+
+    if (gettimeofday(&timev, NULL) == -1)
+        return -1;
+
+    return timev.tv_sec + ((double)timev.tv_usec) / 1000000.0;
+}
diff --git a/src/plugins/vbng/vbng.api b/src/plugins/vbng/vbng.api
new file mode 100644
index 0000000..eba9a10
--- /dev/null
+++ b/src/plugins/vbng/vbng.api
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Intel Corp and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \brief vBNG DHCP config add / del request
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param rx_vrf_id - Rx/interface vrf id
+    @param server_vrf_id - server vrf id
+    @param is_add - add the config if non-zero, else delete
+    @param remote_addr[] - DHCP server address
+    @param local_addr[] - Local Address which could reach DHCP server
+*/
+define vbng_dhcp4_config
+{
+  u32 client_index;
+  u32 context;
+  u32 rx_vrf_id;
+  u32 server_vrf_id;
+  u8 is_add;
+  u8 remote_addr[16];
+  u8 local_addr[16];
+};
+
+/** \brief vBNG DHCP config response
+    @param context - sender context, to match reply w/ request
+    @param retval - return code for the request
+*/
+define vbng_dhcp4_config_reply
+{
+  u32 context;
+  i32 retval;
+};
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/vbng/vbng_aaa.c b/src/plugins/vbng/vbng_aaa.c
new file mode 100644
index 0000000..5e8861f
--- /dev/null
+++ b/src/plugins/vbng/vbng_aaa.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Intel and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <vbng/include/freeradius-client.h>
+#include <vbng/vbng_aaa.h>
+
+int
+process(void *rh, VALUE_PAIR *send, int nas_port)
+{
+    VALUE_PAIR *received = NULL;
+    char msg[PW_MAX_MSG_SIZE];
+    int retval;
+
+    retval = rc_auth(rh, nas_port, send, &received, msg);
+    if (retval == OK_RC && received != NULL) {
+        rc_avpair_free(received);
+    }
+
+    return retval;
+}
+
+int
+vbng_auth(vbng_dhcp4_main_t *dm, int argc, char **argv)
+{
+    int i, nas_port = dm->config.nas_port;
+    char *rc_conf = (char *)dm->config.config_file;
+    VALUE_PAIR *send, **vp;
+    void *rh;
+
+    if ((rh = rc_read_config(rc_conf)) == NULL) {
+        fprintf(stderr, "error opening radius configuration file\n");
+        return (1);
+    }
+
+    if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
+        fprintf(stderr, "error reading radius dictionary\n");
+        return (2);
+    }
+
+    send = NULL;
+    vp = &send;
+    for (i = 0; i < argc; i++) {
+        if (rc_avpair_parse(rh, argv[i], vp) < 0) {
+            fprintf(stderr, "%s: can't parse AV pair\n", argv[i]);
+            return (3);
+        }
+        vp = &send->next;
+    }
+
+    return process(rh, send, nas_port);
+}
+
diff --git a/src/plugins/vbng/vbng_aaa.h b/src/plugins/vbng/vbng_aaa.h
new file mode 100644
index 0000000..411a753
--- /dev/null
+++ b/src/plugins/vbng/vbng_aaa.h
@@ -0,0 +1,34 @@
+/*
+ * vbng_aaa.h - vBNG FreeRADIUS client commons.
+ *
+ * Copyright (c) 2017 Intel and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _VBNG_AAA_H_
+#define _VBNG_AAA_H_
+
+#include <vbng/vbng_dhcp4.h>
+
+/* Common configuration for RADIUS client */
+#define AAA_DEFAULT_NAS_PORT	5060
+#define AAA_DEFAULT_CONFIG_FILE	"/etc/vpp/vbng-aaa.cfg"
+
+#define BUF_LEN		4096
+
+/* String template for the vAAA attributes */
+#define STR_TPL_ATTR_DHCP_AGENT_CIRCUIT_ID "DHCP-Agent-Circuit-Id=%c"
+#define STR_TPL_ATTR_DHCP_AGENT_REMOTE_ID "DHCP-Agent-Remote-Id=%c"
+
+int vbng_auth(vbng_dhcp4_main_t *dm, int argc, char **argv);
+
+#endif /* _VBNG_AAA_H_ */
diff --git a/src/plugins/vbng/vbng_all_api_h.h b/src/plugins/vbng/vbng_all_api_h.h
new file mode 100644
index 0000000..3f74427
--- /dev/null
+++ b/src/plugins/vbng/vbng_all_api_h.h
@@ -0,0 +1,18 @@
+/*
+ * vbng_all_api_h.h - skeleton vpp engine plug-in api #include file
+ *
+ * Copyright (c) 2017 Intel and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vbng/vbng.api.h>
diff --git a/src/plugins/vbng/vbng_api.c b/src/plugins/vbng/vbng_api.c
new file mode 100644
index 0000000..4080f77
--- /dev/null
+++ b/src/plugins/vbng/vbng_api.c
@@ -0,0 +1,123 @@
+/*
+ *------------------------------------------------------------------
+ * vbng_api.c - vbng api
+ *
+ * Copyright (c) 2017 Intel Corp and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vnet/vnet.h>
+#include <vlibmemory/api.h>
+
+#include <vnet/interface.h>
+#include <vnet/api_errno.h>
+#include <vnet/dhcp/dhcp_proxy.h>
+#include <vnet/dhcp/client.h>
+#include <vnet/fib/fib_table.h>
+
+#include <vbng/vbng_msg_enum.h>
+
+#define vl_typedefs		/* define message structures */
+#include <vbng/vbng_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun		/* define message structures */
+#include <vbng/vbng_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_printfun
+#include <vbng/vbng_all_api_h.h>
+#undef vl_printfun
+
+#include <vlibapi/api_helper_macros.h>
+
+#define foreach_vpe_api_msg                       \
+_(VBNG_DHCP4_CONFIG,vbng_dhcp4_config)
+
+static void vl_api_vbng_dhcp4_config_t_handler
+  (vl_api_vbng_dhcp4_config_t * mp)
+{
+  vl_api_vbng_dhcp4_config_reply_t *rmp;
+  ip46_address_t src, server;
+  int rv = -1;
+
+  ip46_address_reset (&src);
+  ip46_address_reset (&server);
+
+  clib_memcpy (&src.ip4, mp->local_addr, sizeof (src.ip4));
+  clib_memcpy (&server.ip4, mp->remote_addr, sizeof (server.ip4));
+
+  rv = dhcp4_proxy_set_server (&server,
+		   &src,
+				   (u32) ntohl (mp->rx_vrf_id),
+				   (u32) ntohl (mp->server_vrf_id),
+				   (int) (mp->is_add == 0));
+
+
+  REPLY_MACRO (VL_API_VBNG_DHCP4_CONFIG_REPLY);
+}
+
+/*
+ * vbng_api_hookup
+ * Add vpe's API message handlers to the table.
+ * vlib has alread mapped shared memory and
+ * added the client registration handlers.
+ * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
+ */
+#define vl_msg_name_crc_list
+#include <vbng/vbng_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+static void
+setup_message_id_table (api_main_t * am)
+{
+#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
+  foreach_vl_msg_name_crc_vbng;
+#undef _
+}
+
+static clib_error_t *
+vbng_api_hookup (vlib_main_t * vm)
+{
+  api_main_t *am = &api_main;
+
+#define _(N,n)                                                  \
+    vl_msg_api_set_handlers(VL_API_##N, #n,                     \
+                           vl_api_##n##_t_handler,              \
+                           vl_noop_handler,                     \
+                           vl_api_##n##_t_endian,               \
+                           vl_api_##n##_t_print,                \
+                           sizeof(vl_api_##n##_t), 1);
+  foreach_vpe_api_msg;
+#undef _
+
+  /*
+   * Set up the (msg_name, crc, message-id) table
+   */
+  setup_message_id_table (am);
+
+  return 0;
+}
+
+VLIB_API_INIT_FUNCTION (vbng_api_hookup);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/vbng/vbng_dhcp4.c b/src/plugins/vbng/vbng_dhcp4.c
new file mode 100644
index 0000000..ed79df4
--- /dev/null
+++ b/src/plugins/vbng/vbng_dhcp4.c
@@ -0,0 +1,160 @@
+/*
+ * vbng_dhcp4.c: common dhcp v4 processing
+ *
+ * Copyright (c) 2017 Intel Corp and/or its affiliates and others.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/fib/fib_table.h>
+#include <vnet/mfib/mfib_table.h>
+
+#include <vbng/vbng_dhcp4.h>
+
+/**
+ * @brief Shard 4/6 instance of DHCP main
+ */
+vbng_dhcp4_main_t vbng_dhcp4_main;
+
+void
+vbng_dhcp4_walk (vbng_dhcp4_walk_fn_t fn,
+                 void *ctx)
+{
+  vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main;
+  dhcp_proxy_t * server;
+  u32 server_index, i;
+
+  vec_foreach_index (i, vdm->dhcp_server_index_by_rx_fib_index)
+  {
+      server_index = vdm->dhcp_server_index_by_rx_fib_index[i];
+      if (~0 == server_index)
+          continue;
+
+      server = pool_elt_at_index (vdm->dhcp4_servers, server_index);
+
+      if (!fn(server, ctx))
+          break;
+    }
+}
+
+static u32
+dhcp_proxy_server_find (dhcp_proxy_t *proxy,
+                        fib_protocol_t proto,
+                        ip46_address_t *addr,
+                        u32 server_table_id)
+{
+    dhcp_server_t *server;
+    u32 ii, fib_index;
+
+    vec_foreach_index(ii, proxy->dhcp_servers)
+    {
+        server = &proxy->dhcp_servers[ii];
+        fib_index = fib_table_find(proto, server_table_id);
+
+        if (ip46_address_is_equal(&server->dhcp_server,
+                                  addr) &&
+            (server->server_fib_index == fib_index))
+        {
+            return (ii);
+        }
+    }
+    return (~0);
+}
+
+int
+vbng_dhcp4_server_del (fib_protocol_t proto,
+                       u32 rx_fib_index,
+                       ip46_address_t *addr,
+                       u32 server_table_id)
+{
+  vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main;
+  dhcp_proxy_t *proxy = 0;
+
+  proxy = vbng_dhcp4_get_server(vdm, rx_fib_index);
+
+  if (NULL != proxy)
+  {
+      dhcp_server_t *server;
+      u32 index;
+
+      index = dhcp_proxy_server_find(proxy, proto, addr, server_table_id);
+
+      if (~0 != index)
+      {
+          server = &proxy->dhcp_servers[index];
+          fib_table_unlock (server->server_fib_index, proto);
+
+          vec_del1(proxy->dhcp_servers, index);
+
+          if (0 == vec_len(proxy->dhcp_servers))
+          {
+              /* no servers left, delete the proxy config */
+              vdm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0;
+              vec_free(proxy->dhcp_servers);
+              pool_put (vdm->dhcp4_servers, proxy);
+              return (1);
+          }
+      }
+  }
+
+  /* the proxy still exists */
+  return (0);
+}
+
+int
+vbng_dhcp4_server_add (fib_protocol_t proto,
+                       ip46_address_t *addr,
+                       ip46_address_t *src_address,
+                       u32 rx_fib_index,
+                       u32 server_table_id)
+{
+  vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main;
+  dhcp_proxy_t * proxy = 0;
+  int new = 0;
+
+  proxy = vbng_dhcp4_get_server(vdm, rx_fib_index);
+
+  if (NULL == proxy)
+  {
+      vec_validate_init_empty(vdm->dhcp_server_index_by_rx_fib_index,
+                              rx_fib_index,
+                              ~0);
+
+      pool_get (vdm->dhcp4_servers, proxy);
+      memset (proxy, 0, sizeof (*proxy));
+      new = 1;
+
+      vdm->dhcp_server_index_by_rx_fib_index[rx_fib_index] =
+          proxy - vdm->dhcp4_servers;
+
+      proxy->dhcp_src_address = *src_address;
+      proxy->rx_fib_index = rx_fib_index;
+  }
+  else
+  {
+      if (~0 != dhcp_proxy_server_find(proxy, proto, addr, server_table_id))
+      {
+          return (new);
+      }
+  }
+
+  dhcp_server_t server = {
+      .dhcp_server = *addr,
+      .server_fib_index = fib_table_find_or_create_and_lock(proto,
+                                                            server_table_id),
+  };
+
+  vec_add1(proxy->dhcp_servers, server);
+
+  return (new);
+}
+
diff --git a/src/plugins/vbng/vbng_dhcp4.h b/src/plugins/vbng/vbng_dhcp4.h
new file mode 100644
index 0000000..2f41575
--- /dev/null
+++ b/src/plugins/vbng/vbng_dhcp4.h
@@ -0,0 +1,139 @@
+/*
+ * vbng_dhcp4.h: DHCP v4 common functions/types
+ *
+ * Copyright (c) 2017 Intel Corp and/or its affiliates and others.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VBNG_DHCP4_H_
+#define _VBNG_DHCP4_H_
+
+#include <vnet/vnet.h>
+#include <vnet/dhcp/dhcp_proxy.h>
+#include <vnet/dhcp/dhcp4_packet.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ip/ip4.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/ip/format.h>
+#include <vnet/udp/udp.h>
+
+typedef enum {
+#define vbng_dhcp4_error(n,s) VBNG_DHCP4_ERROR_##n,
+#include <vbng/vbng_dhcp4_err.def>
+#undef vbng_dhcp4_error
+  VBNG_DHCP4_N_ERROR,
+} vbng_dhcp4_error_t;
+
+#define VBNG_AAA_DISABLED	0
+#define VBNG_AAA_ENABLED	1
+
+typedef struct {
+  int is_enabled;
+  u32 nas_port; /* AAA server port */
+  u8 *config_file; /* Radius Client config file path */
+} vbng_aaa_config_t;
+
+/**
+ * @brief Global configuration for the vBNG plugin.
+ */
+typedef struct {
+  /* Pool of DHCP servers */
+  dhcp_proxy_t *dhcp4_servers;
+
+  /* Pool of selected DHCP server. Zero is the default server */
+  u32 * dhcp_server_index_by_rx_fib_index;
+
+  /* to drop pkts in server-to-client direction */
+  u32 error_drop_node_index;
+
+  /* Configuration for the AAA client */
+  vbng_aaa_config_t config;
+
+  /* convenience */
+  vlib_main_t * vlib_main;
+  vnet_main_t * vnet_main;
+} vbng_dhcp4_main_t;
+
+extern vbng_dhcp4_main_t vbng_dhcp4_main;
+
+/**
+ * @brief Add a new DHCP proxy server configuration.
+ * @return 1 is the config is new,
+ *         0 otherwise (implying a modify of an existing)
+ */
+int vbng_dhcp4_server_add(fib_protocol_t proto,
+                          ip46_address_t *addr,
+                          ip46_address_t *src_address,
+                          u32 rx_fib_iindex,
+                          u32 server_table_id);
+
+/**
+ * @brief Delete a DHCP proxy config
+ * @return 1 if the proxy is deleted, 0 otherwise
+ */
+int vbng_dhcp4_server_del(fib_protocol_t proto,
+                          u32 rx_fib_index,
+                          ip46_address_t *addr,
+                          u32 server_table_id);
+
+u32
+dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto,
+                                  u32 fib_index);
+
+/**
+ * @brief Callback function invoked for each DHCP proxy entry
+ *  return 0 to break the walk, non-zero otherwise.
+ */
+typedef int (*vbng_dhcp4_walk_fn_t)(dhcp_proxy_t *server,
+                                    void *ctx);
+
+/**
+ * @brief Walk/Visit each vBNG DHCP server configurations
+ */
+void vbng_dhcp4_walk(vbng_dhcp4_walk_fn_t fn,
+                     void *ctx);
+
+/**
+ * @brief Get the DHCP proxy server data for the FIB index
+ */
+static inline dhcp_proxy_t *
+vbng_dhcp4_get_server(vbng_dhcp4_main_t *vm,
+		      u32 rx_fib_index)
+{
+	dhcp_proxy_t *s = NULL;
+
+	if (vec_len(vm->dhcp_server_index_by_rx_fib_index) > rx_fib_index &&
+	    vm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0)
+	{
+		s = pool_elt_at_index (
+		    vm->dhcp4_servers,
+		    vm->dhcp_server_index_by_rx_fib_index[rx_fib_index]);
+	}
+
+	return (s);
+}
+
+int vbng_dhcp4_set_server(ip46_address_t *addr,
+                          ip46_address_t *src_addr,
+                          u32 rx_table_id,
+                          u32 server_table_id,
+                          int is_del);
+
+#define DHCP_PACKET_OPTION_82		82
+#define DHCP_PACKET_OPTION82_SUB1	1
+#define DHCP_PACKET_OPTION82_SUB2	2
+#define DHCP_PACKET_OPTION82_SUB5	5
+
+#endif /* _VBNG_DHCP4_H_ */
diff --git a/src/plugins/vbng/vbng_dhcp4_err.def b/src/plugins/vbng/vbng_dhcp4_err.def
new file mode 100644
index 0000000..23f2d0d
--- /dev/null
+++ b/src/plugins/vbng/vbng_dhcp4_err.def
@@ -0,0 +1,29 @@
+/*
+ * vbng_dhcp4_err.def: VBNG DHCP4 Errors
+ *
+ * Copyright (c) 2017 Intel Corp and/or its affiliates and others.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+vbng_dhcp4_error (NONE, "no error")
+vbng_dhcp4_error (NO_SERVER, "no dhcp server configured")
+vbng_dhcp4_error (RELAY_TO_SERVER, "DHCP packets relayed to the server")
+vbng_dhcp4_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients")
+vbng_dhcp4_error (NO_INTERFACE_ADDRESS, "DHCP no interface address")
+vbng_dhcp4_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields")
+vbng_dhcp4_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.")
+vbng_dhcp4_error (PKT_TOO_BIG, "DHCP packets which are too big.")
+vbng_dhcp4_error (AAA_FAILURE, "DHCP packets failed to pass the AAA check.")
+vbng_dhcp4_error (NO_OPTION_82, "DHCP option 82 missing")
+vbng_dhcp4_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value")
+vbng_dhcp4_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value")
diff --git a/src/plugins/vbng/vbng_dhcp4_node.c b/src/plugins/vbng/vbng_dhcp4_node.c
new file mode 100644
index 0000000..205959b
--- /dev/null
+++ b/src/plugins/vbng/vbng_dhcp4_node.c
@@ -0,0 +1,1024 @@
+/*
+ * proxy_node.c: dhcp proxy node processing
+ *
+ * Copyright (c) 2013 Cisco and/or its affiliates and others.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/pg/pg.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/dhcp/client.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
+#include <vbng/vbng_dhcp4.h>
+#include <vbng/vbng_aaa.h>
+
+static char * vbng_dhcp4_error_strings[] = {
+#define vbng_dhcp4_error(n,s) s,
+#include <vbng/vbng_dhcp4_err.def>
+#undef vbng_dhcp4_error
+};
+
+#define foreach_vbng_dhcp4_to_server_input_next \
+  _ (DROP, "error-drop")			\
+  _ (LOOKUP, "ip4-lookup")			\
+  _ (SEND_TO_CLIENT, "vbng-dhcp-to-client")
+
+typedef enum {
+#define _(s,n) VBNG_DHCP4_TO_SERVER_INPUT_NEXT_##s,
+  foreach_vbng_dhcp4_to_server_input_next
+#undef _
+  VBNG_DHCP4_TO_SERVER_INPUT_N_NEXT,
+} vbng_dhcp4_to_server_input_next_t;
+
+typedef struct {
+  /* 0 => to server, 1 => to client */
+  int which;
+  ip4_address_t trace_ip4_address;
+  u32 error;
+  u32 sw_if_index;
+  u32 original_sw_if_index;
+} dhcp_proxy_trace_t;
+
+#define VPP_DHCP_OPTION82_SUB1_SIZE   6
+#define VPP_DHCP_OPTION82_SUB5_SIZE   6
+#define VPP_DHCP_OPTION82_VSS_SIZE    12
+#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \
+                                VPP_DHCP_OPTION82_SUB5_SIZE + \
+                                VPP_DHCP_OPTION82_VSS_SIZE +3)
+
+static vlib_node_registration_t vbng_dhcp4_to_server_node;
+static vlib_node_registration_t vbng_dhcp4_to_client_node;
+
+static u8 *
+format_dhcp_proxy_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *);
+ 
+  if (t->which == 0)
+    s = format (s, "DHCP proxy: sent to server %U\n",
+                format_ip4_address, &t->trace_ip4_address, t->error);
+  else
+    s = format (s, "DHCP proxy: broadcast to client from %U\n",
+                format_ip4_address, &t->trace_ip4_address);
+
+  if (t->error != (u32)~0)
+    s = format (s, "  error: %s\n", vbng_dhcp4_error_strings[t->error]);
+
+  s = format (s, "  original_sw_if_index: %d, sw_if_index: %d\n",
+              t->original_sw_if_index, t->sw_if_index);
+  
+  return s;
+}
+
+static u8 *
+format_dhcp_proxy_header_with_length (u8 * s, va_list * args)
+{
+  dhcp_header_t * h = va_arg (*args, dhcp_header_t *);
+  u32 max_header_bytes = va_arg (*args, u32);
+  u32 header_bytes;
+
+  header_bytes = sizeof (h[0]);
+  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
+    return format (s, "dhcp header truncated");
+
+  s = format (s, "DHCP Proxy");
+
+  return s;
+}
+
+static uword
+vbng_dhcp_to_server_input (vlib_main_t * vm,
+                           vlib_node_runtime_t * node,
+                           vlib_frame_t * from_frame)
+{
+  u32 n_left_from, next_index, * from, * to_next;
+  vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
+  from = vlib_frame_vector_args (from_frame);
+  n_left_from = from_frame->n_vectors;
+  u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0;
+  u32 pkts_no_interface_address=0;
+  u32 pkts_too_big=0, pkts_aaa_fail = 0;
+  ip4_main_t * im = &ip4_main;
+
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index,
+			   to_next, n_left_to_next);
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+	{
+	  u32 bi0;
+	  vlib_buffer_t * b0;
+          udp_header_t * u0;
+	  dhcp_header_t * h0;
+          ip4_header_t * ip0;
+	  u32 next0;
+          u32 old0, new0;
+          ip_csum_t sum0;
+          u32 error0 = (u32) ~0;
+          u32 sw_if_index = 0;
+          u32 original_sw_if_index = 0;
+          u8  *end = NULL;
+          u32 fib_index;
+          dhcp_proxy_t *proxy;
+          dhcp_server_t *server;
+          u32 rx_sw_if_index;
+          dhcp_option_t *o;
+          u32 len = 0;
+          vlib_buffer_free_list_t *fl;
+          u8 is_discover = 0;
+
+	  bi0 = from[0];
+	  from += 1;
+	  n_left_from -= 1;
+
+	  b0 = vlib_get_buffer (vm, bi0);
+
+          h0 = vlib_buffer_get_current (b0);
+
+          /* 
+           * udp_local hands us the DHCP header, need udp hdr, 
+           * ip hdr to relay to server
+           */
+          vlib_buffer_advance (b0, -(sizeof(*u0)));
+	  u0 = vlib_buffer_get_current (b0);
+
+          /* This blows. Return traffic has src_port = 67, dst_port = 67 */
+          if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server))
+            {
+              vlib_buffer_advance (b0, sizeof(*u0));
+              next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
+              error0 = 0;
+              pkts_to_client++;
+              goto do_enqueue;
+            }
+
+          rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+
+          fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index];
+          proxy = vbng_dhcp4_get_server(dm, fib_index);
+
+          if (PREDICT_FALSE (NULL == proxy))
+            {
+              error0 = VBNG_DHCP4_ERROR_NO_SERVER;
+              next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
+              pkts_no_server++;
+              goto do_trace;
+            }
+
+          server = &proxy->dhcp_servers[0];
+          vlib_buffer_advance (b0, -(sizeof(*ip0)));
+          ip0 = vlib_buffer_get_current (b0);
+
+          /* disable UDP checksum */
+          u0->checksum = 0;
+          sum0 = ip0->checksum;
+          old0 = ip0->dst_address.as_u32;
+          new0 = server->dhcp_server.ip4.as_u32;
+          ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
+          sum0 = ip_csum_update (sum0, old0, new0, 
+                                ip4_header_t /* structure */, 
+                                dst_address /* changed member */);
+          ip0->checksum = ip_csum_fold (sum0);
+
+          sum0 = ip0->checksum;
+          old0 = ip0->src_address.as_u32;
+          new0 = proxy->dhcp_src_address.ip4.as_u32;
+          ip0->src_address.as_u32 = new0;
+          sum0 = ip_csum_update (sum0, old0, new0, 
+                                ip4_header_t /* structure */, 
+                                src_address /* changed member */);
+          ip0->checksum = ip_csum_fold (sum0);
+
+          /* Send to DHCP server via the configured FIB */
+          vnet_buffer(b0)->sw_if_index[VLIB_TX] =
+            server->server_fib_index;
+
+          h0->gateway_ip_address.as_u32 = proxy->dhcp_src_address.ip4.as_u32;
+          pkts_to_server++;
+
+          o = (dhcp_option_t *) h0->options;
+              
+          fib_index = im->fib_index_by_sw_if_index 
+              [vnet_buffer(b0)->sw_if_index[VLIB_RX]];
+
+          end = b0->data + b0->current_data + b0->current_length;
+          /* TLVs are not performance-friendly... */
+          while  (o->option != 0xFF /* end of options */ && (u8 *)o < end) 
+            {
+              if (DHCP_PACKET_OPTION_MSG_TYPE == o->option)
+                {
+                  if (DHCP_PACKET_DISCOVER == o->data[0])
+                    {
+                      is_discover = 1;
+                    }
+                }
+
+	      if (DHCP_PACKET_OPTION_82 == o->option) {
+                /* For Demo purpose only */
+                if (dm->config.is_enabled) {
+                  int i = 0, num_kvs = 0, retval = 0;
+                  char *kv_pairs[1];
+                  char key_string[32];
+
+                  if (DHCP_PACKET_OPTION82_SUB1 == o->data[0]) {
+                      sprintf(key_string,  STR_TPL_ATTR_DHCP_AGENT_CIRCUIT_ID, o->data[2]);
+                      for (i = 1; i < o->data[1]; i++) {
+                          sprintf(key_string, "%s%c", key_string, o->data[2 + i]);
+                      }
+                  }
+
+                  if (DHCP_PACKET_OPTION82_SUB2 == o->data[0]) {
+                      sprintf(key_string, STR_TPL_ATTR_DHCP_AGENT_REMOTE_ID, o->data[2]);
+                      for (i = 1; i < o->data[1]; i++) {
+                          sprintf(key_string, "%s%c", key_string, o->data[2 + i]);
+                      }
+                  }
+
+                  kv_pairs[num_kvs] = key_string;
+                  num_kvs++;
+
+		  retval = vbng_auth(dm, num_kvs, kv_pairs);
+		  if (retval) {
+                    if (retval == 1 /* TIMEOUT_RC */) {
+                        dm->config.is_enabled = VBNG_AAA_DISABLED;
+                    }
+                    error0 = VBNG_DHCP4_ERROR_AAA_FAILURE;
+                    next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
+                    pkts_aaa_fail++;
+                    goto do_trace;
+		  }
+  	        }
+
+                fl = vlib_buffer_get_free_list (vm, b0->free_list_index);
+                if (((u8 *)o - (u8 *)b0->data + (VPP_DHCP_OPTION82_SUB1_SIZE + VPP_DHCP_OPTION82_SUB5_SIZE))
+                    > fl->n_data_bytes)
+                {
+                    next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
+                    pkts_too_big++;
+                    goto do_trace;
+                }
+
+                /* Begin to appending new sub-options */
+                {
+                    vnet_main_t *vnm = vnet_get_main();   
+                    u16 old_l0, new_l0, orig_len = 0;
+                    ip4_address_t _ia0, * ia0 = &_ia0;
+                    vnet_sw_interface_t *swif;
+                    sw_if_index = 0;
+                    original_sw_if_index = 0;
+                        
+                    original_sw_if_index = sw_if_index = 
+                        vnet_buffer(b0)->sw_if_index[VLIB_RX];
+                    swif = vnet_get_sw_interface (vnm, sw_if_index);
+                    if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
+                        sw_if_index = swif->unnumbered_sw_if_index;
+                        
+                    /* 
+                     * Get the first ip4 address on the [client-side] 
+                     * RX interface, if not unnumbered. otherwise use
+                     * the loopback interface's ip address.
+                     */
+                    ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0);
+                        
+                    if (ia0 == 0)
+                    {
+                        error0 = VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS;
+                        next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP;
+                        pkts_no_interface_address++;
+                        goto do_trace;
+                    }
+
+                    orig_len = o->length;
+                    o->data[orig_len + 0] = 1;   /* suboption 1, circuit ID (=FIB id) */
+                    o->data[orig_len + 1] = 4;   /* length of suboption */
+                    o->data[orig_len + 2] = (original_sw_if_index >> 24) & 0xFF;
+                    o->data[orig_len + 3] = (original_sw_if_index >> 16) & 0xFF;
+                    o->data[orig_len + 4] = (original_sw_if_index >> 8)  & 0xFF;
+                    o->data[orig_len + 5] = (original_sw_if_index >> 0)  & 0xFF;
+                    o->data[orig_len + 6] = 5; /* suboption 5 (client RX intfc address) */
+                    o->data[orig_len + 7] = 4; /* length 4 */
+                    o->data[orig_len + 8] = ia0->as_u8[0];
+                    o->data[orig_len + 9] = ia0->as_u8[1];
+                    o->data[orig_len + 10] = ia0->as_u8[2];
+                    o->data[orig_len + 11] = ia0->as_u8[3];
+                    o->data[orig_len + 12] = 0xFF;
+                    o->length += 12;   /* 12 octets appended*/
+
+                    len = o->length + 3;
+                    b0->current_length += len;
+                    /* Fix IP header length and checksum */
+                    old_l0 = ip0->length;
+                    new_l0 = clib_net_to_host_u16 (old_l0);
+                    new_l0 += len;
+                    new_l0 = clib_host_to_net_u16 (new_l0);
+                    ip0->length = new_l0;
+                    sum0 = ip0->checksum;
+                    sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
+                                           length /* changed member */);
+                    ip0->checksum = ip_csum_fold (sum0);
+      
+                    /* Fix UDP length */
+                    new_l0 = clib_net_to_host_u16 (u0->length);
+                    new_l0 += len;
+                    u0->length = clib_host_to_net_u16 (new_l0);
+                }
+              }
+
+              o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
+          }
+
+          next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP;
+
+          /*
+           * If we have multiple servers configured and this is the
+           * client's discover message, then send copies to each of
+           * those servers
+           */
+          if (is_discover && vec_len(proxy->dhcp_servers) > 1)
+          {
+              u32 ii;
+
+              for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++)
+              {
+                  vlib_buffer_t *c0;
+                  u32 ci0;
+              
+                  c0 = vlib_buffer_copy(vm, b0);
+                  ci0 = vlib_get_buffer_index(vm, c0);
+                  server = &proxy->dhcp_servers[ii];
+
+                  ip0 = vlib_buffer_get_current (c0);
+
+                  sum0 = ip0->checksum;
+                  old0 = ip0->dst_address.as_u32;
+                  new0 = server->dhcp_server.ip4.as_u32;
+                  ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
+                  sum0 = ip_csum_update (sum0, old0, new0, 
+                                         ip4_header_t /* structure */, 
+                                         dst_address /* changed member */);
+                  ip0->checksum = ip_csum_fold (sum0);
+
+                  to_next[0] = ci0;
+                  to_next += 1;
+                  n_left_to_next -= 1;
+
+                  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+                                                   to_next, n_left_to_next,
+                                                   ci0, next0);
+
+                  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
+                  {
+                      dhcp_proxy_trace_t *tr;
+
+                      tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
+                      tr->which = 0; /* to server */
+                      tr->error = error0;
+                      tr->original_sw_if_index = original_sw_if_index;
+                      tr->sw_if_index = sw_if_index;
+                      if (next0 == VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP)
+                          tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32;
+                  }
+
+                  if (PREDICT_FALSE(0 == n_left_to_next))
+                  {
+                      vlib_put_next_frame (vm, node, next_index,
+                                           n_left_to_next);
+                      vlib_get_next_frame (vm, node, next_index,
+                                           to_next, n_left_to_next);
+                  }
+              }
+          }
+        do_trace:
+          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
+            {
+               dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, 
+                                                        b0, sizeof (*tr));
+               tr->which = 0; /* to server */
+               tr->error = error0;
+               tr->original_sw_if_index = original_sw_if_index;
+               tr->sw_if_index = sw_if_index;
+               if (next0 == VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP)
+                 tr->trace_ip4_address.as_u32 =
+                     proxy->dhcp_servers[0].dhcp_server.ip4.as_u32;
+            }
+
+        do_enqueue:
+	  to_next[0] = bi0;
+	  to_next += 1;
+	  n_left_to_next -= 1;
+
+	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+					   to_next, n_left_to_next,
+					   bi0, next0);
+	}
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
+                               VBNG_DHCP4_ERROR_RELAY_TO_CLIENT,
+                               pkts_to_client);
+  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
+                               VBNG_DHCP4_ERROR_RELAY_TO_SERVER,
+                               pkts_to_server);
+  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
+                               VBNG_DHCP4_ERROR_NO_SERVER,
+                               pkts_no_server);
+  vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
+                               VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS,
+                               pkts_no_interface_address);
+ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
+                              VBNG_DHCP4_ERROR_PKT_TOO_BIG,
+                              pkts_too_big);
+ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index,
+                              VBNG_DHCP4_ERROR_AAA_FAILURE,
+                              pkts_aaa_fail);
+  return from_frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (vbng_dhcp4_to_server_node, static) = {
+  .function = vbng_dhcp_to_server_input,
+  .name = "vbng-dhcp-to-server",
+  /* Takes a vector of packets. */
+  .vector_size = sizeof (u32),
+
+  .n_errors = VBNG_DHCP4_N_ERROR,
+  .error_strings = vbng_dhcp4_error_strings,
+
+  .n_next_nodes = VBNG_DHCP4_TO_SERVER_INPUT_N_NEXT,
+  .next_nodes = {
+#define _(s,n) [VBNG_DHCP4_TO_SERVER_INPUT_NEXT_##s] = n,
+    foreach_vbng_dhcp4_to_server_input_next
+#undef _
+  },
+
+  .format_buffer = format_dhcp_proxy_header_with_length,
+  .format_trace = format_dhcp_proxy_trace,
+};
+
+static uword
+vbng_dhcp_to_client_input (vlib_main_t * vm,
+                           vlib_node_runtime_t * node,
+                           vlib_frame_t * from_frame)
+{
+  u32 n_left_from, * from;
+  ethernet_main_t *em = ethernet_get_main (vm);
+  vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
+  vnet_main_t * vnm = vnet_get_main();
+  ip4_main_t * im = &ip4_main;
+
+  from = vlib_frame_vector_args (from_frame);
+  n_left_from = from_frame->n_vectors;
+
+  while (n_left_from > 0)
+    {
+      u32 bi0;
+      vlib_buffer_t * b0;
+      udp_header_t * u0;
+      dhcp_header_t * h0;
+      ip4_header_t * ip0 = 0;
+      ip4_address_t * ia0 = 0;
+      u32 old0, new0;
+      ip_csum_t sum0;
+      ethernet_interface_t *ei0;
+      ethernet_header_t *mac0;
+      vnet_hw_interface_t *hi0;
+      vlib_frame_t *f0;
+      u32 * to_next0;
+      u32 sw_if_index = ~0;
+      vnet_sw_interface_t *si0;
+      u32 error0 = (u32)~0;
+      vnet_sw_interface_t *swif;
+      u32 fib_index;
+      dhcp_proxy_t *proxy;
+      dhcp_server_t *server;
+      u32 original_sw_if_index = (u32) ~0;
+      ip4_address_t relay_addr = {
+          .as_u32 = 0,
+      };
+
+      bi0 = from[0];
+      from += 1;
+      n_left_from -= 1;
+
+      b0 = vlib_get_buffer (vm, bi0);
+      h0 = vlib_buffer_get_current (b0);
+
+      /* 
+       * udp_local hands us the DHCP header, need udp hdr, 
+       * ip hdr to relay to client
+       */
+      vlib_buffer_advance (b0, -(sizeof(*u0)));
+      u0 = vlib_buffer_get_current (b0);
+
+      vlib_buffer_advance (b0, -(sizeof(*ip0)));
+      ip0 = vlib_buffer_get_current (b0);
+
+      {
+          dhcp_option_t *o = (dhcp_option_t *) h0->options;
+          dhcp_option_t *sub;
+              
+          /* Parse through TLVs looking for option 82.
+             The circuit-ID is the FIB number we need
+             to track down the client-facing interface */
+
+          while (o->option != 0xFF /* end of options */ &&
+                 (u8 *) o < (b0->data + b0->current_data + b0->current_length))
+            {
+              if (o->option == 82)
+                {
+                    sub = (dhcp_option_t *) &o->data[0];
+                    while (sub->option != 0xFF /* end of options */ &&
+                           (u8 *) sub < (u8 *)(o + o->length)) {
+                        /* If this is one of ours, it will have
+                           total length 12, circuit-id suboption type,
+                           and the sw_if_index */
+                        if (sub->option == 1 && sub->length == 4)
+                          {
+                            sw_if_index = ((sub->data[0] << 24) |
+                                           (sub->data[1] << 16) |
+                                           (sub->data[2] << 8)  |
+                                           (sub->data[3]));
+                          }
+                        else if (sub->option == 5 && sub->length == 4)
+                          {
+                              relay_addr.as_u8[0] = sub->data[0];
+                              relay_addr.as_u8[1] = sub->data[1];
+                              relay_addr.as_u8[2] = sub->data[2];
+                              relay_addr.as_u8[3] = sub->data[3];
+                          }
+                        sub = (dhcp_option_t *) 
+                          (((uword) sub) + (sub->length + 2));
+                    }
+
+                }
+              o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
+            }
+        }
+
+      if (sw_if_index == (u32)~0)
+        {
+          error0 = VBNG_DHCP4_ERROR_NO_OPTION_82;
+          
+        drop_packet:
+          vlib_node_increment_counter (vm, vbng_dhcp4_to_client_node.index,
+                                       error0, 1);
+          f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index);
+          to_next0 = vlib_frame_vector_args (f0);
+          to_next0[0] = bi0;
+          f0->n_vectors = 1;
+          vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0);
+          goto do_trace;
+        }
+      
+      if (relay_addr.as_u32 == 0)
+        {
+          error0 = VBNG_DHCP4_ERROR_BAD_OPTION_82_ADDR;
+          goto drop_packet;
+        }
+
+      if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index))
+        {
+          error0 = VBNG_DHCP4_ERROR_BAD_OPTION_82_ITF;
+          goto drop_packet;
+        }
+
+      fib_index = im->fib_index_by_sw_if_index [sw_if_index];
+      proxy = vbng_dhcp4_get_server(dm, fib_index);
+
+      if (PREDICT_FALSE (NULL == proxy))
+        {
+          error0 = VBNG_DHCP4_ERROR_NO_SERVER;
+          goto drop_packet;
+        }
+      
+      vec_foreach(server, proxy->dhcp_servers)
+        {
+          if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32)
+            {
+              goto server_found;
+            }
+        }
+
+      error0 = VBNG_DHCP4_ERROR_BAD_SVR_FIB_OR_ADDRESS;
+      goto drop_packet;
+
+    server_found:
+      vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
+
+      swif = vnet_get_sw_interface (vnm, sw_if_index);
+      original_sw_if_index = sw_if_index;
+      if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
+          sw_if_index = swif->unnumbered_sw_if_index;
+
+      ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
+      if (ia0 == 0)
+        {
+          error0 = VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS;
+          goto drop_packet;
+        }
+
+      if (relay_addr.as_u32 != ia0->as_u32)
+        {             
+          error0 = VBNG_DHCP4_ERROR_BAD_YIADDR;
+          goto drop_packet;
+        }
+
+      u0->checksum = 0;
+      u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client);
+      sum0 = ip0->checksum;
+      old0 = ip0->dst_address.as_u32;
+      new0 = 0xFFFFFFFF;
+      ip0->dst_address.as_u32 = new0;
+      sum0 = ip_csum_update (sum0, old0, new0, 
+                            ip4_header_t /* structure */, 
+                            dst_address /* offset of changed member */);
+      ip0->checksum = ip_csum_fold (sum0);
+
+      sum0 = ip0->checksum;
+      old0 = ip0->src_address.as_u32;
+      new0 = ia0->as_u32;
+      ip0->src_address.as_u32 = new0;
+      sum0 = ip_csum_update (sum0, old0, new0, 
+                            ip4_header_t /* structure */, 
+                            src_address /* offset of changed member */);
+      ip0->checksum = ip_csum_fold (sum0);
+
+      vlib_buffer_advance (b0, -(sizeof(ethernet_header_t)));
+      si0 = vnet_get_sw_interface (vnm, original_sw_if_index);
+      if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
+	  vlib_buffer_advance (b0, -4 /* space for VLAN tag */);
+
+      mac0 = vlib_buffer_get_current (b0);
+
+      hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index);
+      ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance);
+      clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address));
+      memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address));
+      mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ?
+	clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800);
+
+      if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
+	{
+	  u32 * vlan_tag = (u32 *)(mac0+1);
+	  u32 tmp;
+	  tmp = (si0->sub.id << 16) | 0x0800;
+	  *vlan_tag = clib_host_to_net_u32 (tmp);
+	}
+
+      /* $$$ This needs to be rewritten, for sure */
+      f0 = vlib_get_frame_to_node (vm, hi0->output_node_index);
+      to_next0 = vlib_frame_vector_args (f0);
+      to_next0[0] = bi0;
+      f0->n_vectors = 1;
+      vlib_put_frame_to_node (vm, hi0->output_node_index, f0);
+
+    do_trace:
+      if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
+        {
+          dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, 
+                                                   b0, sizeof (*tr));
+          tr->which = 1; /* to client */
+          tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0;
+          tr->error = error0;
+          tr->original_sw_if_index = original_sw_if_index;
+          tr->sw_if_index = sw_if_index;
+        }
+    }
+  return from_frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (vbng_dhcp4_to_client_node, static) = {
+  .function = vbng_dhcp_to_client_input,
+  .name = "vbng-dhcp-to-client",
+  /* Takes a vector of packets. */
+  .vector_size = sizeof (u32),
+
+  .n_errors = VBNG_DHCP4_N_ERROR,
+  .error_strings = vbng_dhcp4_error_strings,
+  .format_buffer = format_dhcp_proxy_header_with_length,
+  .format_trace = format_dhcp_proxy_trace,
+};
+
+static clib_error_t *
+vbng_dhcp4_proxy_init (vlib_main_t * vm)
+{
+  vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
+  vlib_node_t * error_drop_node;
+
+  error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
+  dm->error_drop_node_index = error_drop_node->index;
+
+  udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, 
+                         vbng_dhcp4_to_client_node.index, 1 /* is_ip4 */);
+
+  udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, 
+                         vbng_dhcp4_to_server_node.index, 1 /* is_ip4 */);
+
+  dm->vlib_main = vm;
+  dm->vnet_main = vnet_get_main();
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_INIT_FUNCTION (vbng_dhcp4_proxy_init);
+/* *INDENT-ON* */
+
+int
+vbng_dhcp4_set_server (ip46_address_t *addr,
+                       ip46_address_t *src_addr,
+                       u32 rx_table_id,
+                       u32 server_table_id, 
+                       int is_del)
+{
+  u32 rx_fib_index = 0;
+  int rc = 0;
+
+  const fib_prefix_t all_1s =
+  {
+      .fp_len = 32,
+      .fp_addr.ip4.as_u32 = 0xffffffff,
+      .fp_proto = FIB_PROTOCOL_IP4,
+  };
+
+  if (ip46_address_is_zero(addr))
+    return VNET_API_ERROR_INVALID_DST_ADDRESS;
+  
+  if (ip46_address_is_zero(src_addr))
+    return VNET_API_ERROR_INVALID_SRC_ADDRESS;
+
+  rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
+                                                   rx_table_id);
+
+  if (is_del)
+    {
+      if (vbng_dhcp4_server_del (FIB_PROTOCOL_IP4, rx_fib_index,
+                                 addr, server_table_id))
+      {
+          fib_table_entry_special_remove(rx_fib_index,
+                                         &all_1s,
+                                         FIB_SOURCE_DHCP);
+          fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4);
+      }
+    }
+  else
+  {
+      if (vbng_dhcp4_server_add (FIB_PROTOCOL_IP4,
+                                 addr, src_addr,
+                                 rx_fib_index, server_table_id))
+      {
+          fib_table_entry_special_add(rx_fib_index,
+                                      &all_1s,
+                                      FIB_SOURCE_DHCP,
+                                      FIB_ENTRY_FLAG_LOCAL);
+          fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4);
+      }
+  }
+  fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4);
+
+  return (rc);
+}
+
+static clib_error_t *
+dhcp4_proxy_set_command_fn (vlib_main_t * vm,
+                            unformat_input_t * input,
+                            vlib_cli_command_t * cmd)
+{
+  ip46_address_t server_addr, src_addr;
+  u32 server_table_id = 0, rx_table_id = 0;
+  int is_del = 0;
+  int set_src = 0, set_server = 0;
+
+  memset(&server_addr, 0, sizeof(server_addr));
+  memset(&src_addr, 0, sizeof(src_addr));
+
+  while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
+    {
+      if (unformat (input, "remote %U", 
+                    unformat_ip4_address, &server_addr.ip4)) 
+        set_server = 1;
+      else if (unformat (input, "server-fib-id %d", &server_table_id))
+        ;
+      else if (unformat (input, "rx-fib-id %d", &rx_table_id))
+        ;
+      else if (unformat(input, "local %U", 
+			unformat_ip4_address, &src_addr.ip4))
+        set_src = 1;
+      else if (unformat (input, "delete") ||
+               unformat (input, "del"))
+        is_del = 1;
+      else
+        break;
+    }
+
+  if (is_del || (set_server && set_src))
+    {
+      int rv;
+
+      rv = vbng_dhcp4_set_server (&server_addr, &src_addr, rx_table_id, 
+                                   server_table_id, is_del);
+      switch (rv)
+        {
+        case 0:
+          return 0;
+
+        case VNET_API_ERROR_INVALID_DST_ADDRESS:
+          return clib_error_return (0, "Invalid remote address");
+          
+        case VNET_API_ERROR_INVALID_SRC_ADDRESS:
+          return clib_error_return (0, "Invalid local address");
+
+        case VNET_API_ERROR_NO_SUCH_ENTRY:
+          return clib_error_return 
+            (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id);
+
+        default:
+          return clib_error_return (0, "BUG: rv %d", rv);
+        }
+    }
+  else
+    return clib_error_return (0, "parse error`%U'",
+                              format_unformat_error, input);
+}
+
+VLIB_CLI_COMMAND (vbng_dhcp4_set_command, static) = {
+  .path = "set vbng dhcp4",
+  .short_help = "set vbng dhcp4 [del] remote <ip-addr> local <ip-addr> [server-fib-id <n>] [rx-fib-id <n>]",
+  .function = dhcp4_proxy_set_command_fn,
+};
+
+static u8 *
+format_dhcp4_proxy_server (u8 * s, va_list * args)
+{
+  dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *);
+  ip4_fib_t * rx_fib, * server_fib;
+  dhcp_server_t *server;
+
+  if (proxy == 0)
+    {
+        s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", 
+                    "Servers FIB,Address");
+      return s;
+    }
+
+  rx_fib = ip4_fib_get(proxy->rx_fib_index);
+
+  s = format (s, "%=14u%=16U",
+              rx_fib->table_id,
+              format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY);
+
+  vec_foreach(server, proxy->dhcp_servers)
+  {
+      server_fib = ip4_fib_get(server->server_fib_index);
+      s = format (s, "%u,%U  ",
+                  server_fib->table_id,
+                  format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY);
+  }
+  return s;
+}
+
+static int
+dhcp4_proxy_show_walk (dhcp_proxy_t *server,
+                       void *ctx)
+{
+    vlib_main_t * vm = ctx;
+
+    vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, server);
+
+    return (1);
+}
+
+static clib_error_t *
+vbng_dhcp4_show_command_fn (vlib_main_t * vm,
+                            unformat_input_t * input,
+                            vlib_cli_command_t * cmd)
+{
+  vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, NULL /* header line */);
+
+  vbng_dhcp4_walk(dhcp4_proxy_show_walk, vm);
+
+  return (NULL);
+}
+
+VLIB_CLI_COMMAND (vbng_dhcp4_show_command, static) = {
+  .path = "show vbng dhcp4",
+  .short_help = "Display vbng DHCP4 configuration info",
+  .function = vbng_dhcp4_show_command_fn,
+};
+
+static clib_error_t *
+vbng_aaa_set_command_fn (vlib_main_t * vm,
+                         unformat_input_t * input,
+                         vlib_cli_command_t * cmd)
+{
+	vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
+	u8 *config_file = NULL;
+	u32 nas_port  = 0;
+	int set_config = 0, is_del = 0;
+
+	while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) {
+		if (unformat (input, "nas-port %d", &nas_port))
+			;
+		else if (unformat (input, "config %v", &config_file))
+			set_config = 1;
+		else if (unformat (input, "delete") ||
+		    unformat (input, "del"))
+			is_del = 1;
+		else
+			break;
+	}
+
+	if (!is_del && set_config) {
+		if (dm->config.is_enabled == VBNG_AAA_ENABLED) {
+			return 0;
+		}
+
+		if (nas_port) {
+			dm->config.nas_port = nas_port;
+		} else {
+			dm->config.nas_port = AAA_DEFAULT_NAS_PORT;
+		}
+		dm->config.config_file = config_file;
+		dm->config.is_enabled = VBNG_AAA_ENABLED;
+	} else if (is_del) {
+		if (dm->config.is_enabled == VBNG_AAA_DISABLED) {
+			return 0;
+		}
+
+		vec_free (dm->config.config_file);
+		dm->config.config_file = format(0, "%s",  AAA_DEFAULT_CONFIG_FILE);
+		dm->config.nas_port = AAA_DEFAULT_NAS_PORT;
+		dm->config.is_enabled = VBNG_AAA_DISABLED;
+	} else {
+		return clib_error_return (0, "parse error`%U'",
+		    format_unformat_error, input);
+	}
+
+	return 0;
+}
+
+VLIB_CLI_COMMAND (vbng_aaa_set_command, static) = {
+	.path = "set vbng aaa",
+	.short_help = "set vbng aaa [del] config <file> [nas-port <n>]",
+	.function = vbng_aaa_set_command_fn,
+};
+
+static u8 *
+format_vbng_aaa_config(u8 *s, va_list *args)
+{
+	vbng_dhcp4_main_t *dm = &vbng_dhcp4_main;
+
+	s = format(s, "%=8s %=8s %s\n", "Enabled",
+		   "NAS Port", "Config File");
+
+	s = format(s, "%=8s %=8d %v\n",
+		dm->config.is_enabled ? "True" : "False",
+		dm->config.nas_port,
+		dm->config.config_file);
+
+	return s;
+}
+
+static clib_error_t *
+vbng_aaa_show_command_fn (vlib_main_t * vm,
+                          unformat_input_t * input,
+                          vlib_cli_command_t * cmd)
+{
+  vlib_cli_output (vm, "%U", format_vbng_aaa_config, NULL);
+
+  return (NULL);
+}
+
+VLIB_CLI_COMMAND (vbng_aaa_show_command, static) = {
+	.path = "show vbng aaa",
+	.short_help = "Display vbng AAA configuration info",
+	.function = vbng_aaa_show_command_fn,
+};
+
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () = {
+	.version = VPP_BUILD_VER,
+	.description = "DHCP V4 Proxy With Radius Client",
+};
+/* *INDENT-ON* */
diff --git a/src/plugins/vbng/vbng_msg_enum.h b/src/plugins/vbng/vbng_msg_enum.h
new file mode 100644
index 0000000..1dc1357
--- /dev/null
+++ b/src/plugins/vbng/vbng_msg_enum.h
@@ -0,0 +1,31 @@
+/*
+ * vbng_msg_enum.h - vpp engine plug-in message enumeration
+ *
+ * Copyright (c) 2017 Intel and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _VBNG_MSG_ENUM_H_
+#define _VBNG_MSG_ENUM_H_
+
+#include <vppinfra/byte_order.h>
+
+#define vl_msg_id(n,h) n,
+typedef enum
+{
+#include <vbng/vbng_all_api_h.h>
+  /* We'll want to know how many messages IDs we need... */
+  VL_MSG_FIRST_AVAILABLE,
+} vl_msg_id_t;
+#undef vl_msg_id
+
+#endif /* _VBNG_MSG_ENUM_H_ */
diff --git a/src/vnet.am b/src/vnet.am
index 9e099f3..7c107f0 100644
--- a/src/vnet.am
+++ b/src/vnet.am
@@ -682,31 +682,31 @@ endif
 ########################################
 # DHCP client
 ########################################
-libvnet_la_SOURCES +=				\
- vnet/dhcp/client.c				\
- vnet/dhcp/client.h				\
- vnet/dhcp/dhcp_api.c
-
-nobase_include_HEADERS +=			\
- vnet/dhcp/client.h				\
- vnet/dhcp/dhcp.api.h
-
-API_FILES += vnet/dhcp/dhcp.api
+#libvnet_la_SOURCES +=				\
+# vnet/dhcp/client.c				\
+# vnet/dhcp/client.h				\
+# vnet/dhcp/dhcp_api.c
+#
+#nobase_include_HEADERS +=			\
+# vnet/dhcp/client.h				\
+# vnet/dhcp/dhcp.api.h
+#
+#API_FILES += vnet/dhcp/dhcp.api
 
 ########################################
 # DHCP proxy
 ########################################
-libvnet_la_SOURCES +=				\
- vnet/dhcp/dhcp6_proxy_node.c                   \
- vnet/dhcp/dhcp4_proxy_node.c			\
- vnet/dhcp/dhcp_proxy.c
-
-nobase_include_HEADERS +=			\
- vnet/dhcp/dhcp4_packet.h		        \
- vnet/dhcp/dhcp6_packet.h		        \
- vnet/dhcp/dhcp_proxy.h				\
- vnet/dhcp/dhcp6_proxy_error.def                \
- vnet/dhcp/dhcp4_proxy_error.def
+#libvnet_la_SOURCES +=				\
+# vnet/dhcp/dhcp6_proxy_node.c                   \
+# vnet/dhcp/dhcp4_proxy_node.c			\
+# vnet/dhcp/dhcp_proxy.c
+#
+#nobase_include_HEADERS +=			\
+# vnet/dhcp/dhcp4_packet.h		        \
+# vnet/dhcp/dhcp6_packet.h		        \
+# vnet/dhcp/dhcp_proxy.h				\
+# vnet/dhcp/dhcp6_proxy_error.def                \
+# vnet/dhcp/dhcp4_proxy_error.def
 
 ########################################
 # ipv6 segment routing
diff --git a/src/vpp-api/java/Makefile.am b/src/vpp-api/java/Makefile.am
index f18e0c2..cadaa8d 100644
--- a/src/vpp-api/java/Makefile.am
+++ b/src/vpp-api/java/Makefile.am
@@ -149,6 +149,26 @@ jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: $(jvpp_registry_ok) $(jvpp_snat_js
 endif
 
 #
+# VBNG Plugin
+#
+if ENABLE_VBNG_PLUGIN
+noinst_LTLIBRARIES += libjvpp_vbng.la
+libjvpp_vbng_la_SOURCES = jvpp-vbng/jvpp_vbng.c
+libjvpp_vbng_la_CPPFLAGS = -Ijvpp-vbng
+libjvpp_vbng_la_LIBADD = $(JVPP_LIBS)
+libjvpp_vbng_la_DEPENDENCIES = libjvpp_common.la
+
+BUILT_SOURCES += jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h
+JAR_FILES += jvpp-vbng-$(PACKAGE_VERSION).jar
+CLEANDIRS += jvpp-vbng/target
+
+jvpp_vbng_json_files = @top_builddir@/plugins/vbng/vbng.api.json
+
+jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h: $(jvpp_registry_ok) $(jvpp_vbng_json_files)
+	$(call japigen,vbng,JVppVbngImpl)
+endif
+
+#
 # iOAM Trace Plugin
 #
 if ENABLE_IOAM_PLUGIN
diff --git a/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c
new file mode 100644
index 0000000..b722a50
--- /dev/null
+++ b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017 Intel Corp and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+
+#include <vbng/vbng_msg_enum.h>
+#define vl_typedefs             /* define message structures */
+#include <vbng/vbng_all_api_h.h>
+#undef vl_typedefs
+
+#include <vnet/api_errno.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#if VPPJNI_DEBUG == 1
+  #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
+#else
+  #define DEBUG_LOG(...)
+#endif
+
+#include <jvpp-common/jvpp_common.h>
+
+#include "jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h"
+#include "jvpp_vbng.h"
+#include "jvpp-vbng/jvpp_vbng_gen.h"
+
+/*
+ * Class:     io_fd_vpp_jvpp_vbng_JVppVbngImpl
+ * Method:    init0
+ * Signature: (JI)V
+ */
+JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_init0
+  (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) {
+  vbng_main_t * plugin_main = &vbng_main;
+  clib_warning ("Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_init0");
+
+  plugin_main->my_client_index = my_client_index;
+  plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address;
+
+  plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
+  plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
+
+  // verify API has not changed since jar generation
+  #define _(N)             \
+      get_message_id(env, #N);
+      foreach_supported_api_message;
+  #undef _
+
+  #define _(N,n)                                  \
+      vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
+              vl_api_##n##_t_handler,             \
+              vl_noop_handler,                    \
+              vl_noop_handler,                    \
+              vl_noop_handler,                    \
+              sizeof(vl_api_##n##_t), 1);
+      foreach_api_reply_handler;
+  #undef _
+}
+
+JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_close0
+(JNIEnv *env, jclass clazz) {
+  vbng_main_t * plugin_main = &vbng_main;
+
+    // cleanup:
+    (*env)->DeleteGlobalRef(env, plugin_main->callbackClass);
+    (*env)->DeleteGlobalRef(env, plugin_main->callbackObject);
+
+    plugin_main->callbackClass = NULL;
+    plugin_main->callbackObject = NULL;
+}
+
+/* Attach thread to JVM and cache class references when initiating JVPP VES */
+jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+    JNIEnv* env;
+
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
+        return JNI_EVERSION;
+    }
+
+    if (cache_class_references(env) != 0) {
+        clib_warning ("Failed to cache class references\n");
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_8;
+}
+
+/* Clean up cached references when disposing JVPP VES */
+void JNI_OnUnload(JavaVM *vm, void *reserved) {
+    JNIEnv* env;
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
+        return;
+    }
+    delete_class_references(env);
+}
diff --git a/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h
new file mode 100644
index 0000000..62b4cda
--- /dev/null
+++ b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Intel Corp and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __included_jvpp_vbng_h__
+#define __included_jvpp_vbng_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/api_errno.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <jni.h>
+
+/* Global state for JVPP-VES */
+typedef struct {
+    /* Pointer to shared memory queue */
+    unix_shared_memory_queue_t * vl_input_queue;
+
+    /* VPP api client index */
+    u32 my_client_index;
+
+    /* Callback object and class references enabling asynchronous Java calls */
+    jobject callbackObject;
+    jclass callbackClass;
+
+} vbng_main_t;
+
+vbng_main_t vbng_main __attribute__((aligned (64)));
+
+#endif /* __included_jvpp_vbng_h__ */