diff --git a/Makefile b/Makefile index 1c35028..542b099 100755 --- a/Makefile +++ b/Makefile @@ -7,8 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for easymesh LUCI_DEPENDS:= +kmod-cfg80211 +batctl-default +kmod-batman-adv +dawn +bash -PKG_VERSION:=2.8.5 -PKG_RELEASE:=0 +PKG_VERSION:=2.8.8 include $(TOPDIR)/feeds/luci/luci.mk diff --git a/luasrc/model/cbi/easymesh.lua b/luasrc/model/cbi/easymesh.lua index 3dc4f06..57a7153 100755 --- a/luasrc/model/cbi/easymesh.lua +++ b/luasrc/model/cbi/easymesh.lua @@ -13,34 +13,28 @@ m = Map("easymesh", function detect_Node() - local data = {} - local lps = luci.util.execi(" batctl n 2>/dev/null | tail +2 | sed 's/^[ ][ ]*//g' | sed 's/[ ][ ]*/ /g' | sed 's/$/ /g' ") - for value in lps do - local row = {} - local pos = string.find(value, " ") - local IFA = string.sub(value, 1, pos - 1) - local value = string.sub(value, pos + 1, string.len(value)) - pos = string.find(value, " ") - local pos = string.find(value, " ") - local Neighbora = string.sub(value, 1, pos - 1) - local value = string.sub(value, pos + 1, string.len(value)) - pos = string.find(value, " ") - local pos = string.find(value, " ") - local lastseena = string.sub(value, 1, pos - 1) - local value = string.sub(value, pos + 1, string.len(value)) - pos = string.find(value, " ") - row["IF"] = IFA - row["Neighbor"] = Neighbora - row["lastseen"] = lastseena - table.insert(data, row) - end - return data + local data = {} + -- Streamline the command to retrieve node information + local lps = luci.util.execi("batctl n 2>/dev/null | tail +2 | sed 's/^[ ]*//;s/[ ]*/ /g'") + + for line in lps do + -- Split the line into parts using pattern matching + local ifa, neighbor, lastseen = string.match(line, "(%S+) (%S+) (%S+)") + + if ifa and neighbor and lastseen then + -- Construct the row and add it to the data table + local row = {["IF"] = ifa, ["Neighbor"] = neighbor, ["lastseen"] = lastseen} + table.insert(data, row) + end + end + return data end - function get_verbose_hw_info(iface) + +function get_verbose_hw_info(iface) local type = iwinfo.type(iface) if not type then - return "Unknown interface" + return "Generic" end local driver = iwinfo[type] @@ -48,46 +42,41 @@ end return "Driver not supported" end - -- Get the hardware name (e.g., "Generic MAC80211") local hw_name = driver.hardware_name and driver.hardware_name(iface) if not hw_name or hw_name == "" then hw_name = "Unknown hardware" end - - -- Get the list of supported modes (e.g., "802.11bgnac") - local hw_modes_tbl = driver.hwmodelist and driver.hwmodelist(iface) - local hw_modes_str = "" - if hw_modes_tbl then - local hw_modes = {} - for mode, _ in pairs(hw_modes_tbl) do - table.insert(hw_modes, mode) + + local hw_modes = driver.hwmodelist and driver.hwmodelist(iface) + local supported_modes = {} + if hw_modes then + for mode, supported in pairs(hw_modes) do + if supported then + table.insert(supported_modes, mode) + end end - hw_modes_str = table.concat(hw_modes, "/") - else - hw_modes_str = "No mode information" end - -- Combine the hardware name with the supported modes - local verbose_info = hw_name .. hw_modes_str + if #supported_modes == 0 then + supported_modes_str = "No mode information" + else + supported_modes_str = table.concat(supported_modes, "/") + end + local verbose_info = hw_name .. " (" .. supported_modes_str .. ")" return verbose_info end local Nodes = luci.sys.exec("batctl n 2>/dev/null| tail +3 | wc -l") local Node = detect_Node() -v = m:section(Table, Node, "" ,"" .. translate("Active node") .. "" .. Nodes .. "") -v:option(DummyValue, "IF", translate("IF")) -v:option(DummyValue, "Neighbor", translate("Neighbor")) -v:option(DummyValue, "lastseen", translate("lastseen")) +v = m:section(Table, Node, translate("Active Nodes") ,"" .. translate("Number of Active Nodes: ") .. Nodes .. "") +v:option(DummyValue, "IF", translate("Interface")) +v:option(DummyValue, "Neighbor", translate("Neighbor Nodes")) +v:option(DummyValue, "lastseen", translate("Last Seen Timestamp")) -- Basic -s = m:section(TypedSection, "easymesh", translate("Mesh Gateway & Node WiFi Settings"), translate("Choose Mesh Gateway or Mesh Node WiFi Settings: Begin by completing this section on your mesh server and nodes. Ensure each radio's WiFi network name is consistent. For example: easymesh_AC, easymesh_N.")) +s = m:section(TypedSection, "easymesh", translate("Mesh Settings")) s.anonymous = true ----- Eanble -o = s:option(Flag, "enabled", translate("Enable"), translate("Enable or disable Easy Mesh")) -o.default = 0 -o.rmempty = false - -- Connection Type Dropdown --o = s:option(ListValue, "backbone", translate("Connection Type"), translate("Choose if Node or Gateway is connected to internet by LAN or WiFi")) --o:value("lan", translate("LAN")) @@ -109,16 +98,22 @@ o.rmempty = false --app.rmempty = true s:tab("setup", translate("Basic Setup")) +s:tab("apmode", translate("AP Mode")) s:tab("advanced", translate("Advanced Settings")) +---- Eanble +o = s:taboption("setup", Flag, "enabled", translate("Enable Mesh Network"), translate("Toggle this switch to activate or deactivate the Mesh Network on this device according to the settings specified in this configuration. Make sure to configure all necessary settings before enabling the Mesh Network. Changes will apply when you click Save and Apply")) +o.default = 0 + + -- Move basic settings under the "Setup" tab -o = s:taboption("setup", ListValue, "role", translate("Mesh Mode")) -o:value("off", translate("Node")) +o = s:taboption("setup", ListValue, "role", translate("Mesh Mode"), translate('

Choose the role this device will play in your mesh network. There are two options available:

1. Server: If you select this option, this device will act as the Mesh Gateway Server. The server manages the routing of data in the network and handles connections to the internet. It is the central point of your mesh network.

2. Node: The device functions as a Mesh Node if this option is selected. Nodes connect to the Mesh Gateway Server and other nodes to extend the range of the network. Nodes can also route traffic between each other to increase network efficiency.

Remember to set up the Mesh Gateway Server first before setting up the nodes.

')) o:value("server", translate("Server")) -o:value("client", translate("Client (advanced)")) -o.rmempty = false +o:value("off", translate("Node")) +o.default = "server" +--o:value("client", translate("Client (advanced)")) -apRadio = s:taboption("setup", ListValue, "apRadio", translate("Mesh Radio")) +apRadio = s:taboption("setup", MultiValue, "apRadio", translate("Mesh Radio(s)"), translate('

Select one or multiple radio interfaces to be used for the mesh network. Each selected radio interface will be configured to participate in the mesh network, extending its range and improving its resilience. By using multiple radios, your mesh network can balance the network load and handle a larger number of connected devices.

')) uci:foreach("wireless", "wifi-device", function(s) @@ -127,40 +122,37 @@ uci:foreach("wireless", "wifi-device", local desc = string.format("%s (%s)", iface, hw_modes) apRadio:value(iface, desc) -- Display radio interface with its hardware modes end) -apRadio:value("all", translate("ALL")) apRadio.default = "radio0" -apRadio.rmempty = false +apRadio.widget = "select" o = s:taboption("setup", Value, "mesh_id", translate("Mesh SSID")) o.default = "easymesh_AC" -enable = s:taboption("setup", Flag, "encryption", translate("Encryption WIP DROPDOWN"), translate("")) -enable.default = 0 -enable.rmempty = false +encryption = s:taboption("setup", Flag, "encryption", translate("Enable Password"), translate("")) +encryption.default = 0 -o = s:taboption("setup", Value, "key", translate("Key")) +o = s:taboption("setup", Value, "key", translate("Mesh Password")) o.default = "easymesh" o:depends("encryption", 1) +o.password = true --- Move K/V/R settings to the "Advanced" tab enable_kvr = s:taboption("advanced", Flag, "kvr", translate("K/V/R"), translate("Enable Key Value Roaming")) enable_kvr.default = 1 -enable_kvr.rmempty = false mobility_domain = s:taboption("advanced", Value, "mobility_domain", translate("Mobility Domain"), translate("4-character hexadecimal ID")) mobility_domain.default = "4f57" -mobility_domain.datatype = "and(hexstring,rangelength(4,4))" -mobility_domain:depends("kvr", 1) +--mobility_domain.datatype = "and(hexstring,rangelength(4,4))" + rssi_val = s:taboption("advanced", Value, "rssi_val", translate("Threshold for a good RSSI")) rssi_val.default = "-60" -rssi_val.datatype = "range(-1,-120)" -rssi_val:depends("kvr", 1) +--rssi_val.datatype = "range(-1,-120)" + low_rssi_val = s:taboption("advanced", Value, "low_rssi_val", translate("Threshold for a bad RSSI")) low_rssi_val.default = "-88" -low_rssi_val.datatype = "range(-1,-120)" -low_rssi_val:depends("kvr", 1) +--low_rssi_val.datatype = "range(-1,-120)" + ---- Apply MESH settings @@ -179,31 +171,11 @@ low_rssi_val:depends("kvr", 1) --enable.rmempty = false -- NodeMode -s = m:section(TypedSection, "easymesh", translate("Enable Router as DHCP Mesh Node"), translate("Set up Easy Mesh WiFi on your server and nodes first. All mesh nodes will utilize your mesh server for DHCP. ")) -s.anonymous = true +-- s = m:section(TypedSection, "easymesh", translate("Enable Router as DHCP Mesh Node"), translate("Set up Easy Mesh WiFi on your server and nodes first. All mesh nodes will utilize your mesh server for DHCP. ")) +-- s.anonymous = true ---- ap_mode -enable = s:option(Flag, "ap_mode", translate("Enable as DHCP Mesh Node"), translate("Important: Setup your mesh WiFi network before enabling.")) -enable.default = 0 -enable.rmempty = false - ----- ip address ---o = s:option(Value, "ipaddr", translate("Static IP Address")) ---o.default = "192.168.8.2" ---o.datatype = "ip4addr" ---o:depends("ap_mode", 1) - -o = s:option(Value, "dns", translate("Mesh Gateway IP Address")) -o.default = "192.168.8.1" -o.datatype = "ip4addr" -o:depends("ap_mode", 1) - -o = s:option(Value, "netmask", translate("IPv4 netmask")) -o.default = "255.255.255.0" -o.datatype = "ip4addr" -o:depends("ap_mode", 1) - -o = s:option(Value, "gateway", translate("Set Hostname for this Mesh Node")) +o = s:taboption("apmode", Value, "hostname", translate("Node Hostname")) o.default = "node2" o:value("node2", "node2") o:value("node3", "node3") @@ -214,29 +186,52 @@ o:value("node7", "node7") o:value("node8", "node8") o:value("node9", "node9") o.datatype = "string" -o:depends("ap_mode", 1) +o:depends("role", "off") + +-- IP Mode (DHCP or Static) +ipmode = s:taboption("apmode", ListValue, "ipmode", translate("IP Mode"), translate("Choose if the node uses DHCP or a Static IP")) +ipmode:value("dhcp", translate("DHCP")) +ipmode:value("static", translate("Static")) +ipmode.default = "dhcp" +ipmode:depends("role", "off") + +-- Static IP address +o = s:taboption("apmode", Value, "ipaddr", translate("Static IP Address")) +o.default = "192.168.70.254" +o.datatype = "ip4addr" +o:depends({ipmode="static",role="off"}) --- MESH Node Control: apply mesh settings -ctrl = m:section(TypedSection, "easymesh", "Click Save Then Enable or Disable Your Mesh WiFi settings") -ctrl.anonymous = true -ctrl.addremove = false +-- DNS (Mesh Gateway IP Address) +o = s:taboption("apmode", Value, "gateway", translate("Mesh Gateway IP Address")) +o.default = "192.168.70.1" +o.datatype = "ip4addr" +o:depends({ipmode="static",role="off"}) +-- IPv4 netmask +o = s:taboption("apmode", Value, "netmask", translate("IPv4 netmask")) +o.default = "255.255.255.0" +o.datatype = "ip4addr" +o:depends({ipmode="static",role="off"}) -btnStart = ctrl:option(Button, "_btn_start", translate("Enable Easy Mesh")) -function btnStart.write() - io.popen("/easymesh/easymesh.sh start") -end +-- IPv4 netmask +o = s:taboption("apmode", Value, "dns", translate("DNS Server")) +o.default = "192.168.70.1" +o.datatype = "ip4addr" +o:depends({ipmode="static",role="off"}) -btnStop = ctrl:option(Button, "_btn_stop", translate("Disable Easy Mesh")) -function btnStop.write() - io.popen("/easymesh/easymesh.sh stop") +btnAPMode = s:taboption("apmode", Button, "_btn_apmode", translate("Enable Dumb AP Mode"), translate("WARNING: THIS WILL CHANGE THIS NODE'S IP ADDRESS, YOU WILL LOOSE ACCESS TO THIS UI")) +function btnAPMode.write() + io.popen("/easymesh/easymesh.sh dumbap &") end +btnAPMode:depends("role", "off") -function o.write(self, section, value) - Flag.write(self, section, value) - -- Run init start - -- luci.sys.call("uci commit") - -- luci.sys.call("/etc/init.d/easymesh start &") +m.on_before_apply = function(self) + local enabled = m:formvalue("cbid.easymesh.config.enabled") + if enabled and enabled == "1" then + io.popen("/easymesh/easymesh.sh enable &") + else + io.popen("/easymesh/easymesh.sh disable &") + end end return m \ No newline at end of file diff --git a/root/easymesh/easymesh.sh b/root/easymesh/easymesh.sh old mode 100644 new mode 100755 index ece9d54..3db535d --- a/root/easymesh/easymesh.sh +++ b/root/easymesh/easymesh.sh @@ -1,38 +1,234 @@ #!/bin/bash -clear_old_networks() { - # Get the mesh name from UCI config - MESH_NAME=$(uci -q get easymesh.config.mesh_id) +# Dumb AP Mode Block +set_apmode() { + # Backup our configs + rm /etc/config/*.meshbak + cp /etc/config/wireless /etc/config/wireless.meshbak + cp /etc/config/network /etc/config/network.meshbak + cp /etc/config/dhcp /etc/config/dhcp.meshbak + cp /etc/config/system /etc/config/system.meshbak + cp /etc/config/firewall /etc/config/firewall.meshbak + + uci set easymesh.config.ap_mode_enabled=1 + + # Disabling and stopping services not needed + for service in firewall dnsmasq odhcpd; do + if /etc/init.d/$service enabled; then + echo "Disabling and stopping $service..." + /etc/init.d/$service disable >/dev/null 2>&1 + /etc/init.d/$service stop >/dev/null 2>&1 + else + echo "$service is not enabled, skipping..." + fi + done + + if [ $(uci -q get easymesh.config.ipmode) == "static" ]; then + # Set static IP + uci set network.lan.proto='static' + uci set network.lan.ipaddr=$(uci -q get easymesh.config.ipaddr) + uci set network.lan.netmask=$(uci -q get easymesh.config.netmask) + uci set network.lan.gateway=$(uci -q get easymesh.config.gateway) + uci set network.lan.dns=$(uci -q get easymesh.config.dns) + else + # Set LAN interface to DHCP client + uci del network.lan.ipaddr + uci del network.lan.netmask + uci set network.lan.proto='dhcp' + fi - # Get all the radios and go through them one by one to remove old networks and interfaces with the same mesh name - for CURRENT_RADIO in $(uci -X show wireless | grep wifi-device | awk -F'[.=]' '{print $2}'); do - echo "Clearing old networks for radio: $CURRENT_RADIO" + # Delete wan interfaces + uci del network.wan + uci del network.wan6 - # Use awk to parse the 'uci show wireless' output and find the matching section - matched_section=$(uci show wireless | awk -F. -v radio="$CURRENT_RADIO" -v ssid="$MESH_NAME" ' - $0 ~ /^wireless\.wifinet[0-9]+\.device=/ && $3 ~ radio { device_section=$2 } - $0 ~ /^wireless\.wifinet[0-9]+\.ssid=/ && $3 ~ ssid && device_section == $2 { print $2; exit } - ') + # Set firewall disabled + uci del firewall.lan.network + uci del firewall.wan.network - # Check if a matching section was found - if [ -n "$matched_section" ]; then - echo "The matching wireless interface section is: $matched_section - deleting it" - uci delete wireless.$matched_section - fi + # Just in case, set lan to be ignored by dhcp + uci set dhcp.lan.ignore='1' + uci del dhcp.wan + + # Fix this for proper variable name + HOSTNAME=$(uci -q get easymesh.config.hostname) + # Set netmask and gateway (assuming $netmask and $dns didn't break more stuff) + uci set system.@system[0].hostname=$HOSTNAME - # Find and delete existing mesh network interfaces with the specified MESH_NAME on the current radio - EXISTING_MESH=$(uci show wireless | grep -w "mesh_id='$MESH_NAME'" | grep ".$CURRENT_RADIO." | cut -d'.' -f1-2) - for section in $EXISTING_MESH; do - uci delete $section - echo "The matching wireless interface section is: $section - deleting it" + # Retrieve the list of ports for network.@device[0] + LAN_PORTS=$(uci get network.@device[0].ports) + + # Check if 'wan' is already in the list of ports + if echo "$LAN_PORTS" | grep -q -w 'wan'; then + echo "'wan' is already in the list of ports for lan." + else + echo "'wan' is not in the list. Adding it to lan ports..." + uci add_list network.@device[0].ports='wan' + fi + + # Get the radio to be used for mesh from the config + AP_RADIO=$(uci -q get easymesh.config.apRadio) + + # Our config set mesh_id that we are looking for + MESH_ID=$(uci -q get easymesh.config.mesh_id) + + # Check if MESH_NAME and AP_RADIO are set, if so find set our network + if [ ! -z "$AP_RADIO" ] && [ ! -z "$MESH_ID" ]; then + # Loop through the radios and update the network settings + for radio in $AP_RADIO; do + # Get the number from the radio name + radio_num="${radio#radio}" + echo "Checking wireless networks on radio${radio_num} for ssid '$MESH_ID'" + + # Loop through all the wireless interfaces associated with the current radio + uci show wireless | grep "wireless\.wifinet${radio_num}" | grep '\.ssid=' | while read -r ssid_line; do + # Extract the interface identifier + wifinet=$(echo "$ssid_line" | cut -d'.' -f2) + # Extract the ssid value + interface_ssid=$(echo "$ssid_line" | cut -d'=' -f2 | tr -d "'") + + if [ "$interface_ssid" = "$MESH_ID" ]; then + echo "Found target SSID '$MESH_ID' on wireless wifinet ${wifinet} on radio ${radio}" + + # Get the current network setting for this wifinet + current_network=$(uci get "wireless.${wifinet}.network") + echo "Current network setting for ${wifinet}: ${current_network}" + + # Check if 'private_router_batman' is part of the current network setting + if echo "$current_network" | grep -qv 'private_router_batman'; then + # 'private_router_batman' is not in the network setting, so we add it + new_network="${current_network} private_router_batman" + uci set "wireless.${wifinet}.network=${new_network}" + echo "Added 'private_router_batman' to the network setting for ${wifinet}." + uci commit wireless + else + echo "'private_router_batman' is already in the network setting for ${wifinet}." + fi + else + echo "SSID '$interface_ssid' on wireless wifinet ${wifinet} does not match target SSID '$MESH_ID'. Skipping..." + fi + done done + fi - # Commit changes to wireless - uci commit - done + # Commit changes to make sure the wireless configuration is updated + uci commit + + # Restart wireless + wifi reload + + # Tell openwrt to reload the configs + reload_config + /etc/init.d/network reload } -create_bat0() { +disable_apmode() { + # Config Count Must Match 5 + local CONFIG_COUNT=0 + + # Check our configs exist, then restore them + [ -f /etc/config/wireless.meshbak ] && { + CONFIG_COUNT=$((CONFIG_COUNT+1)) + } + [ -f /etc/config/network.meshbak ] && { + CONFIG_COUNT=$((CONFIG_COUNT+1)) + } + [ -f /etc/config/dhcp.meshbak ] && { + CONFIG_COUNT=$((CONFIG_COUNT+1)) + } + [ -f /etc/config/system.meshbak ] && { + CONFIG_COUNT=$((CONFIG_COUNT+1)) + } + [ -f /etc/config/firewall.meshbak ] && { + CONFIG_COUNT=$((CONFIG_COUNT+1)) + } + + # Check if we have 5 configs to restore + if [ $CONFIG_COUNT -eq 5 ]; then + echo "Restoring configs from backup..." + echo "Existing configs will be moved to /etc/config/*.dumbap for reference." + rm /etc/config/*.dumbap + mv /etc/config/dhcp /etc/config/dhcp.dumbap + mv /etc/config/network /etc/config/network.dumbap + mv /etc/config/wireless /etc/config/wireless.dumbap + mv /etc/config/system /etc/config/system.dumbap + mv /etc/config/firewall /etc/config/firewall.dumbap + mv /etc/config/dhcp.meshbak /etc/config/dhcp + mv /etc/config/network.meshbak /etc/config/network + mv /etc/config/wireless.meshbak /etc/config/wireless + mv /etc/config/system.meshbak /etc/config/system + mv /etc/config/firewall.meshbak /etc/config/firewall + + # Enable and start services not needed + for service in firewall dnsmasq odhcpd; do + if /etc/init.d/$service disabled; then + echo "Enabling and starting $service..." + /etc/init.d/$service enable + /etc/init.d/$service start + else + echo "$service is not disabled, skipping..." + fi + done + + # Reload all the system configs + reload_config + /etc/init.d/network reload + wifi reload + else + echo "Unable to restore configs as none were found." + fi +} + +clear_by_mesh_id() { + # Passed mesh_id to clear, allows us to multipurpose this function + MESH_ID_TO_CLEAR=$1 + + # Get the radio to be used for mesh from the config + AP_RADIO=$(uci -q get easymesh.config.apRadio) + + # Check if MESH_NAME is not empty + if [ -z "$MESH_ID_TO_CLEAR" ]; then + echo "No mesh_id passed to remove from wireless." + return; + fi + + # Get the output from uci show wireless + uci_output=$(uci show wireless) + + # Find the mesh network with the matching mesh_id and delete it + mesh_id=$(echo "$uci_output" | grep -o "wireless\.mesh_radio[0-9]*\.mesh_id='$MESH_ID_TO_CLEAR'") + if [ ! -z "$mesh_id" ]; then + # Extract the number from the interface name + mesh_radio=$(echo "$mesh_id" | grep -o "radio[0-9]*") + # Loop through radios and delete the mesh networks + for radio in $AP_RADIO; do + # Delete the network + uci del wireless.mesh_$radio + echo "Deleted mesh network with mesh_id '$MESH_ID_TO_CLEAR' on $radio" + done + fi + + # Find the wireless network with the matching ssid and delete it + ssid=$(echo "$uci_output" | grep -o "wireless\.wifinet[0-9]*\.ssid='$MESH_ID_TO_CLEAR'") + if [ ! -z "$ssid" ]; then + # Loop through radios and delete the wireless networks + for radio in $AP_RADIO; do + # Get the number from the radio name + radio_num="${radio#radio}" + # Delete the network + uci del wireless.wifinet$radio_num + echo "Deleted wireless network with ssid '$MESH_ID_TO_CLEAR' on radio$radio_num" + done + fi + + # Commit changes to make sure the wireless configuration is updated + uci commit wireless + + # Restart wireless to apply changes + wifi reload + echo "Wireless interfaces reloaded." +} + +create_batman_network() { # Check if bat0 already exists if uci -q get network.bat0 >/dev/null; then echo "bat0 interface already exists." @@ -73,15 +269,28 @@ create_bat0() { echo "Old bat0 interface deleted from lan network." fi - # Add 'bat0' to the list of ports for 'br-lan' - uci add_list network.@device[0].ports='bat0' - echo "bat0 has been added to the lan network." + uci commit network + fi + + # Check if network.private_router_batman already exists + if uci -q get network.private_router_batman >/dev/null; then + echo "network.private_router_batman interface already exists." + else + # Get the LAN bridge name + LAN_NAME=$(uci -q get network.@device[0].name) + + # Setup our Private Router Batman Interface + uci set network.private_router_batman=interface + uci set network.private_router_batman.proto='batadv_hardif' + uci set network.private_router_batman.master='bat0' + uci set network.private_router_batman.device="$LAN_NAME" + uci set network.private_router_batman.mtu='1536' uci commit network fi } -find_radios() { +process_radios() { # Get the radio to be used for mesh from the config AP_RADIO=$(uci -q get easymesh.config.apRadio) @@ -91,28 +300,11 @@ find_radios() { exit 1 fi - # Check to make sure if "all" is passed or a single radio - if [ "$AP_RADIO" == "all" ]; then - # Get the list of wifi devices - WIFI_RADIOS=$(uci -X show wireless | awk -F'[.=]' '/wifi-device/ {print $2}' | tr '\n' ' ') - else - # Set the radio to the one passed in the config - WIFI_RADIOS=$AP_RADIO - fi -} - -process_radios() { - # Check if WIFI_RADIOS contains more than one radio - if [[ $WIFI_RADIOS =~ [[:space:]] ]]; then - # Loop through all the radios and set them up - for radio in $WIFI_RADIOS; do - echo "Multiple Radio Setup, Current Radio: $radio" - setup_mesh_radio $radio - done - else - echo "Calling Single Radio Setup: $WIFI_RADIOS" - setup_mesh_radio $WIFI_RADIOS - fi + # Loop through the selected radios + for CURRENT_RADIO in $AP_RADIO; do + echo "Setting up mesh networks for: $CURRENT_RADIO" + setup_mesh_radio $CURRENT_RADIO + done } # This is called from the process_radios function and is passed the radio to be used for mesh @@ -126,18 +318,12 @@ setup_mesh_radio() { # Commit changes to wireless uci commit wireless - uci set network.nwi_mesh_$CURRENT_RADIO=interface - uci set network.nwi_mesh_$CURRENT_RADIO.proto='batadv_hardif' - uci set network.nwi_mesh_$CURRENT_RADIO.master='bat0' - uci set network.nwi_mesh_$CURRENT_RADIO.device='bat0' - uci set network.nwi_mesh_$CURRENT_RADIO.mtu='1536' - - uci set wireless.mesh_$CURRENT_RADIO=wifi-iface - uci set wireless.mesh_$CURRENT_RADIO.device=$CURRENT_RADIO - uci set wireless.mesh_$CURRENT_RADIO.ifname=mesh_$CURRENT_RADIO - uci set wireless.mesh_$CURRENT_RADIO.network=nwi_mesh_$CURRENT_RADIO + uci set wireless.mesh_$CURRENT_RADIO='wifi-iface' + uci set wireless.mesh_$CURRENT_RADIO.device="$CURRENT_RADIO" + uci set wireless.mesh_$CURRENT_RADIO.ifname="mesh_$CURRENT_RADIO" + uci set wireless.mesh_$CURRENT_RADIO.network='private_router_batman' uci set wireless.mesh_$CURRENT_RADIO.mode='mesh' - uci set wireless.mesh_$CURRENT_RADIO.mesh_id=$MESH_NAME + uci set wireless.mesh_$CURRENT_RADIO.mesh_id="$MESH_NAME" uci set wireless.mesh_$CURRENT_RADIO.mesh_fwding='0' uci set wireless.mesh_$CURRENT_RADIO.mesh_rssi_threshold='0' uci set wireless.mesh_$CURRENT_RADIO.mesh_ttl='1' @@ -163,7 +349,6 @@ setup_mesh_radio() { ENCRYPTION_ENABLED=$(uci -q get easymesh.config.encryption) # Setup the interface for the mesh network - uci set wireless.mesh_$CURRENT_RADIO.disabled='0' uci set wireless.wifinet$RADIO_NUM=wifi-iface uci set wireless.wifinet$RADIO_NUM.device=$CURRENT_RADIO uci set wireless.wifinet$RADIO_NUM.mode='ap' @@ -172,9 +357,16 @@ setup_mesh_radio() { uci set wireless.wifinet$RADIO_NUM.mobility_domain=$MOBILITY_DOMAIN uci set wireless.wifinet$RADIO_NUM.ft_over_ds='0' uci set wireless.wifinet$RADIO_NUM.ft_psk_generate_local='0' - uci set wireless.wifinet$RADIO_NUM.network='lan' uci set wireless.wifinet$RADIO_NUM.disabled=0 + # Check if ap_mode_enabled is enabled, if so add private_router_batman to the network + # otherwise just add lan + if [ "$(uci -q get easymesh.config.ap_mode_enabled)" = 1 ]; then + uci set wireless.wifinet$RADIO_NUM.network='lan' + else + uci set wireless.wifinet$RADIO_NUM.network='lan private_router_batman' + fi + # Get the encryption key from the config NETWORK_KEY=$(uci -q get easymesh.config.key) @@ -213,22 +405,6 @@ setup_mesh_radio() { uci commit wireless fi - # Check if we need to setup iapp - ENABLE_IAPP=$(uci -q get easymesh.config.iapp) - - if [ "$ENABLE_IAPP" = 1 ]; then - # Get the LAN interface name - LAN_NAME=$(uci -q get network.@device[0].name) - # If LAN_NAME is not empty, set the iapp interface - if [ ! -z "$LAN_NAME" ]; then - uci set wireless.wifinet$RADIO_NUM.iapp_interface="$LAN_NAME" - uci commit wireless - fi - else - uci -q delete wireless.wifinet$RADIO_NUM.iapp_interface - uci commit wireless - fi - # If KVR is enabled, setup DAWN if [ "$ENABLE_KVR" = 1 ]; then RSSI=$(uci -q get easymesh.config.rssi_val) @@ -246,207 +422,89 @@ setup_mesh_radio() { } restart_and_reload() { - # Enable all the radios and commit the changes at once - for radio in $(uci -X show wireless | grep wifi-device | awk -F'[.=]' '{print $2}'); do + # Get the radio to be used for mesh from the config + AP_RADIO=$(uci -q get easymesh.config.apRadio) + + # Check if AP_RADIO is empty, if so exit + if [ -z "$AP_RADIO" ]; then + echo "No radio specified in the config, exiting." + exit 1 + fi + + # Enable radios + for radio in $AP_RADIO; do echo "Enabling $radio..." uci set wireless.$radio.disabled=0 done - uci commit - echo "All radios enabled." - # Apply the wireless configuration changes - wifi reload + uci commit wireless + + # Reload wifi to apply changes without restarting all interfaces + wifi up echo "Wireless interfaces reloaded." # Apply network configuration changes - # Note: Only use reload_config if you have made changes to the network config - # and need to apply them. Otherwise, you can skip this step. reload_config echo "Network configuration reloaded." /etc/init.d/network reload - /etc/init.d/network restart } -disable_easymesh() { +disable_batman_interfaces() { # Delete the bat0 interface if [ "$(uci -q get network.bat0)" = "interface" ]; then uci del network.bat0 fi - # Get the current list of ports for the 'br-lan' interface - LAN_PORTS=$(uci -q get network.@device[0].ports) - # Check if 'bat0' is already in the list of ports for 'br-lan' - if echo "$LAN_PORTS" | grep -q 'bat0'; then - uci del_list network.@device[0].ports='bat0' - echo "Old bat0 interface deleted from lan network." + # Delete the private_router_batman network interface + if [ "$(uci -q get network.private_router_batman)" = "interface" ]; then + uci del network.private_router_batman fi - # Get the list of wifi devices - WIFI_RADIOS=$(uci -X show wireless | awk -F'[.=]' '/wifi-device/ {print $2}' | tr '\n' ' ') - - # Loop through all the radios and delete the network interfaces - for CURRENT_RADIO in $WIFI_RADIOS; do - echo "Handling removal of mesh networks for: $CURRENT_RADIO" - if [ "$(uci -q get network.nwi_mesh_$CURRENT_RADIO)" = "interface" ]; then - uci del network.nwi_mesh_$CURRENT_RADIO - uci commit network - fi - done - - uci commit + uci commit network reload_config - echo "Network configuration reloaded." - /etc/init.d/network reload - /etc/init.d/network restart + echo "Network configuration reloaded." } -set_apmode() { - AP_MODE=$(uci -q get easymesh.config.ap_mode) - if [ "$AP_MODE" = 1 ]; then - # Set a flag to indicate that we are in AP mode - # When we go to disable easymesh, we will check this flag and if it was set we restore settings - uci set easymesh.config.ap_mode_enabled=1 - - # Backup our configs - rm /etc/config/*.meshbak - cp /etc/config/wireless /etc/config/wireless.meshbak - cp /etc/config/network /etc/config/network.meshbak - cp /etc/config/dhcp /etc/config/dhcp.meshbak - - # Generate a random IP in the same subnet for fun - # ip_base=$(echo "$dns" | cut -d'.' -f1-3) # Get the first three octets of the DNS IP - # last_octet=$((RANDOM % 254 + 1)) # Generate a random value for the last octet between 1 and 254 - # nodeip="${ip_base}.${last_octet}" # Concatenate the base IP with the new last octet - - # Disabling and stopping services not needed - for service in firewall dnsmasq odhcpd; do - if /etc/init.d/$service enabled; then - echo "Disabling and stopping $service..." - /etc/init.d/$service disable - /etc/init.d/$service stop - else - echo "$service is not enabled, skipping..." - fi - done - - # Set LAN interface to DHCP client - uci del network.lan.ipaddr - uci del network.lan.netmask - uci set network.lan.proto='dhcp' - uci del network.wan - uci del network.wan6 - - # Fix firewall to be disabled - uci del firewall.lan.network - uci del firewall.wan.network - - # Fix dhcp to be disabled - uci set dhcp.lan.ignore='1' - uci del dhcp.wan - - # Fix this for proper variable name - HOSTNAME=$(uci -q get easymesh.config.gateway) - # Set netmask and gateway (assuming $netmask and $dns didn't break more stuff) - uci set system.@system[0].hostname=$HOSTNAME - - # Retrieve the list of ports for network.@device[0] - LAN_PORTS=$(uci get network.@device[0].ports) - - # Check if 'wan' is already in the list of ports - if echo "$LAN_PORTS" | grep -q -w 'wan'; then - echo "'wan' is already in the list of ports for lan." - else - echo "'wan' is not in the list. Adding it to lan ports..." - uci add_list network.@device[0].ports='wan' - fi - - # Find all radios we are using in our setup - find_radios - - #### COME BACK TO THIS #### - # # Check if WIFI_RADIOS contains more than one radio - # if [[ $WIFI_RADIOS =~ [[:space:]] ]]; then - # # Loop through all the radios add nwimesh to the that network - # for cur_radio in $WIFI_RADIOS; do - # echo "Multiple Radio Setup, Current Radio: $radio" - # # Extact the radio number from the radio name - # wifi_num="${cur_radio#radio}" - # uci set wireless.wifinet${wifi_num}.network="lan nwi_mesh_${cur_radio}" - # done - # else - # echo "Calling Single Radio Setup: $WIFI_RADIOS" - # # Extact the radio number from the radio name - # wifi_num="${WIFI_RADIOS#radio}" - # uci set wireless.wifinet${wifi_num}.network="lan nwi_mesh_${WIFI_RADIOS}" - # fi - - uci commit - # Tell openwrt to reload the configs - reload_config - else - # Set a flag to indicate that we are in AP mode - uci set easymesh.config.ap_mode_enabled=0 - - # Restore our configs - [ -f /etc/config/wireless.meshbak ] && { - mv /etc/config/wireless /etc/config/wireless.dumbap - cp /etc/config/wireless.meshbak /etc/config/wireless - } - [ -f /etc/config/network.meshbak ] && { - mv /etc/config/network /etc/config/network.dumbap - cp /etc/config/network.meshbak /etc/config/network - } - [ -f /etc/config/dhcp.meshbak ] && { - mv /etc/config/dhcp /etc/config/dhcp.dumbap - cp /etc/config/dhcp.meshbak /etc/config/dhcp - } - - # Enable and start services not needed - for service in firewall dnsmasq odhcpd; do - if /etc/init.d/$service disabled; then - echo "Enabling and starting $service..." - /etc/init.d/$service enable - /etc/init.d/$service start - else - echo "$service is not disabled, skipping..." - fi - done +# Enable easymesh +enable_easymesh() { + # Clear old radios then set "old values" + clear_by_mesh_id "$(uci -q get easymesh.config.mesh_id)" + clear_by_mesh_id "$(uci -q get easymesh.config.old_mesh_id)" + uci set easymesh.config.old_mesh_id="$(uci -q get easymesh.config.mesh_id)" + create_batman_network + process_radios + restart_and_reload + # Set at end to be sure it worked + uci set easymesh.config.running=1 +} - reload_config - /etc/init.d/network reload - fi +# Disable easymesh +disable_easymesh() { + # Clear old radios then set "old values" + clear_by_mesh_id "$(uci -q get easymesh.config.mesh_id)" + clear_by_mesh_id "$(uci -q get easymesh.config.old_mesh_id)" + uci del easymesh.config.old_mesh_id + disable_batman_interfaces + # Set at end to be sure it worked + uci del easymesh.config.running } -# ENABLED=$(uci -q get easymesh.config.enabled) -# if [ "$ENABLED" = 1 ]; then -# clear_old_networks -# create_bat0 -# find_radios -# process_radios -# restart_and_reload -# else -# clear_old_networks -# disable_easymesh -# fi - -# We accept the parameters: start, stop and apmode -# start: Enables easymesh -# stop: Disables easymesh -# apmode: Sets the device to AP mode -if [ "$1" = "start" ]; then - clear_old_networks - create_bat0 - find_radios - process_radios - restart_and_reload -elif [ "$1" = "stop" ]; then - clear_old_networks +if [ "$1" = "enable" ]; then + enable_easymesh + exit 0 +elif [ "$1" = "disable" ]; then disable_easymesh -# elif [ "$1" = "apmode" ]; then -# set_apmode + exit 0 +elif [ "$1" = "dumbap" ]; then + set_apmode + exit 0 +elif [ "$1" = "undumb" ]; then + disable_apmode + exit 0 else - echo "Invalid parameter passed." + echo "Invalid argument. Please use 'start', 'stop' or 'dumbap'" + exit 1 fi