diff --git a/net/quagga/Makefile b/net/quagga/Makefile
new file mode 100644
index 000000000..378ca5509
--- /dev/null
+++ b/net/quagga/Makefile
@@ -0,0 +1,7 @@
+PLUGIN_NAME= quagga
+PLUGIN_VERSION= 0.0.1
+PLUGIN_COMMENT= Plugin to manage the quagga routing daemon software which offers routing protocols like RIP, IS-IS and OSPF to guide your packets through the sea
+PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
+PLUGIN_DEVEL = yes
+
+.include "../../Mk/plugins.mk"
diff --git a/net/quagga/src/etc/inc/plugins.inc.d/quagga.inc b/net/quagga/src/etc/inc/plugins.inc.d/quagga.inc
new file mode 100644
index 000000000..e5fbfbaa2
--- /dev/null
+++ b/net/quagga/src/etc/inc/plugins.inc.d/quagga.inc
@@ -0,0 +1,48 @@
+ gettext('Quagga is a deamon to add support of various routing protocols.'),
+ 'configd' => array(
+ 'restart' => array('quagga restart'),
+ 'start' => array('quagga start'),
+ 'stop' => array('quagga stop'),
+ ),
+ 'name' => 'quagga',
+ );
+ }
+
+ return $services;
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/GeneralController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/GeneralController.php
new file mode 100644
index 000000000..009e965e4
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/GeneralController.php
@@ -0,0 +1,76 @@
+request->isGet()) {
+ $mdlGeneral = new General();
+ $result['general'] = $mdlGeneral->getNodes();
+ }
+ return $result;
+}
+public function setAction()
+{
+ $result = array("result"=>"failed");
+ if ($this->request->isPost()) {
+ // load model and update with provided data
+ $mdlGeneral = new General();
+ $mdlGeneral->setNodes($this->request->getPost("general"));
+
+ // perform validation
+ $valMsgs = $mdlGeneral->performValidation();
+ foreach ($valMsgs as $field => $msg) {
+ if (!array_key_exists("validations", $result)) {
+ $result["validations"] = array();
+ }
+ $result["validations"]["general.".$msg->getField()] = $msg->getMessage();
+ }
+
+ // serialize model to config and save
+ if ($valMsgs->count() == 0) {
+ $mdlGeneral->serializeToConfig();
+ Config::getInstance()->save();
+ $result["result"] = "saved";
+ }
+ }
+ return $result;
+}
+
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/OspfsettingsController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/OspfsettingsController.php
new file mode 100644
index 000000000..7701407cf
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/OspfsettingsController.php
@@ -0,0 +1,312 @@
+request->isGet()) {
+ $mdlospf = new OSPF();
+ $result['ospf'] = $mdlospf->getNodes();
+ }
+ return $result;
+ }
+
+ public function setAction()
+ {
+ $result = array("result"=>"failed");
+ if ($this->request->isPost()) {
+ // load model and update with provided data
+ $mdlospf = new OSPF();
+ $mdlospf->setNodes($this->request->getPost("ospf"));
+
+ // perform validation
+ $valMsgs = $mdlospf->performValidation();
+ foreach ($valMsgs as $field => $msg) {
+ if (!array_key_exists("validations", $result)) {
+ $result["validations"] = array();
+ }
+ $result["validations"]["general.".$msg->getField()] = $msg->getMessage();
+ }
+
+ // serialize model to config and save
+ if ($valMsgs->count() == 0) {
+ $mdlospf->serializeToConfig();
+ Config::getInstance()->save();
+ $result["result"] = "saved";
+ }
+ }
+ return $result;
+ }
+
+
+/////////////////////////////////////////////////////////////////////
+ public function searchNetworkAction()
+ {
+ $this->sessionClose();
+ $mdlOSPF = $this->getModel();
+ $grid = new UIModelGrid($mdlOSPF->networks->network);
+ return $grid->fetchBindRequest(
+ $this->request,
+ array("enabled", "ipaddr", "netmask", "area")
+ );
+ }
+ public function searchInterfaceAction()
+ {
+ $this->sessionClose();
+ $mdlOSPF = $this->getModel();
+ $grid = new UIModelGrid($mdlOSPF->interfaces->interface);
+ return $grid->fetchBindRequest(
+ $this->request,
+ array("enabled", "interfacename", "networktype", "authtype", "area")
+ );
+ }
+ public function getNetworkAction($uuid = null)
+ {
+ $mdlOSPF = $this->getModel();
+ if ($uuid != null) {
+ $node = $mdlOSPF->getNodeByReference('networks.network.' . $uuid);
+ if ($node != null) {
+ // return node
+ return array("network" => $node->getNodes());
+ }
+ } else {
+ $node = $mdlOSPF->networks->network->add();
+ return array("network" => $node->getNodes());
+ }
+ return array();
+ }
+ public function getInterfaceAction($uuid = null)
+ {
+ $mdlOSPF = $this->getModel();
+ if ($uuid != null) {
+ $node = $mdlOSPF->getNodeByReference('interfaces.interface.' . $uuid);
+ if ($node != null) {
+ // return node
+ return array("interface" => $node->getNodes());
+ }
+ } else {
+ $node = $mdlOSPF->interfaces->interface->add();
+ return array("interface" => $node->getNodes());
+ }
+ return array();
+ }
+
+ public function addNetworkAction()
+ {
+ $result = array("result" => "failed");
+ if ($this->request->isPost() && $this->request->hasPost("network")) {
+ $result = array("result" => "failed", "validations" => array());
+ $mdlOSPF = $this->getModel();
+ $node = $mdlOSPF->networks->network->Add();
+ $node->setNodes($this->request->getPost("network"));
+ $valMsgs = $mdlOSPF->performValidation();
+
+ foreach ($valMsgs as $field => $msg) {
+ $fieldnm = str_replace($node->__reference, "network", $msg->getField());
+ $result["validations"][$fieldnm] = $msg->getMessage();
+ }
+
+ if (count($result['validations']) == 0) {
+ // save config if validated correctly
+ $mdlOSPF->serializeToConfig();
+ Config::getInstance()->save();
+ $result["result"] = "saved";
+ }
+ }
+ return $result;
+ }
+ public function addInterfaceAction()
+ {
+ $result = array("result" => "failed");
+ if ($this->request->isPost() && $this->request->hasPost("interface")) {
+ $result = array("result" => "failed", "validations" => array());
+ $mdlOSPF = $this->getModel();
+ $node = $mdlOSPF->interfaces->interface->Add();
+ $node->setNodes($this->request->getPost("interface"));
+ $valMsgs = $mdlOSPF->performValidation();
+
+ foreach ($valMsgs as $field => $msg) {
+ $fieldnm = str_replace($node->__reference, "interface", $msg->getField());
+ $result["validations"][$fieldnm] = $msg->getMessage();
+ }
+
+ if (count($result['validations']) == 0) {
+ // save config if validated correctly
+ $mdlOSPF->serializeToConfig();
+ Config::getInstance()->save();
+ $result["result"] = "saved";
+ }
+ }
+ return $result;
+ }
+ public function delNetworkAction($uuid)
+ {
+
+ $result = array("result" => "failed");
+
+ if ($this->request->isPost()) {
+ $mdlOSPF = $this->getModel();
+ if ($uuid != null) {
+ if ($mdlOSPF->networks->network->del($uuid)) {
+ $mdlOSPF->serializeToConfig();
+ Config::getInstance()->save();
+ $result['result'] = 'deleted';
+ } else {
+ $result['result'] = 'not found';
+ }
+ }
+ }
+ return $result;
+ }
+ public function delInterfaceAction($uuid)
+ {
+
+ $result = array("result" => "failed");
+
+ if ($this->request->isPost()) {
+ $mdlOSPF = $this->getModel();
+ if ($uuid != null) {
+ if ($mdlOSPF->interfaces->interface->del($uuid)) {
+ $mdlOSPF->serializeToConfig();
+ Config::getInstance()->save();
+ $result['result'] = 'deleted';
+ } else {
+ $result['result'] = 'not found';
+ }
+ }
+ }
+ return $result;
+ }
+ public function setNetworkAction($uuid)
+ {
+ if ($this->request->isPost() && $this->request->hasPost("network")) {
+ $mdlNetwork = $this->getModel();
+ if ($uuid != null) {
+ $node = $mdlNetwork->getNodeByReference('networks.network.' . $uuid);
+ if ($node != null) {
+ $result = array("result" => "failed", "validations" => array());
+ $networkInfo = $this->request->getPost("network");
+
+ $node->setNodes($networkInfo);
+ $valMsgs = $mdlNetwork->performValidation();
+ foreach ($valMsgs as $field => $msg) {
+ $fieldnm = str_replace($node->__reference, "network", $msg->getField());
+ $result["validations"][$fieldnm] = $msg->getMessage();
+ }
+
+ if (count($result['validations']) == 0) {
+ // save config if validated correctly
+ $mdlNetwork->serializeToConfig();
+ Config::getInstance()->save();
+ $result = array("result" => "saved");
+ }
+ return $result;
+ }
+ }
+ }
+ return array("result" => "failed");
+ }
+ public function setInterfaceAction($uuid)
+ {
+ if ($this->request->isPost() && $this->request->hasPost("interface")) {
+ $mdlNetwork = $this->getModel();
+ if ($uuid != null) {
+ $node = $mdlNetwork->getNodeByReference('interfaces.interface.' . $uuid);
+ if ($node != null) {
+ $result = array("result" => "failed", "validations" => array());
+ $interfaceInfo = $this->request->getPost("interface");
+
+ $node->setNodes($interfaceInfo);
+ $valMsgs = $mdlNetwork->performValidation();
+ foreach ($valMsgs as $field => $msg) {
+ $fieldnm = str_replace($node->__reference, "interface", $msg->getField());
+ $result["validations"][$fieldnm] = $msg->getMessage();
+ }
+
+ if (count($result['validations']) == 0) {
+ // save config if validated correctly
+ $mdlNetwork->serializeToConfig();
+ Config::getInstance()->save();
+ $result = array("result" => "saved");
+ }
+ return $result;
+ }
+ }
+ }
+ return array("result" => "failed");
+ }
+ public function toggle_handler($uuid, $elements, $element)
+ {
+
+ $result = array("result" => "failed");
+
+ if ($this->request->isPost()) {
+ $mdlNetwork = $this->getModel();
+ if ($uuid != null) {
+ $node = $mdlNetwork->getNodeByReference($elements . '.'. $element .'.' . $uuid);
+ if ($node != null) {
+ if ($node->enabled->__toString() == "1") {
+ $result['result'] = "Disabled";
+ $node->enabled = "0";
+ } else {
+ $result['result'] = "Enabled";
+ $node->enabled = "1";
+ }
+ // if item has toggled, serialize to config and save
+ $mdlNetwork->serializeToConfig();
+ Config::getInstance()->save();
+ }
+ }
+ }
+ return $result;
+ }
+
+ public function toggleNetworkAction($uuid)
+ {
+ return $this->toggle_handler($uuid, 'networks', 'network');
+ }
+ public function toggleInterfaceAction($uuid)
+ {
+ return $this->toggle_handler($uuid, 'interfaces', 'interface');
+ }
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/ServiceController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/ServiceController.php
new file mode 100644
index 000000000..22a50b322
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/ServiceController.php
@@ -0,0 +1,154 @@
+request->isPost()) {
+ $backend = new Backend();
+ $response = $backend->configdRun("quagga start", true);
+ return array("response" => $response);
+ } else {
+ return array("response" => array());
+ }
+ }
+
+ /**
+ * stop quagga service
+ * @return array
+ */
+ public function stopAction()
+ {
+ if ($this->request->isPost()) {
+ $backend = new Backend();
+ $response = $backend->configdRun("quagga stop");
+ return array("response" => $response);
+ } else {
+ return array("response" => array());
+ }
+ }
+
+ /**
+ * restart quagga service
+ * @return array
+ */
+ public function restartAction()
+ {
+ if ($this->request->isPost()) {
+ $backend = new Backend();
+ $response = $backend->configdRun("quagga restart");
+ return array("response" => $response);
+ } else {
+ return array("response" => array());
+ }
+ }
+
+ /**
+ * retrieve status of quagga
+ * @return array
+ * @throws \Exception
+ */
+ public function statusAction()
+ {
+ $backend = new Backend();
+ $mdlGeneral = new General();
+ $response = $backend->configdRun("quagga status");
+
+ if (strpos($response, "not running") > 0) {
+ if ($mdlGeneral->enabled->__toString() == 1) {
+ $status = "stopped";
+ } else {
+ $status = "disabled";
+ }
+ } elseif (strpos($response, "is running") > 0) {
+ $status = "running";
+ } elseif ($mdlGeneral->enabled->__toString() == 0) {
+ $status = "disabled";
+ } else {
+ $status = "unkown";
+ }
+
+
+ return array("status" => $status);
+ }
+
+ /**
+ * reconfigure quagga, generate config and reload
+ */
+ public function reconfigureAction()
+ {
+ if ($this->request->isPost()) {
+ $force_restart = false;
+ // close session for long running action
+ $this->sessionClose();
+
+ $mdlGeneral = new General();
+ $backend = new Backend();
+
+ $runStatus = $this->statusAction();
+
+ // stop squid when disabled
+ if ($runStatus['status'] == "running" &&
+ ($mdlGeneral->enabled->__toString() == 0)) {
+ $this->stopAction();
+ }
+
+ // generate template
+ $backend->configdRun('template reload OPNsense/Quagga');
+
+ // (res)start daemon
+ if ($mdlGeneral->enabled->__toString() == 1) {
+ if ($runStatus['status'] == "running" && !$force_restart) {
+ $this->restartAction();
+ } else {
+ $this->startAction();
+ }
+ }
+
+ return array("status" => "ok");
+ } else {
+ return array("status" => "failed");
+ }
+ }
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/BgpController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/BgpController.php
new file mode 100644
index 000000000..b42e4d027
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/BgpController.php
@@ -0,0 +1,11 @@
+view->title = gettext("BGP-Settings");
+ $this->view->generalForm = $this->getForm("bgp");
+ $this->view->pick('OPNsense/Quagga/bgp');
+ }
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/GeneralController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/GeneralController.php
new file mode 100644
index 000000000..43d087f3b
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/GeneralController.php
@@ -0,0 +1,38 @@
+view->title = gettext("Routing-Settings");
+ $this->view->generalForm = $this->getForm("general");
+ $this->view->pick('OPNsense/Quagga/general');
+ }
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/IsisController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/IsisController.php
new file mode 100644
index 000000000..b0db33cb9
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/IsisController.php
@@ -0,0 +1,11 @@
+view->title = gettext("IS-IS-Settings");
+ $this->view->generalForm = $this->getForm("isis");
+ $this->view->pick('OPNsense/Quagga/isis');
+ }
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/OspfController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/OspfController.php
new file mode 100644
index 000000000..43c74a9e7
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/OspfController.php
@@ -0,0 +1,40 @@
+view->title = gettext("OSPF Settings");
+ $this->view->generalForm = $this->getForm("ospf");
+ $this->view->formDialogEditNetwork = $this->getForm("dialogEditOSPFNetwork");
+ $this->view->formDialogEditInterface = $this->getForm("dialogEditOSPFInterface");
+ $this->view->pick('OPNsense/Quagga/ospf');
+ }
+}
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/RipController.php b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/RipController.php
new file mode 100644
index 000000000..191158e16
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/RipController.php
@@ -0,0 +1,12 @@
+view->title = gettext("RIP-Settings");
+ $this->view->generalForm = $this->getForm("rip");
+ $this->view->pick('OPNsense/Quagga/rip');
+ }
+}
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/bgp.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/bgp.xml
new file mode 100644
index 000000000..61ec5daef
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/bgp.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPFInterface.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPFInterface.xml
new file mode 100644
index 000000000..379fd7af3
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPFInterface.xml
@@ -0,0 +1,64 @@
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPFNetwork.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPFNetwork.xml
new file mode 100644
index 000000000..a7a81c9d8
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPFNetwork.xml
@@ -0,0 +1,22 @@
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/general.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/general.xml
new file mode 100644
index 000000000..fac27a39c
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/general.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/isis.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/isis.xml
new file mode 100644
index 000000000..a6657f78c
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/isis.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf.xml
new file mode 100644
index 000000000..2fd5f09b5
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf.xml
@@ -0,0 +1,38 @@
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/rip.xml b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/rip.xml
new file mode 100644
index 000000000..ca4256275
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/rip.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/ACL/ACL.xml b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/ACL/ACL.xml
new file mode 100644
index 000000000..3fa7a13e5
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/ACL/ACL.xml
@@ -0,0 +1,9 @@
+
+
+ Routing
+
+ ui/quagga/*
+ api/quagga/*
+
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/General.php b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/General.php
new file mode 100644
index 000000000..e92b4188c
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/General.php
@@ -0,0 +1,33 @@
+
+ //OPNsense/quagga/general
+ OSPF Routing configuration
+
+
+ 0
+ Y
+
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/Menu/Menu.xml b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/Menu/Menu.xml
new file mode 100644
index 000000000..113917841
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/Menu/Menu.xml
@@ -0,0 +1,10 @@
+
diff --git a/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF.php b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF.php
new file mode 100644
index 000000000..54299fbc4
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF.php
@@ -0,0 +1,33 @@
+
+ //OPNsense/quagga/ospf
+ OSPF Routing configuration
+
+
+ 0
+ Y
+
+
+ 0
+ Y
+
+
+ 0
+ Y
+
+
+
+ N
+ Y
+
+
+ /^(?!0).*$/
+
+
+
+ N
+ Y
+
+
+ Babel routing protocol (Babel)
+ Border Gateway Protocol (BGP)
+ Connected routes (directly attached subnet or host)
+ Intermediate System to Intermediate System (IS-IS)
+ Kernel routes (not installed via the zebra RIB)
+ Protocol Independent Multicast (PIM)
+ Routing Information Protocol (RIP)
+ Statically configured routes
+
+
+
+
+
+ 1
+ Y
+
+
+
+ Y
+ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
+
+
+
+ Y
+ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
+
+
+ 24
+ 0
+ Y
+ 32
+ Network mask must be between 0 and 32.
+
+
+
+
+
+
+ 1
+ Y
+
+
+ N
+ N
+
+
+ /^(?!0).*$/
+
+
+
+ N
+ N
+
+
+ MD5
+
+
+
+
+ N
+ /^\S+$/
+
+
+
+ N
+ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3},)*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/
+
+
+
+ 0
+ N
+ 4294967295
+ Cost must be between 0 and 4294967295.
+
+
+
+ 0
+ N
+ 4294967295
+ Hello interval must be between 0 and 4294967295.
+
+
+
+ 0
+ N
+ 4294967295
+ Dead interval must be between 0 and 4294967295.
+
+
+
+ 0
+ N
+ 4294967295
+ Retransmit interval must be between 0 and 4294967295.
+
+
+
+ 0
+ N
+ 4294967295
+ Transmit delay must be between 0 and 4294967295.
+
+
+
+ 0
+ N
+ 4294967295
+ Priority must be between 0 and 4294967295.
+
+
+ N
+ N
+
+
+ Broadcast multi-access network
+ NBMA network
+ Point-to-multipoint network
+ Point-to-point network
+
+
+
+
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/bgp.volt b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/bgp.volt
new file mode 100644
index 000000000..4ca174841
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/bgp.volt
@@ -0,0 +1 @@
+{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
diff --git a/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/general.volt b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/general.volt
new file mode 100644
index 000000000..731ed2daa
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/general.volt
@@ -0,0 +1,56 @@
+{#
+
+OPNsense® is Copyright © 2014 – 2017 by Deciso B.V.
+This file is Copyright © 2017 by Fabian Franz
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+#}{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}}
+
+
+
+
+
+
diff --git a/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/isis.volt b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/isis.volt
new file mode 100644
index 000000000..4ca174841
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/isis.volt
@@ -0,0 +1 @@
+{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
diff --git a/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/ospf.volt b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/ospf.volt
new file mode 100644
index 000000000..522fe76ae
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/ospf.volt
@@ -0,0 +1,144 @@
+{#
+
+OPNsense® is Copyright © 2014 – 2017 by Deciso B.V.
+This file is Copyright © 2017 by Fabian Franz
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+#}{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
+
+
+
+
+
+
+
+{{ lang._('Networks') }}
+
+
+
+
+
+
+ | {{ lang._('Enabled') }} |
+ {{ lang._('Network Address') }} |
+ {{ lang._('Mask') }} |
+ {{ lang._('Area') }} |
+ {{ lang._('ID') }} |
+ {{ lang._('Commands') }} |
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+{{ lang._('Interfaces') }}
+
+
+
+
+
+
+ | {{ lang._('Enabled') }} |
+ {{ lang._('Interface Name') }} |
+ {{ lang._('Network Type') }} |
+ {{ lang._('Authentication Type') }} |
+ {{ lang._('Area') }} |
+ {{ lang._('ID') }} |
+ {{ lang._('Commands') }} |
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+{{ partial("layout_partials/base_dialog",['fields':formDialogEditNetwork,'id':'DialogEditNetwork','label':'Edit Network'])}}
+{{ partial("layout_partials/base_dialog",['fields':formDialogEditInterface,'id':'DialogEditInterface','label':'Edit Interface'])}}
diff --git a/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/rip.volt b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/rip.volt
new file mode 100644
index 000000000..4ca174841
--- /dev/null
+++ b/net/quagga/src/opnsense/mvc/app/views/OPNsense/Quagga/rip.volt
@@ -0,0 +1 @@
+{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
diff --git a/net/quagga/src/opnsense/service/conf/actions.d/actions_quagga.conf b/net/quagga/src/opnsense/service/conf/actions.d/actions_quagga.conf
new file mode 100644
index 000000000..9beb56257
--- /dev/null
+++ b/net/quagga/src/opnsense/service/conf/actions.d/actions_quagga.conf
@@ -0,0 +1,30 @@
+[start]
+command:/usr/local/etc/rc.d/quagga start
+parameters:
+type:script
+message:starting proxy
+
+[stop]
+command:/usr/local/etc/rc.d/quagga; exit 0
+parameters:
+type:script
+message:stopping proxy
+
+[restart]
+command:/usr/local/etc/rc.d/quagga restart
+parameters:
+type:script
+message:restarting proxy
+
+[reconfigure]
+command:/usr/local/etc/rc.d/quagga reload
+parameters:
+type:script
+message:reconfigure proxy
+
+[status]
+command:/usr/local/etc/rc.d/quagga status;exit 0
+parameters:
+type:script_output
+message:request proxy status
+
diff --git a/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS b/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS
new file mode 100644
index 000000000..49745db1b
--- /dev/null
+++ b/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS
@@ -0,0 +1,2 @@
+ospfd.conf:/usr/local/etc/quagga/ospfd.conf
+quagga:/etc/rc.conf.d/quagga
diff --git a/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/ospfd.conf b/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/ospfd.conf
new file mode 100644
index 000000000..f4e325fb3
--- /dev/null
+++ b/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/ospfd.conf
@@ -0,0 +1,49 @@
+{% macro cline(directive, modelname) -%}{% if modelname %}
+ ip ospf {{ directive }} {{ modelname }}
+{% endif %}{%- endmacro %}
+!
+! Zebra configuration saved from vty
+! 2017/03/03 20:21:04
+!
+!
+!
+!
+{% if helpers.exists('OPNsense.quagga.ospf.interfaces.interface') %}
+{% for interface in helpers.toList('OPNsense.quagga.ospf.interfaces.interface') %}
+{% if interface.enabled == '1' %}
+interface {{ interface.interfacename }}
+{{ cline("authentication",interface.authtype)
+}}{{ cline("authentication-key",interface.authkey)
+}}{{ cline("cost",interface.cost)
+}}{{ cline("dead-interval",interface.deadinterval)
+}}{{ cline("hello-interval",interface.hellointerval)
+}}{{ cline("priority",interface.priority)
+}}{{ cline("retransmit-interval",interface.retransmitinterval)
+}}!
+{% endif %}
+{% endfor %}
+{% endif %}
+!
+router ospf
+{% if helpers.exists('OPNsense.quagga.ospf.redistribute') and OPNsense.quagga.ospf.redistribute != '' %}
+{% for line in OPNsense.quagga.ospf.redistribute.split(',') %}
+ redistribute {{ line }}
+{% endfor %}{% endif %}
+{% if helpers.exists('OPNsense.quagga.ospf.passiveinterfaces') and OPNsense.quagga.ospf.passiveinterfaces != '' %}
+{% for line in OPNsense.quagga.ospf.passiveinterfaces.split(',') %}
+ passive-interface {{ line }}
+{% endfor %}{% endif %}
+{% if helpers.exists('OPNsense.quagga.ospf.networks.network') %}
+{% for network in helpers.toList('OPNsense.quagga.ospf.networks.network') %}
+{% if network.enabled == '1' %}
+ network {{ network.ipaddr }}/{{ network.netmask }} area {{ network.area }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if helpers.exists('OPNsense.quagga.ospf.originate') and OPNsense.quagga.ospf.originate == '1' %}
+ default-information originate{% if helpers.exists('OPNsense.quagga.ospf.originatealways') and OPNsense.quagga.ospf.originatealways == '1' %} always {% endif %}
+
+{% endif %}
+!
+line vty
+!
diff --git a/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/quagga b/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/quagga
new file mode 100644
index 000000000..58ce70cf3
--- /dev/null
+++ b/net/quagga/src/opnsense/service/templates/OPNsense/Quagga/quagga
@@ -0,0 +1,14 @@
+defaultrouter="NO"
+quagga_enable="{% if helpers.exists('OPNsense.quagga.general.enabled') and OPNsense.quagga.general.enabled == '1' %}YES{% else %}NO{% endif %}"
+
+quagga_daemons="zebra{%
+if helpers.exists('OPNsense.quagga.ospf.enabled') and OPNsense.quagga.ospf.enabled == '1' %} ospfd{% endif %}{%
+if helpers.exists('OPNsense.quagga.rip.enabled') and OPNsense.quagga.ripd.enabled == '1' %} ripd{% endif %}{%
+if helpers.exists('OPNsense.quagga.bgp.enabled') and OPNsense.quagga.bgp.enabled == '1' %} bgpd{% endif %}{%
+if helpers.exists('OPNsense.quagga.ospf6.enabled') and OPNsense.quagga.ospf6.enabled == '1' %} ospf6d{% endif %}{%
+if helpers.exists('OPNsense.quagga.ripng.enabled') and OPNsense.quagga.ripng.enabled == '1' %} ripngd{% endif %}{%
+if helpers.exists('OPNsense.quagga.isis.enabled') and OPNsense.quagga.isis.enabled == '1' %} isisd{% endif %}"
+#quagga_flags="...."
+#quagga_extralibs_path="... ..."
+#router_enable="NO"
+watchquagga_enable="YES"