diff --git a/packages/lime-proto-batadv/files/usr/lib/lua/lime/proto/batadv.lua b/packages/lime-proto-batadv/files/usr/lib/lua/lime/proto/batadv.lua index 4ee156970..1722239a1 100644 --- a/packages/lime-proto-batadv/files/usr/lib/lua/lime/proto/batadv.lua +++ b/packages/lime-proto-batadv/files/usr/lib/lua/lime/proto/batadv.lua @@ -133,8 +133,25 @@ function batadv.runOnDevice(linuxDev, args) --! TODO: as of today ubus silently fails to properly setting up a linux network --! device for batman ADV usage dinamycally work around it by using --! shell commands instead - network.createStatic(devName) - utils.unsafe_shell("batctl if add "..devName) + local id = utils.get_id(devName) + local original_mac = network.get_mac(devName) + local vMacaddr = { } + -- Set first byte to 02 (locally administered unicast) + vMacaddr[1] = "02" + -- Use id[2] and id[3] from interface name for next bytes + vMacaddr[2] = id[2] + vMacaddr[3] = id[3] + -- Use last 3 bytes from main interface MAC + vMacaddr[4] = original_mac[4] + vMacaddr[5] = original_mac[5] + vMacaddr[6] = original_mac[6] + macaddr = table.concat(vMacaddr, ":") + + utils.unsafe_shell("ip link set dev "..devName.." address "..macaddr) + local ifnames = network.createStatic(devName) + utils.log("batadv created vlan "..devName.." with address:".. macaddr .." and static ".. ifnames) + --this seems not to be needed + --utils.unsafe_shell("batctl if add "..devName) end return batadv diff --git a/packages/lime-proto-batadv/tests/test_bat_apup.sh b/packages/lime-proto-batadv/tests/test_bat_apup.sh new file mode 100755 index 000000000..179639357 --- /dev/null +++ b/packages/lime-proto-batadv/tests/test_bat_apup.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# configure at least three routers with apup and limed, only leave one of them +# on and turn the rest off. +# run this script on a computer connected to the node to start limed and u-bus +# listen. +# turn on the other nodes and wait for them to connect + +NODE_IP="thisnode.info" +SSH_USER="root" +SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" + +ssh $SSH_OPTS "$SSH_USER@$NODE_IP" <&1 | while IFS= read -r line; do + echo "[\$(date +'%Y-%m-%d %H:%M:%S')] [limed] \$line" + done & + LIMED_PID=\$! + + ubus listen 2>&1 | while IFS= read -r line; do + echo "[\$(date +'%Y-%m-%d %H:%M:%S')] [ubus] \$line" + done & + UBUS_PID=\$! + + sleep 2 + echo "------------------------------------------" + sleep 2 + echo "------------------------------------------" + sleep 2 + + echo "[3/4] Bringing Wi-Fi up..." + wifi up + + echo "[4/4] Now you should be able to see new connections. Press Ctrl+C to stop." + wait \$LIMED_PID \$UBUS_PID +) +EOF + + +###### sample output +# [1/4] Bringing Wi-Fi down... +# [2/4] Starting limed and ubus listen ... +# ------------------------------------------ +# [2025-07-31 21:35:06] [limed] 'hostapd' namespace exists... +# [2025-07-31 21:35:07] [ubus] { "ubus.object.remove": {"id":1399214265,"path":"hostapd.wlan1-apup"} } +# ------------------------------------------ +# ------------------------------------------ +# [3/4] Bringing Wi-Fi up... +# [4/4] Now you should be able to see new connections. Press Ctrl+C to stop. +# [2025-07-31 21:35:16] [ubus] { "ubus.object.add": {"id":-1307156726,"path":"hostapd.wlan1-apup"} } + + +# [2025-07-31 21:36:02] [limed] Subscribing: hostapd.wlan1-apup +# [2025-07-31 21:36:03] [limed] peerSubscriber type: apup-newpeer data.ifname: wlan1-peer1 +# [2025-07-31 21:36:03] [ubus] { "ubus.object.add": {"id":565721540,"path":"network.interface.lm_net_lm_net_wlan1_peer1_static"} } +# [2025-07-31 21:36:03] [limed] lime.network.runProtocols(wlan1-peer1, ...) +# [2025-07-31 21:36:03] [limed] lime.proto.batadv.runOnDevice(wlan1-peer1, ...) +# [2025-07-31 21:36:03] [limed] lime.network.createVlan(wlan1-peer1, ...) +# [2025-07-31 21:36:03] [limed] vid = 29 +# [2025-07-31 21:36:03] [limed] type = 8021ad +# [2025-07-31 21:36:03] [limed] name = wlan1-peer1_29 +# [2025-07-31 21:36:03] [ubus] { "ubus.object.add": {"id":-1500836794,"path":"network.interface.lm_net_wlan1-peer1_batadv"} } +# [2025-07-31 21:36:03] [limed] ifname = wlan1-peer1 +# [2025-07-31 21:36:04] [ubus] { "network.interface": {"action":"ifup","interface":"lm_net_lm_net_wlan1_peer1_29_static"} } +# [2025-07-31 21:36:04] [ubus] { "ubus.object.add": {"id":-1232818779,"path":"network.interface.lm_net_lm_net_wlan1_peer1_29_static"} } +# [2025-07-31 21:36:04] [ubus] { "network.interface": {"action":"ifup","interface":"lm_net_wlan1-peer1_batadv"} } +# [2025-07-31 21:36:04] [limed] batadv createdwlan1-peer1_29 with address:02:58:11:22:55:bc and static lm_net_lm_net_wlan1_peer1_29_static +# [2025-07-31 21:36:04] [limed] lime.proto.babeld.runOnDevice(wlan1-peer1, ...) +# [2025-07-31 21:36:04] [limed] lime.network.createVlan(wlan1-peer1, ...) +# [2025-07-31 21:36:04] [limed] vid = 17 +# [2025-07-31 21:36:04] [limed] type = 8021ad +# [2025-07-31 21:36:04] [limed] name = wlan1-peer1_17 +# [2025-07-31 21:36:04] [limed] ifname = wlan1-peer1 +# [2025-07-31 21:36:04] [ubus] { "network.interface": {"action":"ifup","interface":"lm_net_lm_net_wlan1_peer1_17_static"} } +# [2025-07-31 21:36:04] [ubus] { "ubus.object.add": {"id":-1137476629,"path":"network.interface.lm_net_lm_net_wlan1_peer1_17_static"} } +# [2025-07-31 21:36:05] [limed] ip: RTNETLINK answers: File exists +# [2025-07-31 21:36:05] [ubus] { "ubus.object.add": {"id":-366401286,"path":"network.interface.lm_net_lm_net_wlan1_peer2_static"} } +# [2025-07-31 21:36:06] [ubus] { "ubus.object.add": {"id":-82673599,"path":"network.interface.lm_net_wlan1-peer2_batadv"} } +# [2025-07-31 21:36:06] [ubus] { "network.interface": {"action":"ifup","interface":"lm_net_lm_net_wlan1_peer2_29_static"} } +# [2025-07-31 21:36:06] [ubus] { "ubus.object.add": {"id":-1777215837,"path":"network.interface.lm_net_lm_net_wlan1_peer2_29_static"} } +# [2025-07-31 21:36:07] [ubus] { "network.interface": {"action":"ifup","interface":"lm_net_wlan1-peer2_batadv"} } +# [2025-07-31 21:36:07] [ubus] { "network.interface": {"action":"ifup","interface":"lm_net_lm_net_wlan1_peer2_17_static"} } +# [2025-07-31 21:36:07] [ubus] { "ubus.object.add": {"id":-1538210722,"path":"network.interface.lm_net_lm_net_wlan1_peer2_17_static"} } +# [2025-07-31 21:36:08] [limed] peerSubscriber type: apup-newpeer data.ifname: wlan1-peer2 +# [2025-07-31 21:36:08] [limed] ip: RTNETLINK answers: File exists +# [2025-07-31 21:36:08] [limed] lime.network.runProtocols(wlan1-peer2, ...) +# [2025-07-31 21:36:08] [limed] lime.proto.batadv.runOnDevice(wlan1-peer2, ...) +# [2025-07-31 21:36:08] [limed] lime.network.createVlan(wlan1-peer2, ...) +# [2025-07-31 21:36:08] [limed] vid = 29 +# [2025-07-31 21:36:08] [limed] type = 8021ad +# [2025-07-31 21:36:08] [limed] name = wlan1-peer2_29 +# [2025-07-31 21:36:08] [limed] ifname = wlan1-peer2 +# [2025-07-31 21:36:08] [limed] ip: RTNETLINK answers: File exists +# [2025-07-31 21:36:08] [limed] ip: RTNETLINK answers: File exists +# [2025-07-31 21:36:09] [limed] batadv createdwlan1-peer2_29 with address:02:f4:ce:22:55:bc and static lm_net_lm_net_wlan1_peer2_29_static +# [2025-07-31 21:36:09] [limed] lime.proto.babeld.runOnDevice(wlan1-peer2, ...) +# [2025-07-31 21:36:09] [limed] lime.network.createVlan(wlan1-peer2, ...) +# [2025-07-31 21:36:09] [limed] vid = 17 +# [2025-07-31 21:36:09] [limed] type = 8021ad +# [2025-07-31 21:36:09] [limed] name = wlan1-peer2_17 +# [2025-07-31 21:36:09] [limed] ifname = wlan1-peer2 +# [2025-07-31 21:36:09] [limed] ip: RTNETLINK answers: File exists +# [2025-07-31 21:36:09] [limed] ip: RTNETLINK answers: File exists diff --git a/packages/lime-system/files/usr/bin/limed b/packages/lime-system/files/usr/bin/limed index 31f47dcea..93ff67414 100755 --- a/packages/lime-system/files/usr/bin/limed +++ b/packages/lime-system/files/usr/bin/limed @@ -46,8 +46,27 @@ local peerSubscriber = { notify = function(nData, nType) if nType ~= "apup-newpeer" then return end - utils.log("peerSubscriber:", nType, nData.ifname) + utils.log("peerSubscriber type: %s data.ifname: %s ", nType, nData.ifname) + network.createStatic(nData.ifname) +--! interfaces should exist, but just in case we need to check, +--! to avoid +--! [2025-07-31 20:06:09] [limed] ip: SIOCGIFFLAGS: No such device +--! [2025-07-31 20:06:10] [limed] ip: can't find device 'wlan1-peer2' +--! [2025-07-31 20:06:10] [limed] lime.network.runProtocols(wlan1-peer2, ...) +--! [2025-07-31 20:06:10] [limed] lime.proto.batadv.runOnDevice(wlan1-peer2, ...) +--! [2025-07-31 20:06:11] [limed] lime.network.createVlan(wlan1-peer2, ...) +--! [2025-07-31 20:06:11] [limed] vid = 29 +--! [2025-07-31 20:06:11] [limed] type = 8021ad +--! [2025-07-31 20:06:11] [limed] name = wlan1-peer2_29 +--! [2025-07-31 20:06:11] [limed] ifname = wlan1-peer2 +--! [2025-07-31 20:06:12] [limed] ip: can't find device 'wlan1-peer2' +--! [2025-07-31 20:06:12] [ubus] { "ubus.object.add": +--{"id":-1478746778,"path":"network.interface.lm_net_wlan1-peer2_batadv"} } + if not network.device_exists(nData.ifname) then + utils.log("Device does not exist, skipping:", nData.ifname) + return + end network.runProtocols(nData.ifname) end } @@ -61,7 +80,7 @@ local apupSubscriber = { local evPath = "hostapd." .. apupDev - utils.log("Subscribing:", evPath) + utils.log("Subscribing: %s", evPath) ubus:subscribe(evPath, peerSubscriber) end } @@ -78,7 +97,7 @@ function limed.waitForHostapd() end if not found then utils.log("Waiting for 'hostapd' namespace...") - os.execute("sleep 1") -- Wait for 1 second before retrying + os.execute("sleep 1") else utils.log(" 'hostapd' namespace exists...") end diff --git a/packages/lime-system/files/usr/lib/lua/lime/network.lua b/packages/lime-system/files/usr/lib/lua/lime/network.lua index 344197cdd..25ab248b6 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/network.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/network.lua @@ -29,9 +29,14 @@ network.protoParamsSeparator=":" network.protoVlanSeparator="_" network.limeIfNamePrefix="lm_net_" - +--! Retuns the mac address of the interface or nill if it does not exist function network.get_mac(ifname) local _, macaddr = next(network.get_own_macs(ifname)) + --! this is to avoid the error: + --! ...ackages/lime-system/files/usr/lib/lua/lime/utils.lua:53: attempt to index local 'string' (a nil value) + if macaddr == nil then + return nil + end return utils.split(macaddr, ":") end @@ -594,6 +599,14 @@ function network.createStatic(linuxBaseIfname) return ifaceConf.name end +--! Check if a device exists in the system +function network.device_exists(dev) + local handle = io.popen("ip link show " .. dev .. " 2>/dev/null") + local result = handle:read("*a") + handle:close() + return result ~= nil and result ~= "" +end + --! Create a vlan at runtime via ubus function network.createVlan(linuxBaseIfname, vid, vlanProtocol) local vlanConf = { diff --git a/packages/lime-system/files/usr/lib/lua/lime/utils.lua b/packages/lime-system/files/usr/lib/lua/lime/utils.lua index f453dff9a..48f5814e5 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/utils.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/utils.lua @@ -50,6 +50,12 @@ end function utils.split(string, sep) local ret = {} + if sep == nil or sep == '' then + sep = '%s' --! default to whitespace + end + if string == nil or string == '' then + return ret + end for token in string.gmatch(string, "[^"..sep.."]+") do table.insert(ret, token) end return ret end diff --git a/packages/lime-system/tests/test_lime_network.lua b/packages/lime-system/tests/test_lime_network.lua index a9139df16..68b213783 100644 --- a/packages/lime-system/tests/test_lime_network.lua +++ b/packages/lime-system/tests/test_lime_network.lua @@ -28,6 +28,10 @@ describe('LiMe Network tests', function() assert.are.same({'00', '00', '00', '00', '00', '00'}, network.get_mac('lo')) end) + it('test get_mac for ethernet', function() + assert.is_nil (network.get_mac('nonexistent-interface')) + end) + it('test primary_interface configured interface', function() config.set('network', 'lime') config.set('network', 'primary_interface', 'test0') @@ -161,6 +165,14 @@ describe('LiMe Network tests', function() assert.are.Not.same(network.get_own_macs("wlan0"), network.get_own_macs("lo")) end) + it('test device_exists returns true for existing device', function() + assert.is_true(network.device_exists('lo')) + end) + + it('test device_exists returns false for non-existing device', function() + assert.is_false(network.device_exists('definitelynotadevicename')) + end) + before_each('', function() uci = test_utils.setup_test_uci() end)