diff --git a/packages/lime-curtigghio/README.adoc b/packages/lime-curtigghio/README.adoc new file mode 100644 index 000000000..742d728cc --- /dev/null +++ b/packages/lime-curtigghio/README.adoc @@ -0,0 +1,656 @@ += README +:email: gio@altermundi.net +:revdate: May 08, 2023 +:lang: en + +*TL;DR* Fiddling with hostad code I have managed to successfully establish WiFi +communication between multiple AP, each of them send and receive traffic from +the other as if they where associated stations, while they are all configured in +AP mode. This P2P like behavior have multiple advantages compared to the usual +setup where one of them is configured as AP and all the others as stations, and +also compared to Ad-Hoc, WDS, 802.11s, Multi-AP and EasyMesh. +I have named this operanting mode APuP (Access Point Micro Peering). + + +== A bit of context + +In community networks we need to maximize the possible paths of communitacions +between nodes. In a classical AP-STA approach it is not possible to guarantee +communication between all possible nodes in all scenarios. As an example if we +have 4 nodes A, B, C and D where A and B sees each other, B and C sees each +other C and D sees each other. With AP-STA mode each radio must operate either +as AP or as STA, each STA must connect to only one AP at once, STA need an AP to +relay communication between thems. In each combination configuring each node +either as AP or STA you will see that some of them will end up not being able to +connect. To overcome this issue in the past adhoc mode was used which solved the +basic connectivity issue, still it\'s implementation wasn\'t high quality and +it\'s design had important flaws, this resulted it in becoming +unmaintained after a few years. Luckly while adhoc was growing outdated 802.11s +emerged, it had a few improvements, still some design choice such as complex +ways to bridge other networks and routing between nodes fossilized into the +standard, increased WiFi drivers complexity became problematic and lastly +determined it\'s silent demisal. New radios drivers and firmwares doesn\'t +support 802.11s well. New WiFi standards doesn\'t bring much improvements to +802.11s mesh mode, while they do improve a lot AP-STA modes. Still our need of +nodes being able to comunicate to anyone in range is strong. In this context, +looking for a modern solution I started asking myself, is there an hard to +resolve problem that impede AP nodes in sight to talk each other? +Talking about my thinking with Felix Fietkau (nbd), we agreed that it might be +possible for AP nodes to commuicate directly each other, and because AP mode is +what is getting more support and improvements, if we can we just use that on +all nodes with some slight modification so all AP in sight can talk each other, +we could solve this problem that afflict us since WiFi creation. +Felix suggested that this should be possible and with a bit of luck should not +even need kernel and driver modifications, modifing `hostapd` in a way that each +AP adds the other in sight to its station list could be enough and it is indeed +the staring point to start experimenting and see what happens. + + +== Deep diving into hostapd + +File +src/hostapd/drivers/driver.h+ contain API specification and documentation +of hostapd -> WiFi driver interface. + +File +src/hostapd/drivers/driver_nl80211.c+ hostapd WiFi driver interface +implementation for nl80211 based wireless devices. + + +=== Adding STA flow + +`ap_sta_add(...)` + +Relevant functions: + - `wpa_driver_nl80211_sta_add(...)` + +File +src/hostapd/drivers/driver_nl80211_event.c+ hostapd receives and handle +events from nl80211 based wireless devices. + +Relevant functions: + - `do_process_drv_event(...)` + +File `wpa_supplicant/events.c` + +Relevant functions: + - `wpa_supplicant_event(...)` + + +Adding STA function flow: + +`do_process_drv_event(...) +driver_nl80211_event.c+ -> +`case NL80211_CMD_NEW_STATION:` -> +`nl80211_new_station_event(...)` -> +`drv_event_assoc(...)` +driver.h+ -> +`wpa_supplicant_event(..., EVENT_ASSOC, ...)` +wpa_supplicant/events.c+ -> +`case EVENT_ASSOC:` -> +`wpa_supplicant_event_assoc(..) && wpa_supplicant_event_assoc_auth(...)` + + +`wpa_supplicant_event_assoc(..)` -> +`hostapd_notif_assoc(...)` drv_callbacks.c -> +`ap_sta_add(...) ; hostapd_sta_assoc(...)` -> + + +`ap_sta_add(...)` +stainfo.c+ the new station is finally added to the list of +associated station to this AP in hostapd + + +`hostapd_sta_assoc(...)` -> `driver->sta_assoc(...)` +driver.h+ ++driver_nl80211.c+ does nothing for nl80211 devices + + +`wpa_supplicant_event_assoc_auth(...)` +wpa_supplicant/events.c+ seems to deal +with WPA authentication specific stuff + + +=== Adding WDS station flow + +Relevant functions: + - `wpa_driver_ops->set_wds_sta(...)` file +src/drivers/driver.h+ pointer to + hostapd + driver specific function to add or remove WDS stations, along with some + documentation about it + - `hostapd_set_wds_sta(...)` file +src/ap/ap_drv_ops.c+ do a few checks and + operations about bridging configuration then call + `hapd->driver->set_wds_sta(...)` aka `i802_set_wds_sta(...)` + - `i802_set_wds_sta(...)` file +src/hostapd/drivers/driver_nl80211.c+ + implementation of `wpa_driver_ops->set_wds_sta(...)` for mac80211 driver + +When an AP receive an association request `handle_assoc_cb(...)` file ++src/ap/ieee802_11.c+ is called if `WLAN_STA_WDS` flag is set then +`hostapd_set_wds_sta(...)` is called + + +=== Other APs beacon handling flow + +-------------------------------------------------------------------------------- + * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from + * other BSSes when any interfaces are in AP mode. This helps implement + * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME + * messages. Note that per PHY only one application may register. +-------------------------------------------------------------------------------- + +`nl80211_register_beacons(...)` +driver_nl80211.c+ register hostapd to +receive events from the kernel when beacons from other BSS are received, inside +this function no specific callback is passed to the kernel. +Inside `nl80211_get_wiphy_data_ap(...)` +driver_nl80211.c+ I have found the only +usage of the former function, `process_beacon_event(...)` +driver_nl80211.c+ is +registered as +callback and then `nl80211_register_beacons(...)` is finally called if +everything goes fine another function +`nl80211_recv_beacons(...)` +driver_nl80211.c+ is register with a call to +`nl80211_register_eloop_read(...)` +driver_nl80211.c+ . + + +`nl80211_recv_beacons(...)` +driver_nl80211.c+ which just call the more obscure +`nl_recvmsgs(handle, w->nl_cb);` where `w->nl_cb` seems to be +`process_beacon_event(...)` again... + + +`process_beacon_event(...)` +driver_nl80211.c+ do a few checks and then forward +the event to `wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);` which if +the beacon was received on an AP interface just call +`ap_mgmt_rx(wpa_s, &data->rx_mgmt);` at line 5598 of +wpa_supplicant/events.c+. + +`ap_mgmt_rx(...)` +wpa_supplicant/ap.c+ just call +`ieee802_11_mgmt(...)` +src/ap/iee802_11.c+ which at line 6337 calls +`handle_beacon(...);` +src/ap/iee802_11.c+ which do a few checks and then calls +`ap_list_process_beacon(...)` +src/ap/ap_list.c+ which finally seems to add the +AP from where the beacon originated to the list of known APs and do a few more +checks about _overlapping legacy BSS condition_. + + +== OpenWrt hostapd packaging + +`hostapd` openwrt package is shipped toghether with OpenWrt sources, and it is +found at +package/network/services/hostapd/+. In this directory we find ++README.md+ file which show a few interesting methods of the hostapd ubus +interface and +Makefile+ where all the `hostapd` OpenWrt variants like `wpad` +are defined. The +Makefile+ is a bit complex because the variants are a lot +depending on which subset of `hostapd` features are enabled, on what SSL/TLS +library is used etc. it is structured to avoid duplicating code and +common options all around that effectlively reduces the size of the `Makefile` +and probably ease the work for the maintainer. + +Depending on package variant OpenWrt `hostapd` package +Makefile+ sets multiple +configs with statments like `DRIVER_MAKEOPTS += CONFIG_AP=y` or +`DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y` those configurations +doesn't seems to impact directly in the hostapd C code `#ifdef` but are dealt +within `hostapd` and `wpa_supplicant` sources +Makefile+ which depending on the +passed configs set the proper `CFLAGS`, C source files and output objects files. + +To use our customized `hostapd` source in OpenWrt we use source tree override +https://forum.archive.openwrt.org/viewtopic.php?id=46916[as explained by Jow] + +Plus a couple more steps to integrate OpenWrt `hostapd` specific patches and +additional sources. + +`rsync -aPh ~/Builds/openwrt/package/network/services/hostapd/src/ ./` +`for mPatch in ~/Builds/openwrt/package/network/services/hostapd/patches/*.patch ; do patch -p1 < $mPatch ; done` + +The modified `hostapd` code I published on my +https://gitlab.com/g10h4ck/hostap/-/tree/APuP[gitlab sandbox] already +includes those so you don't need to reapply them. + +To clean and re-build only hostapd package use +`make package/network/services/hostapd/clean` +`make package/network/services/hostapd/compile` + + +== hostapd modifications + +To enable WDS AP - AP I have modified `handle_beacon(...)` function defined in ++src/ap/ieee802_11.c+, so when a beacon from another AP is received beside the +usual processing, it checks if the advertised SSID is the same as one advertised +by current istance, if so, information from that beacon is extracted and +adapted to look like station information, and a station entry is populated and +saved into hostapd station list. This modifications should be put into their own +function later. + +To avoid all specific interface created for each AP-AP connection being bridged +automatically by `hostapd` and potentially creating a loop, I have temporarly +disabled bridging in `hostapd_set_wds_sta` defined in +src/ap/ap_drv_ops.c+, +this should become a runtime configuration later. + +I have also added a compile time config `CONFIG_APUP` in +hostapd/Makefile+ so +this modifications can be easly enabled at compile time. + +I have tested the modifications and after a bunch of round of trial and error +works as expected, with good performances, you can see the +test.sh+ script +which configures four vanilla OpenWrt routers into a working testbed to see how +to use this. + +The modified `hostapd` code is published on my +https://gitlab.com/g10h4ck/hostap/-/tree/APuP[gitlab sandbox] + + +== Useful snippets + +.Log: TL-WDR3600 and TL-WDR4300 WDS AP - AP connection success +-------------------------------------------------------------------------------- +Fri Apr 28 22:24:11 2023 daemon.notice hostapd: Configuration file: /var/run/hostapd-phy1.conf (phy phy1-ap0) --> new PHY +Fri Apr 28 22:24:11 2023 daemon.notice netifd: wan (1619): udhcpc: broadcasting discover +Fri Apr 28 22:24:12 2023 kern.info kernel: [ 39.574041] IPv6: ADDRCONF(NETDEV_CHANGE): phy1-ap0: link becomes ready +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy1-ap0: interface state UNINITIALIZED->ENABLED +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy1-ap0: AP-ENABLED +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: Configuration file: /var/run/hostapd-phy0.conf (phy phy0-ap0) --> new PHY +Fri Apr 28 22:24:12 2023 kern.info kernel: [ 39.827175] IPv6: ADDRCONF(NETDEV_CHANGE): phy0-ap0: link becomes ready +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy0-ap0: interface state UNINITIALIZED->ENABLED +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy0-ap0: AP-ENABLED +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy1-ap0: AP-STA-CONNECTED 64:70:02:de:c5:1e auth_alg=open +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy1-ap0: WDS-STA-INTERFACE-ADDED ifname=phy1-ap0.sta1 sta_addr=64:70:02:de:c5:1e +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: handle_beacon(...) Added WDS AP at phy1-ap0.sta1 with flags: 35491, capabilities 33 +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy0-ap0: AP-STA-CONNECTED 64:70:02:de:c5:1d auth_alg=open +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: phy0-ap0: WDS-STA-INTERFACE-ADDED ifname=phy0-ap0.sta1 sta_addr=64:70:02:de:c5:1d +Fri Apr 28 22:24:12 2023 daemon.notice hostapd: handle_beacon(...) Added WDS AP at phy0-ap0.sta1 with flags: 35491, capabilities 1057 +-------------------------------------------------------------------------------- + +.Log: Two DAP-X1860-A1 WDS AP - AP connection success +-------------------------------------------------------------------------------- +Thu May 25 21:55:04 2023 daemon.notice hostapd: phy0-ap0: AP-STA-CONNECTED a8:63:7d:2e:97:d9 auth_alg=open +Thu May 25 21:55:05 2023 daemon.notice hostapd: phy0-ap0: WDS-STA-INTERFACE-ADDED ifname=phy0-ap0.sta1 sta_addr=a8:63:7d:2e:97:d9 +Thu May 25 21:55:05 2023 daemon.notice netifd: Interface 'curtigghio' is now down +Thu May 25 21:55:05 2023 daemon.notice hostapd: handle_beacon(...) Added WDS AP at phy0-ap0.sta1 with flags: 35491, capabilities 1057 +Thu May 25 21:55:05 2023 daemon.notice netifd: Interface 'curtigghio' is setting up now +Thu May 25 21:55:05 2023 daemon.notice netifd: Interface 'curtigghio' is now up +Thu May 25 21:55:05 2023 daemon.notice netifd: Network device 'phy0-ap0.sta1' link is up +Thu May 25 21:55:05 2023 daemon.notice hostapd: phy1-ap0: AP-STA-CONNECTED a8:63:7d:2e:97:dc auth_alg=open +Thu May 25 21:55:05 2023 daemon.notice hostapd: phy1-ap0: WDS-STA-INTERFACE-ADDED ifname=phy1-ap0.sta1 sta_addr=a8:63:7d:2e:97:dc +Thu May 25 21:55:05 2023 daemon.notice hostapd: handle_beacon(...) Added WDS AP at phy1-ap0.sta1 with flags: 297635, capabilities 33 +Thu May 25 21:55:05 2023 daemon.notice netifd: Network device 'phy1-ap0.sta1' link is up +-------------------------------------------------------------------------------- + + +.Log: plain station connecting and desconnecting to the AP +-------------------------------------------------------------------------------- +Sun Jan 1 22:06:54 2023 daemon.notice hostapd: phy0-ap0: interface state UNINITIALIZED->ENABLED +Sun Jan 1 22:06:54 2023 daemon.notice hostapd: phy0-ap0: AP-ENABLED +Sun Jan 1 22:06:54 2023 daemon.notice hostapd: LIME_CURTIJJO nl80211: Drv Event 60 (NL80211_CMD_FRAME_TX_STATUS) received for phy0-ap0 +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO nl80211: Drv Event 60 (NL80211_CMD_FRAME_TX_STATUS) received for phy0-ap0 +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO ap_sta_add addr: b4:9d:0b:87:ed:06 +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO ap_sta_add addr: b4:9d:0b:87:ed:06 New STA +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO hostapd_sta_add explicit params addr=b4:9d:0b:87:ed:06 aid=0 capability=0 supp_rates=0x77aee688 supp_rates_len=3 listen_interval=0 ht_capab=0 vht_capab=0 he_capab=0 he_capab_len=0 eht_capab=0 eht_capab_len=0 he_6ghz_capab=0 flags=0 qosinfo=0 vht_opmode=0 supp_p2p_ps=0 set=0 +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 IEEE 802.11: authentication OK (open system) +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 MLME: MLME-AUTHENTICATE.indication(b4:9d:0b:87:ed:06, OPEN_SYSTEM) +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 MLME: MLME-DELETEKEYS.request(b4:9d:0b:87:ed:06) +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO nl80211: Drv Event 19 (NL80211_CMD_NEW_STATION) received for phy0-ap0 +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO nl80211: Drv Event 60 (NL80211_CMD_FRAME_TX_STATUS) received for phy0-ap0 +Sun Jan 1 22:07:09 2023 daemon.info hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 IEEE 802.11: authenticated +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 IEEE 802.11: association OK (aid 1) +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO hostapd_sta_add explicit params addr=b4:9d:0b:87:ed:06 aid=1 capability=1057 supp_rates=0x77aee688 supp_rates_len=8 listen_interval=1 ht_capab=0x7f7aec04 vht_capab=0 he_capab=0 he_capab_len=0 eht_capab=0 eht_capab_len=0 he_6ghz_capab=0 flags=35459 qosinfo=0 vht_opmode=0 supp_p2p_ps=0 set=1 +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: LIME_CURTIJJO nl80211: Drv Event 60 (NL80211_CMD_FRAME_TX_STATUS) received for phy0-ap0 +Sun Jan 1 22:07:09 2023 daemon.info hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 IEEE 802.11: associated (aid 1) +Sun Jan 1 22:07:09 2023 daemon.notice hostapd: phy0-ap0: AP-STA-CONNECTED b4:9d:0b:87:ed:06 auth_alg=open +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 MLME: MLME-ASSOCIATE.indication(b4:9d:0b:87:ed:06) +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 MLME: MLME-DELETEKEYS.request(b4:9d:0b:87:ed:06) +Sun Jan 1 22:07:09 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 IEEE 802.11: binding station to interface 'phy0-ap0' +Sun Jan 1 22:07:12 2023 daemon.info dnsmasq-dhcp[1]: DHCPDISCOVER(br-lan) b4:9d:0b:87:ed:06 +Sun Jan 1 22:07:12 2023 daemon.info dnsmasq-dhcp[1]: DHCPOFFER(br-lan) 192.168.1.122 b4:9d:0b:87:ed:06 +Sun Jan 1 22:07:12 2023 daemon.info dnsmasq-dhcp[1]: DHCPREQUEST(br-lan) 192.168.1.122 b4:9d:0b:87:ed:06 +Sun Jan 1 22:07:12 2023 daemon.info dnsmasq-dhcp[1]: DHCPNAK(br-lan) 192.168.1.122 b4:9d:0b:87:ed:06 wrong server-ID +Sun Jan 1 22:07:28 2023 daemon.notice hostapd: phy0-ap0: AP-STA-DISCONNECTED b4:9d:0b:87:ed:06 +Sun Jan 1 22:07:28 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 IEEE 802.11: deauthenticated +Sun Jan 1 22:07:28 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 MLME: MLME-DEAUTHENTICATE.indication(b4:9d:0b:87:ed:06, 3) +Sun Jan 1 22:07:28 2023 daemon.debug hostapd: phy0-ap0: STA b4:9d:0b:87:ed:06 MLME: MLME-DELETEKEYS.request(b4:9d:0b:87:ed:06) +Sun Jan 1 22:07:28 2023 daemon.notice hostapd: LIME_CURTIJJO nl80211: Drv Event 20 (NL80211_CMD_DEL_STATION) received for phy0-ap0 +-------------------------------------------------------------------------------- + +.Dump ieee802_11_elems +-------------------------------------------------------------------------------- + wpa_printf( MSG_INFO, + "handle_beacon(...) elems: " + "ssid %.*s " + "supp_rates_len %d, " + "ds_params %p, " + "challenge_len %d, " + "erp_info %p, " + "ext_supp_rates_len %d, " + "wpa_ie_len %d, " + "rsn_ie_len %d, " + "rsnxe_len %d, " + "wmm_len %d, " + "wmm_tspec_len %d, " + "wps_ie_len %d, " + "supp_channels_len %d, " + "mdie_len %d, " + "ftie_len %d, " + "timeout_int %p, " + "ht_capabilities %p, " + "ht_operation %p, " + "mesh_config_len %d, " + "mesh_id_len %d, " + "peer_mgmt_len %d, " + "vht_capabilities %p, " + "vht_operation %p, " + "vht_opmode_notif %p, " + "vendor_ht_cap_len %d, " + "vendor_vht_len %d, " + "p2p_len %d, " + "wfd_len %d, " + "link_id %p, " + "interworking_len %d, " + "qos_map_set_len %d, " + "hs20_len %d, " + "bss_max_idle_period %p, " + "ext_capab_len %d, " + "ssid_list_len %d, " + "osen_len %d, " + "mbo_len %d, " + "ampe_len %d, " + "mic_len %d, " + "pref_freq_list_len %d, " + "supp_op_classes_len %d, " + "rrm_enabled_len %d, " + "cag_number_len %d, " + "ap_csn %p, " + "fils_indic_len %d, " + "dils_len %d, " + "assoc_delay_info %p," + "fils_req_params_len %d, " + "fils_key_confirm_len %d, " + "fils_session %p, " + "fils_hlp_len %d, " + "fils_ip_addr_assign_len %d, " + "key_delivery_len %d, " + "wrapped_data_len %d, " + "fils_pk_len %d, " + "fils_nonce %p, " + "owe_dh_len %d, " + "power_capab_len %d, " + "roaming_cons_sel_len %d, " + "password_id_len %d, " + "oci_len %d, " + "multi_ap_len %d, " + "he_capabilities_len %d, " + "he_operation_len %d, " + "short_ssid_list_len %d, " + "he_6ghz_band_cap %p," + "sae_pk_len %d, " + "s1g_capab %p, " + "pasn_params_len %d, " + "eht_capabilities_len %d, " + "eht_operation_len %d, " + "basic_mle_len %d, " + "probe_req_mle_len %d, " + "reconf_mle_len %d, " + "tdls_mle_len %d, " + "prior_access_mle_len %d, " + "mbssid_known_bss_len %d |END|" + , + (int) elems.ssid_len, elems.ssid, + elems.supp_rates_len, + elems.ds_params, + elems.challenge_len, + elems.erp_info, + elems.ext_supp_rates_len, + elems.wpa_ie_len, + elems.rsn_ie_len, + elems.rsnxe_len, + elems.wmm_len, + elems.wmm_tspec_len, + elems.wps_ie_len, + elems.supp_channels_len, + elems.mdie_len, + elems.ftie_len, + elems.timeout_int, + elems.ht_capabilities, + elems.ht_operation, + elems.mesh_config_len, + elems.mesh_id_len, + elems.peer_mgmt_len, + elems.vht_capabilities, + elems.vht_operation, + elems.vht_opmode_notif, + elems.vendor_ht_cap_len, + elems.vendor_vht_len, + elems.p2p_len, + elems.wfd_len, + elems.link_id, + elems.interworking_len, + elems.qos_map_set_len, + elems.hs20_len, + elems.bss_max_idle_period, + elems.ext_capab_len, + elems.ssid_list_len, + elems.osen_len, + elems.mbo_len, + elems.ampe_len, + elems.mic_len, + elems.pref_freq_list_len, + elems.supp_op_classes_len, + elems.rrm_enabled_len, + elems.cag_number_len, + elems.ap_csn, + elems.fils_indic_len, + elems.dils_len, + elems.assoc_delay_info, + elems.fils_req_params_len, + elems.fils_key_confirm_len, + elems.fils_session, + elems.fils_hlp_len, + elems.fils_ip_addr_assign_len, + elems.key_delivery_len, + elems.wrapped_data_len, + elems.fils_pk_len, + elems.fils_nonce, + elems.owe_dh_len, + elems.power_capab_len, + elems.roaming_cons_sel_len, + elems.password_id_len, + elems.oci_len, + elems.multi_ap_len, + elems.he_capabilities_len, + elems.he_operation_len, + elems.short_ssid_list_len, + elems.he_6ghz_band_cap, + elems.sae_pk_len, + elems.s1g_capab, + elems.pasn_params_len, + elems.eht_capabilities_len, + elems.eht_operation_len, + elems.basic_mle_len, + elems.probe_req_mle_len, + elems.reconf_mle_len, + elems.tdls_mle_len, + elems.prior_access_mle_len, + elems.mbssid_known_bss_len + ); +-------------------------------------------------------------------------------- + + +http://www.bradgoodman.com/bittool/ + + +== WDS Station interface bridging + +hostapd add WDS STA interfaces to a bridge either the same of plain station +passed with the `bridge` option or to another one passed with the `wds_bridge`, +in our use case this is not ideal as we might want the routing propocols access +directly to the station interface. Moreover in a mesh setup multiple links could +easily cause a bridge loop, that linux simple bridge will be not able to handle +as is. To disable automatic bridging set `wds_bridge` to an empty string in the +hostapd config file. + + +== Interesting conversations + +-------------------------------------------------------------------------------- +[16:11] G10h4ck: ovsdb is what actually contains the switch configuration; it's needed +[16:13] <-- Guest2984 (~srslypasc@0002bff5.user.oftc.net) has left this server (Ping timeout: 480 seconds). +[16:19] <-- Borromini (~Jean-Jacq@0001344c.user.oftc.net) has left this server (Quit: Lost terminal). +[16:27] <-- cbeznea (~claudiu@82.78.167.116) has left this server (Quit: Leaving.). +[16:41] <-- borek (~Thunderbi@2001:1488:fffe:6:e258:8d45:f844:67) has left this server (Ping timeout: 480 seconds). +[17:11] dwfreed in my case the heig level configuration is managed by another custom compontent which is able to output openflow +[17:11] --> csrf1 (~csrf@ip72-199-118-215.sd.sd.cox.net) has joined this channel. +[17:12] in that case I guess only only ovs-vswitchd should be needed +[17:13] anyway I see libopenvswitch is 2.3M it seems huge for an embedded device, and used by even the most basic tool ovs-ctl -_- is this the toll to use openvswitch ? +[17:14] <-- csrf1 (~csrf@ip72-199-118-215.sd.sd.cox.net) has left this server. +[17:14] --> csrf (~csrf@ip72-199-118-215.sd.sd.cox.net) has joined this channel. +[17:19] I mean, yeah +[17:20] ovs is not intended for microscopic devices +[17:21] equally I would not expect non-trivial configs to work well with the barebones DSA implementations of embedded devices +[17:22] dwfreed the idea is to use openvswitch mainly as datapath, another component which understand mesh networks would configure it +[17:22] <-- csrf (~csrf@ip72-199-118-215.sd.sd.cox.net) has left this server (Remote host closed the connection). +[17:22] sadly batman-adv seems not much alive anymore so we are looking for alternatives way +[17:22] --> csrf (~csrf@ip72-199-118-215.sd.sd.cox.net) has joined this channel. +[17:23] the idea we had was "let's implement layed 2 mesh logic in userspace and then configure openvswitch as kernel space datapath" +[17:23] and we are investigating the fesibility +[17:24] so basically we would have an ovs bridge with ethernet ports and wifi mesh ports, and then the table of the switch would be manipulated by a mesh aware compontent, to deal with loops, lossy links etc.. +[17:25] if you're doing your own datapath thing anyway, why not just implement the datapath in ebpf? +[17:29] I have thinked of that too nbd to use openvswitch was to avoid implementing the datapath, and just implement the mesh logic +[17:29] nbd did you recognized me? it's Gio from libre-mesh +[17:29] yes +[17:29] it's been a while +[17:30] how ar ere you? +[17:31] doing fine, thanks. how about you? +[17:31] I am good too, in Argentina right now with the Altermundi people +[17:31] cool +[17:31] so I thinked that openvswitch datapath should be fine for libre-mesh setup, but was just exploring that +[17:32] do you think reimplementing the datapath in ebpf would endup working better then attempting to reuse openvswitch stuff? +[17:32] depends on the needs of the routing algorithm, i guess +[17:32] with ebpf you can have more control over the datapath +[17:33] my idea was to keep the datapath kernel-space and move the wole mesh login like link discovery. quality measure, calculatinc best path etc. in user space +[17:33] but it takes a while to learn how to fight the verifier :) +[17:33] that makes sense +[17:34] either way, if you choose ovs, i would recommend simply not using any of the existing ovs user space code +[17:35] and just write your own thing that talks to the kernel ovs api +[17:35] i don't think there's any easy way to cut down on the amount of bloat in the ovs user space +[17:36] it is a pity the ovs userspace is so bloated... +[17:37] thanks nbd i was feeling a bit lost exploring all that stuff and your opinion helps a lot +[17:38] i think a ebpf data path in the kernel might actually end up being rather simple +[17:39] the routing table is basically a map that uses the destination mac as primary key +[17:39] and points to an entry in another map that keeps track of links +[17:39] containing metadata such as the output device, packet counters, etc. +[17:40] the program should recognize protocol data packets and simply bounce them to user space on a separate device +[17:41] if you're using a custom eth type for encapsulation and don't use IP, the header overhead should be small as well +[17:41] initially i would recommend simply bouncing all multicast traffic into user space and forwarding it from there +[17:42] multicast/broadcast +[17:42] makes it easier to deal with special cases for dhcp, arp, etc. +[17:43] thanks! +[17:43] you're welcome. let me know how it goes and which approach you decide on +[17:43] i'm definitely interested in this +[17:44] i also have some experience writing ebpf programs, so i can offer some advice if you get stuck somewhere +[17:44] great! +[17:45] for openwrt, i wrote 'bridger', which is a fast path for the linux bridge code and 'qosify' which does rule based dscp marking +[17:45] in current openwrt compiling ebpf stuff is already integrated in the toolchain? +[17:46] there's some makefile magic to make it easy to build and package ebpf code +[17:46] didn't know of those new components at all! +[17:47] inside qosify or unetd you can also find a header file bpf_skb_utils.h which makes it much easier to parse ip protocol stuff in skbs +[17:47] qosify seems something we my end up using in libre-mesh +[17:47] maybe you might be interested in unetd as well +[17:48] my goal with it was to create the easiest way to deploy and manage fully meshed decentralized wireguard networks +[17:48] very interesting +[17:49] it also makes it easy to layer vxlan on top to bridge l2 segments over the network +[17:50] it seemsto have many interesting overlapping area which what i was investigating :D +[17:50] https://openwrt.org/docs/techref/unetd +[17:50] :) +[17:51] unetd can also do direct connections over double-NAT, assuming at least one node is publicly reachable (or you're using DHT + a STUN server) +[17:52] and what happens if some connections are over lossy wifi links ? (smirk smirk) +[17:53] it doesn't do any form of mesh routing +[17:53] though i guess that might be interesting too +[17:54] it has some limited configuration where you configure a node as a gateway for another node +[17:55] it works on the basis of having a cryptographically signed network topology with wireguard keys, hostnames and ip/subnet addresses reachable over nodes with those keys +[17:56] you can update the network topology and it'll spread across participating nodes +[17:56] --> minimal (~minimal@0002b71e.user.oftc.net) has joined this channel. +[17:56] and it'll exchange peer endpoint information to try to get every node to be able to talk to all other nodes directly +[17:58] anyways... it was good talking to you, i need to get some sleep now +[17:58] the kids wake me up early in the morning +[17:58] have a good sleep +[17:58] thanks +[17:58] hugs to the family +[17:58] and thanks for sharing all the interesting ideas + +[11:24] hi all! +[11:24] --> Gaspare (~Gaspare@177-38-99-106.netway.psi.br) has joined this channel. +[11:25] nbd I was diving into eBPF and found that linux have many helper functions like bpf_skb_vlan_push, i was wandering if it is powwible to manipulate wifi frames with similar helpers, in particular if there is a way to access and manypulate the 4 macaddress fields in the wifi data frames +[11:29] you can insert headers, manipulate frame data, etc. +[11:29] it's quite flexible +[11:31] I was wondering about forwarding L2 frames without need to encapsulate them, encapsulating L2 stuff have gine MTU quirks historically expecially when both cabled ethernet and wifi links are involved +[11:31] we managed to work around those hickups, but prevent them radically is tempting +[11:32] so if we can access the four macs fields in the wifi frame we gould use one for real source and one for real destination +[11:32] <-- Gaspare (~Gaspare@177-38-99-106.netway.psi.br) has left this server (Ping timeout: 480 seconds). +[11:34] G10h4ck: in unetd vxlan i had mtu issues as well, so i wrote a BPF program that fixes the TCP MSS option to deal with that +[11:34] yeah we have that sort of workaround in place in libremesh too +[11:34] but they always fix only part of the problem +[11:35] at some point we endup having reports from users the the app X that uses it's own UDP based transport protocol doesn't work as expected for example +[11:36] in the end we have all user facing network interfaces setted with MTU 1350 +[11:36] we also telle the clients via DHCP that the mtu is 1350 and so on +[11:36] but there is always some quirks +[11:37] you could bounce oversized packets to user space and let user space send back ICMP error packets to trigger path MTU discovery +[11:37] in our case it seems we can avoid it almost completely in most of the case by avoiding encapsulation unless it is strictly needed +[11:38] on cabled links we could just forward the frame as-is to the correct interface +[11:38] in wireless link we should set DST macaddress to the nextop, and save the real_DST somewhere, maybe in 4 mac address field +[11:39] just make a real 4-address wireless link +[11:39] then you can treat it as an ethernet link +[11:39] or we could encapsulate on wireless only which supports greater mtu, and then decapsulate when forwarding over cabled link +[11:40] at some point i was thinking of making a mesh-like mode which runs on top of a regular AP interface and simply creates 4-addr peer station entries/interfaces for its neighbors +[11:40] seems like it would fit nicely with what you're trying to do +[11:40] also it seems that newer radios doesn'T supports 802,11s that well +[11:40] one useful property of this is that it doesn't require special addressing modes used for 802.11s +[11:41] it would work with any chipset that has normal mac80211 4-addr support +[11:41] and would work with the existing offload features +[11:41] e.g. encap offload on mtk chipsets +[11:41] with a bit of luck, it wouldn't even need user space changes +[11:41] sorry, kernel space changes +[11:42] it would work with a modified hostapd +[11:42] since all you're doing is creating extra station entries and handling mgmt/auth in user space +[11:42] > it would work with any chipset that has normal mac80211 4-addr support< is this supported by most of the chips/drivers ? +[11:42] most common ones yes +[11:42] ath9k, ath10k, mt76 +[11:43] it would definitely be a lot faster than 802.11s +[11:45] do you think ath11k will be viable for this too ? +[11:45] San was investigating 802.11ax radios for librerouter 2 +[11:46] i think it could work, but i would definitely recommend going with mt7915 instead +[11:46] for 802.11ax +[11:46] he has been playing with some mt7915e based radios +[11:48] from what i hear, ath11k still has a lot of firmware bugs +[11:48] and you can't really expect any reasonable support from qualcomm +[11:48] so this AP + 4-addr custom mode you suggests seems very interesting +[11:49] with mt76, i can forward bug reports directly to mtk +[11:49] and they typically have been very responsive when it comes to dealing with firmware issues +[11:49] so basically one should configure the radio in this mode on each router, and it would behave more or less like mesh node, but with better performances +[11:49] of course somebody would have to write the code for hostapd to do this +[11:50] one advantage is that you wouldn't even need a separate interface for meshing anymore. you could piggy-back on a normal ap interface with this +[11:52] that would be great +[11:53] from what I understand we will be also less dependant on driver support of "more exotic" features like virtual interfaces and 802.11s +[11:53] so any radio with good AP support should work well +[11:54] do I understand well? +-------------------------------------------------------------------------------- + + +-------------------------------------------------------------------------------- +[16:21] G10h4ck: hi +[16:41] hi nbd how are you? +[16:45] G10h4ck: fine, thx +[16:45] how about you? +[16:48] I had some stomachache but now seem going good, also have been reading hostapd code, I have now some undertanding, still I need your suggestion on what should be the flow to add an AP as a station in the station list, AFAIR right now when a station try to associato to our AP an event is bubbled from the kernel to the hostapd code and the hostapd code do a few stuff, authentication etc. then add it in it's station list and call a driver specific callback ( +[16:48] driver->add_station or something similar) that in case of mac80211 is NULL so does nothing +[17:05] so in case there is another AP, I guess that event is not triggered because the APwill not attempt to associate +[17:07] so there is some useful event bubbled to hostapd, for example when a beacon from another AP is received, where we can plug our code which create a station entry or should I "scan" for available AP in another way, and then trigger the station adding code? +[17:09] it's been a while since i looked at that part of hostapd +[17:09] so i don't have any answers yet +[17:10] i don't think you should scan +[17:10] beacons should be received already +[17:10] for coexistence purposes +[17:10] i just don't know in which part of the code +[17:22] nbd: so in some part of the code hostapd should receive the beacons from other AP ? +[17:23] yes +[17:25] so I need to keep digging into hostapd code and then come back with more questions :) +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +[14:51] nbd It's me getting too old or it's hostapd/wpa_supplicant code utterly convoluted? digging into function calls one and up falling in the white rabbit hole every a couple of them... +[14:53] it's not just you, been there yesterday +[14:56] i feel less alone :p +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +[11:41] Hi! +[11:42] with device tree there is something wone can look at at runtime from userspace to explore the hardware? or it is available only at compile time ? +[11:56] G10h4ck: /proc/device-tree +[11:58] Great! thanks f00b4r0 +-------------------------------------------------------------------------------- + +== Suggested readings + +https://wireless.wiki.kernel.org/en/users/Documentation/hostapd +https://wireless.wiki.kernel.org/en/developers/documentation/glossary diff --git a/packages/lime-curtigghio/test.sh b/packages/lime-curtigghio/test.sh new file mode 100755 index 000000000..d349b5f3d --- /dev/null +++ b/packages/lime-curtigghio/test.sh @@ -0,0 +1,502 @@ +#!/bin/bash + +## LibreMesh community mesh networks meta-firmware +## +## Copyright (C) 2023-2024 Gioacchino Mazzurco +## Copyright (C) 2023-2024 Asociación Civil Altermundi +## +## SPDX-License-Identifier: AGPL-3.0-only + + +## Define default value for variable, take two arguments, $1 variable name, +## $2 default variable value, if the variable is not already define define it +## with default value. +function define_default_value() +{ + VAR_NAME="${1}" + DEFAULT_VALUE="${2}" + + [ -z "${!VAR_NAME}" ] && export ${VAR_NAME}="${DEFAULT_VALUE}" || true +} + + +define_default_value OPENWRT_BUILD_DIR "$HOME/Builds/openwrt-apup/" +define_default_value KCONFIG_UTILS_DIR "$HOME/Development/kconfig-utils/" +define_default_value HOSTAPD_REPO_DIR "$HOME/Development/hostap/" +define_default_value OPENWRT_REPO_DIR "$HOME/Development/openwrt/" +define_default_value NETIFD_REPO_DIR "$HOME/Development/netifd/" + + + +cIface="usbe1" + +bianco43IP="fe80::c24a:ff:fefc:2f12%$cIface" +bluIP="fe80::6670:2ff:fede:c51e%$cIface" +neroIP="fe80::c24a:ff:fe7a:acac%$cIface" +verdeIP="fe80::ea94:f6ff:fe68:3364%$cIface" + +dax1Ipll="fe80::aa63:7dff:fe2e:97c8%$cIface" +dax2Ipll="fe80::aa63:7dff:fe2e:97d8%$cIface" + +hlk1Ipll="169.254.145.20" +hlk2Ipll="169.254.145.22" + +youhuaIpll="fe80::d65f:25ff:feeb:63d8%$cIface" + +source "${KCONFIG_UTILS_DIR}/kconfig-utils.sh" + +function fHostapdSourceTreeOverride() +{ + local mHostapdGitSrc="$OPENWRT_BUILD_DIR/package/network/services/hostapd/git-src" + rm -f "$mHostapdGitSrc" + ln -s "${HOSTAPD_REPO_DIR}/.git" "$mHostapdGitSrc" +} + +function fNetifdSourceTreeOverride() +{ + local mNetifdGitSrc="$OPENWRT_BUILD_DIR/package/network/config/netifd/git-src" + rm -f "$mNetifdGitSrc" + ln -s "$NETIFD_REPO_DIR/.git" "$mNetifdGitSrc" +} + +function fTestConf() +{ + kconfig_set CONFIG_DEVEL + kconfig_set CONFIG_SRC_TREE_OVERRIDE + +# fHostapdSourceTreeOverride + + fNetifdSourceTreeOverride + + kconfig_set CONFIG_PACKAGE_iperf3 + + kconfig_unset CONFIG_PACKAGE_ppp + kconfig_unset CONFIG_PACKAGE_ppp-mod-pppoe + kconfig_unset CONFIG_PACKAGE_kmod-ppp + kconfig_unset CONFIG_PACKAGE_kmod-pppoe + kconfig_unset CONFIG_PACKAGE_kmod-pppox +} + +function fBuildDapX() +{ + pushd "$OPENWRT_BUILD_DIR" + + ./scripts/feeds update -a + ./scripts/feeds install -a + + # Prepare firmware for D-Link DAP-X1860 + echo "" > "$KCONFIG_CONFIG_PATH" + kconfig_init_register + + kconfig_set CONFIG_TARGET_ramips + kconfig_set CONFIG_TARGET_ramips_mt7621 + kconfig_set CONFIG_TARGET_ramips_mt7621_DEVICE_dlink_dap-x1860-a1 + make defconfig + + fTestConf + make defconfig + + kconfig_check + kconfig_wipe_register + + clean_hostapd + + make -j $(($(nproc)-1)) + popd +} + +function fBuildYouhua() +{ + pushd "$OPENWRT_BUILD_DIR" + + ./scripts/feeds update -a + ./scripts/feeds install -a + + # Prepare firmware for D-Link DAP-X1860 + echo "" > "$KCONFIG_CONFIG_PATH" + kconfig_init_register + + kconfig_set CONFIG_TARGET_ramips + kconfig_set CONFIG_TARGET_ramips_mt7621 + kconfig_set CONFIG_TARGET_ramips_mt7621_DEVICE_youhua_wr1200js + make defconfig + + fTestConf + make defconfig + + kconfig_check + kconfig_wipe_register + + clean_hostapd + + make -j $(($(nproc)-1)) + popd +} + +function fBuildHlk() +{ + pushd "$OPENWRT_BUILD_DIR" + + ./scripts/feeds update -a + ./scripts/feeds install -a + + # Prepare firmware for D-Link DAP-X1860 + echo "" > "$KCONFIG_CONFIG_PATH" + kconfig_init_register + + kconfig_set CONFIG_TARGET_ramips + kconfig_set CONFIG_TARGET_ramips_mt7621 + kconfig_set CONFIG_TARGET_ramips_mt7621_DEVICE_hilink_hlk-7621a-evb + make defconfig + + kconfig_set CONFIG_PACKAGE_pciutils + kconfig_set CONFIG_PACKAGE_kmod-mt7916-firmware + fTestConf + make defconfig + + kconfig_check + kconfig_wipe_register + + clean_packages + + make -j $(($(nproc)-1)) + popd +} + +function dflash() +{ + dDevice="$1" + dImage="$2" + + scp -O "${dImage}" root@[${dDevice}]:/tmp/ + imgName="$(basename "$dImage")" + + origHash="$(sha256sum "$dImage" | awk '{print $1}')" + copiedHash="$(ssh root@$dDevice sha256sum "/tmp/$imgName" | awk '{print $1}')" + + [ "X$origHash" != "X$copiedHash" ] && echo "Hash mismatch" && return -1 + + # Do not use -n as this will erease IP confifuration for hilink_hlk-7621a-evb + ssh root@$dDevice "sysupgrade /tmp/$imgName" + + # Wait the detached flashing to start + sleep 10 +} + +# Wait for a device to be ready after flashing +function dWait() +{ + dAddress="$1" + mInterval="10s" + mTryMax="20" + + function mTest() + { + dUptime="$(ssh root@$dAddress cat /proc/uptime)" + [ "0$(echo $dUptime | awk -F. '{print $1}')" -gt "100" ] + } + + for mTry in $(seq $mTryMax -1 1) ; do + mTest && return $? || sleep $mInterval $mTry + done + + # Failure after max try + return -1 +} + +function wait_all() +{ +# dWait ${youhuaIpll} +# dWait ${dax1Ipll} +# return + +# dWait ${hlk1Ipll} +# dWait ${hlk2Ipll} +# return + +# dWait ${dax1Ipll} +# dWait ${dax2Ipll} +# return + + dWait ${verdeIP} +# dWait ${neroIP} +# dWait ${bluIP} +# dWait ${bianco43IP} +} + +function dConf() +{ + dAddress="$1" + dHostName="$2" + dHostIPv4="$3" + + cat << EOF | ssh root@${dAddress} uci batch + + set system.@system[0].hostname="$dHostName" + set network.lan.ipaddr="$dHostIPv4" + + set dhcp.lan.ignore='1' + + set network.curtigghio=interface + set network.curtigghio.proto='none' + set network.curtigghio.auto='1' + + set wireless.radio0.disabled='0' + set wireless.radio0.channel='9' + set wireless.default_radio0.ssid='libre-curtigghio' + set wireless.default_radio0.mode='ap' + set wireless.default_radio0.apup='1' + set wireless.default_radio0.apup_peer_ifname_prefix='wlan0.peer' + set wireless.default_radio0.network='lan' + + set wireless.radio1.disabled='0' + set wireless.default_radio1.ssid='libre-curtigghio' + set wireless.default_radio1.mode='ap' + set wireless.default_radio1.apup='1' + set wireless.default_radio1.apup_peer_ifname_prefix='wlan1.peer' + set wireless.default_radio1.wds_bridge='' + set wireless.default_radio1.network='lan' + + set firewall.@defaults[0].input='ACCEPT' + set firewall.@defaults[0].output='ACCEPT' + set firewall.@defaults[0].forward='ACCEPT' +EOF + + ssh root@${dAddress} uci commit +} + +function conf_all() +{ +# dConf ${youhuaIpll} "OpenWrt-Youhua" "192.168.1.24" +# dConf ${dax1Ipll} "OpenWrt-Dax1" "192.168.1.16" +# return + +# dConf ${hlk1Ipll} "OpenWrt-Hlk1" "169.254.145.20" +# dConf ${hlk2Ipll} "OpenWrt-Hlk2" "169.254.145.22" +# return + +# dConf ${dax1Ipll} "OpenWrt-Dax1" "192.168.1.16" +# dConf ${dax2Ipll} "OpenWrt-Dax2" "192.168.1.18" +# return + + dConf ${verdeIP} "OpenWrt-Verde" "192.168.1.4" +# dConf ${neroIP} "OpenWrt-nero" "192.168.1.10" +# dConf ${bluIP} "OpenWrt-blu" "192.168.1.8" +# dConf ${bianco43IP} "OpenWrt-bianco43" "192.168.1.12" +} + +function flash_all() +{ +# dflash ${hlk1Ipll} "${OPENWRT_BUILD_DIR}/bin/targets/ramips/mt7621/openwrt-ramips-mt7621-hilink_hlk-7621a-evb-squashfs-sysupgrade.bin" +# dflash ${hlk2Ipll} "${OPENWRT_BUILD_DIR}/bin/targets/ramips/mt7621/openwrt-ramips-mt7621-hilink_hlk-7621a-evb-squashfs-sysupgrade.bin" + +# dflash ${dax1Ipll} "${OPENWRT_BUILD_DIR}/bin/targets/ramips/mt7621/openwrt-ramips-mt7621-dlink_dap-x1860-a1-squashfs-sysupgrade.bin" +# dflash ${dax2Ipll} "${OPENWRT_BUILD_DIR}/bin/targets/ramips/mt7621/openwrt-ramips-mt7621-dlink_dap-x1860-a1-squashfs-sysupgrade.bin" + + dflash ${verdeIP} "${OPENWRT_BUILD_DIR}/bin/targets/ath79/generic/openwrt-ath79-generic-tplink_tl-wdr3600-v1-squashfs-sysupgrade.bin" +# dflash ${neroIP} "${OPENWRT_BUILD_DIR}/bin/targets/ath79/generic/openwrt-ath79-generic-tplink_tl-wdr3600-v1-squashfs-sysupgrade.bin" +# dflash ${bluIP} "${OPENWRT_BUILD_DIR}/bin/targets/ath79/generic/openwrt-ath79-generic-tplink_tl-wdr3600-v1-squashfs-sysupgrade.bin" +# dflash ${bianco43IP} "${OPENWRT_BUILD_DIR}/bin/targets/ath79/generic/openwrt-ath79-generic-tplink_tl-wdr4300-v1-squashfs-sysupgrade.bin" + +# dflash ${youhuaIpll} "${OPENWRT_BUILD_DIR}/bin/targets/ramips/mt7621/openwrt-ramips-mt7621-youhua_wr1200js-squashfs-sysupgrade.bin" + + wait_all + + conf_all + +# ssh root@${hlk1Ipll} reboot +# ssh root@${hlk2Ipll} reboot + +# ssh root@${dax1Ipll} reboot +# ssh root@${dax2Ipll} reboot + + ssh root@${verdeIP} reboot +# ssh root@${neroIP} reboot +# ssh root@${bluIP} reboot +# ssh root@${bianco43IP} reboot + +# ssh root@${youhuaIpll} reboot +} + +function dev_packages_paths() +{ + echo package/feeds/libremesh/lime-system \ + package/feeds/libremesh/lime-proto-batadv \ + package/feeds/libremesh/lime-proto-babeld + +# package/feeds/libremesh/lime-proto-anygw + +# echo package/network/config/netifd +# package/network/config/wifi-scripts \ +# package/network/services/hostapd +} + +function clean_packages() +{ + pushd "$OPENWRT_BUILD_DIR" + + for mPackagePath in $(dev_packages_paths) ; do + make $mPackagePath/clean + done + + popd +} + +function build_packages() +{ + clean_packages + + pushd "$OPENWRT_BUILD_DIR" + + for mPackagePath in $(dev_packages_paths); do + make $mPackagePath/compile || + { + make $mPackagePath/compile -j1 V=sc + return -1 + } + done + + popd +} + +function upgrade_packages() +{ + local dAddress="$1" + local dPkgArch="${2:-mipsel_24kc}" + + local mInstalls="" + + for mPackageName in $(dev_packages_paths) ; do + mPackageName="$(basename "$mPackageName")" + + local mPkgPath="$(ls "$OPENWRT_BUILD_DIR/bin/packages/$dPkgArch/"*"/$mPackageName"*.ipk | head -n 1)" + scp -O "$mPkgPath" root@[${dAddress}]:/tmp/ + + mInstalls="$mInstalls \"/tmp/$(basename $mPkgPath)\"" + done + + ssh root@${dAddress} "opkg install --force-reinstall $mInstalls && reboot" +} + +function upgrade_packages_all() +{ +# upgrade_packages ${hlk1Ipll} +# upgrade_packages ${hlk2Ipll} + +# upgrade_packages ${dax1Ipll} +# upgrade_packages ${dax2Ipll} + + upgrade_packages $verdeIP mips_24kc +# upgrade_packages ${neroIP} mips_24kc +# upgrade_packages $bluIP mips_24kc +# upgrade_packages ${bianco43IP} mips_24kc + +# upgrade_packages ${youhuaIpll} + + sleep 5s + + wait_all +} + +function errcho() { >&2 echo $@; } + +function dTestMulticast() +{ + local dAddress="$1" + + [ "0$(ssh root@${dAddress} ping6 -c 4 ff02::1%phy0-ap0.sta1 | \ + grep duplicates | awk '{print $7}')" -gt "1" ] || + { errcho dTestMulticast $dAddress Failed ; return -1 ; } + errcho dTestMulticast $dAddress Success +} + +function dTestIperf3() +{ + local clientAddress="$1" + local servAddress="$2" + local servIfaceAddress="$3" + + ssh root@${servAddress} iperf3 -s + ssh root@${clientAddress} iperf3 -c $servIfaceAddress +} + +function dTestUbusDev() +{ + local dAddress="$1" + +# ssh root@${dAddress} reboot ; sleep 10 + +# dWait ${dAddress} + + ssh root@${dAddress} << REMOTE_HOST_EOS + ubus call network add_dynamic_device '{"name":"wlan0_peer1_47", "type":"8021ad", "ifname":"wlan0.peer1", "vid":"47"}' + ubus call network add_dynamic '{"name":"wlan0_peer1_47", "proto":"static", "auto":1, "device":"nomestru", "ipaddr":"169.254.145.20", "netmask":"255.255.255.255"}' + ubus call network.interface.wlan0_peer1_47 up + ubus call network.device status '{"name":"wlan0_peer1_47"}' + + ip address show wlan0_peer1_47 +REMOTE_HOST_EOS +} + +function DO_NOT_CALL_prepareHostapdChangesForSubmission() +{ + # Just a bunch of commands I used, not a proper function the commands + # requires developer interaction + # See https://openwrt.org/docs/guide-developer/toolchain/use-patches-with-buildsystem + + pushd "$HOSTAPD_REPO_DIR" + # -3 number of commit for which to create patches + git format-patch -3 HEAD + popd + + pushd "$OPENWRT_REPO_DIR" + make package/network/services/hostapd/{clean,prepare} V=s QUILT=1 + + pushd "$OPENWRT_REPO_DIR/build_dir/target-mips_24kc_musl/hostapd-wpad-basic-mbedtls/hostapd-2024.03.09~695277a5" + quilt push -a + + mLastIndex="$(quilt series | tail -n 1 | awk -F- '{print $1}')" + for mPatch in $(ls "$HOSTAPD_REPO_DIR"/*.patch) ; do + mLastIndex=$((mLastIndex+10)) + mNewPatchPath="/tmp/$mLastIndex-$(basename $mPatch | cut -c 6-)" + mv "$mPatch" "$mNewPatchPath" + quilt import "$mNewPatchPath" + quilt push -a + quilt refresh + rm "$mNewPatchPath" + done + + popd + + make package/network/services/hostapd/update V=s + make package/network/services/hostapd/refresh V=s + + + popd +} + +#fBuildDapX +#fBuildYouhua + +#fBuildHlk + +#flash_all + +build_packages +upgrade_packages_all + +#dTestUbusDev ${youhuaIpll} +#dTestUbusDev ${hlk1Ipll} + +#conf_all + +#dTestUbusDev ${verdeIP} + + +#dTestMulticast ${dax1Ipll} +#dTestMulticast ${dax2Ipll} + +# dTestMulticast $bluIP +# dTestMulticast $verdeIP +# dTestMulticast $bianco43IP +# dTestMulticast $neroIP diff --git a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua index db01f6b5e..31bf8ab9c 100644 --- a/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua +++ b/packages/lime-proto-anygw/files/usr/lib/lua/lime/proto/anygw.lua @@ -139,4 +139,6 @@ protocol direct { return base_conf end +function anygw.runOnDevice(linuxDev, args) end + return anygw diff --git a/packages/lime-proto-babeld/files/usr/lib/lua/lime/proto/babeld.lua b/packages/lime-proto-babeld/files/usr/lib/lua/lime/proto/babeld.lua index a4fde093a..1fb4735c0 100644 --- a/packages/lime-proto-babeld/files/usr/lib/lua/lime/proto/babeld.lua +++ b/packages/lime-proto-babeld/files/usr/lib/lua/lime/proto/babeld.lua @@ -129,4 +129,18 @@ function babeld.setup_interface(ifname, args) uci:save("babeld") end +function babeld.runOnDevice(linuxDev, args) + utils.log("lime.proto.babeld.runOnDevice(%s, ...)", linuxDev) + + local vlanId = args[2] or 17 + local vlanProto = args[3] or "8021ad" + + local vlanDev = network.createVlan(linuxDev, vlanId, vlanProto) + network.createStatic(vlanDev) + + local libubus = require("ubus") + local ubus = libubus.connect() + ubus:call('babeld', 'add_interface', { ifname = vlanDev }) +end + return babeld 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 523ab4f39..87f53689c 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 @@ -99,5 +99,42 @@ function batadv.setup_interface(ifname, args) uci:save("network") end +function batadv.runOnDevice(linuxDev, args) + args = args or {} + local vlanId = args[2] or "%N1" + local vlanProto = args[3] or "8021ad" + + utils.log("lime.proto.batadv.runOnDevice(%s, ...)", linuxDev) + + + local mtu = 1532 + + if not tonumber(vlanId) then + vlanId = 29 + (utils.applyNetTemplate10(vlanId) - 13) % 256 + end + + local devName = network.createVlan(linuxDev, vlanId, vlanProto) + local ifName = network.limeIfNamePrefix..linuxDev .. "_batadv" + + local ifaceConf = { + name = ifName, + proto = "batadv_hardif", + auto = "1", + device = devName, + master = "bat0" + } + + local libubus = require("ubus"); + local ubus = libubus.connect() + ubus:call('network', 'add_dynamic', ifaceConf) + ubus:call('network.interface.'..ifName, 'up', {}) + + +--! 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) +end return batadv diff --git a/packages/lime-system/Makefile b/packages/lime-system/Makefile index d327c9c54..6e001a5fe 100644 --- a/packages/lime-system/Makefile +++ b/packages/lime-system/Makefile @@ -23,7 +23,7 @@ LIME_DESCRIPTION:=$(LIME_ID) $(LIME_RELEASE) $(LIME_CODENAME) ($(LIME_BRANCH) re include $(INCLUDE_DIR)/package.mk define Package/$(PKG_NAME) - TITLE:=libremesh system files + TITLE:=LibreMesh system core CATEGORY:=LibreMesh MAINTAINER:=Gioacchino Mazzurco URL:=http://libremesh.org @@ -32,7 +32,8 @@ define Package/$(PKG_NAME) endef define Package/$(PKG_NAME)/description - Basic system files for LiMe node + LibreMesh is a modular meta-firmare this package provide the core of it + which articulates all LiMe modules around it endef define Build/Compile diff --git a/packages/lime-system/files/etc/config/lime-defaults b/packages/lime-system/files/etc/config/lime-defaults index 5f5c4a31f..954696ab8 100644 --- a/packages/lime-system/files/etc/config/lime-defaults +++ b/packages/lime-system/files/etc/config/lime-defaults @@ -58,6 +58,7 @@ config lime wifi option apname_ssid 'LibreMesh.org/%H' option adhoc_ssid 'LiMe' option adhoc_bssid 'ca:fe:00:c0:ff:ee' + option apup_ssid 'LibreMesh.org' option ieee80211s_mesh_fwding '0' option ieee80211s_mesh_id 'LiMe' option unstuck_interval '10' diff --git a/packages/lime-system/files/etc/init.d/limed b/packages/lime-system/files/etc/init.d/limed new file mode 100755 index 000000000..47d8792f3 --- /dev/null +++ b/packages/lime-system/files/etc/init.d/limed @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=15 + +start_service() +{ + procd_open_instance + procd_set_param command /usr/bin/limed +## procd_set_param respawn + procd_set_param stderr 1 + procd_set_param term_timeout 10 + procd_close_instance +} diff --git a/packages/lime-system/files/usr/bin/limed b/packages/lime-system/files/usr/bin/limed new file mode 100755 index 000000000..bbc1e1936 --- /dev/null +++ b/packages/lime-system/files/usr/bin/limed @@ -0,0 +1,87 @@ +#!/usr/bin/lua + +--! LibreMesh community mesh networks meta-firmware +--! +--! Copyright (C) 2024 Gioacchino Mazzurco +--! Copyright (C) 2024 Asociación Civil Altermundi +--! +--! SPDX-License-Identifier: AGPL-3.0-only + +local config = require("lime.config") + +local limed = {}; + +limed.__PRIVATE_APUP_ENABLED = nil + +function limed.APUP_ENABLED() + if limed.__PRIVATE_APUP_ENABLED ~= nil then + return limed.__PRIVATE_APUP_ENABLED + end + + function check_apup_mode_cb(section) + if(section['modes'] == null) then return end + + for _,mode in pairs(section['modes']) do + if(mode == 'apup') then + limed.__PRIVATE_APUP_ENABLED = true; + return limed.__PRIVATE_APUP_ENABLED; + end + end + end + + config.foreach(nil, check_apup_mode_cb) + return limed.__PRIVATE_APUP_ENABLED +end + +-- No need to run if APuP is not enabled in configuration +if not limed.APUP_ENABLED() then os.exit(0) end; + +local uloop = require("uloop"); +local network = require("lime.network") + +local function dumptable(table, nesting) + local nesting = nesting or 1 + if type(table) ~= "table" then + print("dumptable: first argument is expected to be a table but you passed a", type(table), table) + else + if next(table) == nil then + print(table, "empty") + else + for k,v in pairs(table) do + print(string.rep('\t', nesting), k, ' = ', v) + if type(v) == 'table' then dumptable(v, nesting+1) end + end + end + end +end + +local libubus = require("ubus") +local ubus = libubus.connect() + +local peerSubscriber = { + notify = function(nData, nType) + if nType ~= "apup-newpeer" then return end + + print("peerSubscriber:", nType, nData.ifname) + network.createStatic(nData.ifname) + network.runProtocols(nData.ifname) + end +} + +local apupSubscriber = { + notify = function(nData, nType) + if nType ~= "bss.add" then return end + + local apupDev = string.match(nData["name"], "wlan%d+%-apup"); + if not apupDev then return end + + local evPath = "hostapd." .. apupDev + + print("Subscribing:", evPath) + ubus:subscribe(evPath, peerSubscriber) + end +} + +uloop.init(); +ubus:subscribe("hostapd", apupSubscriber) +uloop.run(); diff --git a/packages/lime-system/files/usr/lib/lua/lime/mode/apup.lua b/packages/lime-system/files/usr/lib/lua/lime/mode/apup.lua new file mode 100644 index 000000000..588337e06 --- /dev/null +++ b/packages/lime-system/files/usr/lib/lua/lime/mode/apup.lua @@ -0,0 +1,41 @@ +#!/usr/bin/lua + +--! LibreMesh community mesh networks meta-firmware +--! +--! Copyright (C) 2024 Gioacchino Mazzurco +--! Copyright (C) 2024 Asociación Civil Altermundi +--! +--! SPDX-License-Identifier: AGPL-3.0-only + +local wireless = require("lime.wireless") + +local apup = {} + +function apup.WIFI_MODE() + return "ap" +end + +function apup.WIFI_MODE_SUFFIX() + return "up" +end + +function apup.PEER_SUFFIX() + return "peer" +end + +function apup.setup_radio(radio, args) +--! checks("table", "?table") + + args["network"] = "lan" + args["apup"] = "1" + args["apup_peer_ifname_prefix"] = + wireless.calcIfname(radio[".name"], apup.PEER_SUFFIX(), "") + + return wireless.createBaseWirelessIface( + radio, apup.WIFI_MODE(), apup.WIFI_MODE_SUFFIX(), args ) +end + +--! TODO: port all modes to .WIFI_MODE() +apup.wifi_mode="ap" + +return apup 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 1d9856051..cf4edfaf0 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/network.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/network.lua @@ -2,8 +2,8 @@ --! LibreMesh community mesh networks meta-firmware --! ---! Copyright (C) 2013-2023 Gioacchino Mazzurco ---! Copyright (C) 2023 Asociación Civil Altermundi +--! Copyright (C) 2013-2024 Gioacchino Mazzurco +--! Copyright (C) 2023-2024 Asociación Civil Altermundi --! --! SPDX-License-Identifier: AGPL-3.0-only @@ -15,13 +15,21 @@ local fs = require("nixio.fs") local config = require("lime.config") local utils = require("lime.utils") -network.limeIfNamePrefix="lm_net_" -network.protoParamsSeparator=":" -network.protoVlanSeparator="_" + +function network.PROTO_PARAM_SEPARATOR() return ":" end +function network.PROTO_VLAN_SEPARATOR() return "_" end +function network.LIME_UCI_IFNAME_PREFIX() return "lm_net_" end + network.MTU_ETH = 1500 network.MTU_ETH_WITH_VLAN = network.MTU_ETH - 4 +-- Deprecated use corresponding functions instead +network.protoParamsSeparator=":" +network.protoVlanSeparator="_" +network.limeIfNamePrefix="lm_net_" + + function network.get_mac(ifname) local _, macaddr = next(network.get_own_macs(ifname)) return utils.split(macaddr, ":") @@ -268,7 +276,7 @@ function network.scandevices() end end - if dev:match("^wlan%d+"..wireless.wifiModeSeparator.."%w+$") then + if dev:match("^wlan%d+"..wireless.WIFI_MODE_SEPARATOR().."%w+$") then devices[dev] = {} utils.log( "network.scandevices.dev_parser found WiFi device %s", dev ) @@ -550,4 +558,94 @@ function network.createMacvlanIface(baseIfname, linuxName, argsDev, argsIf) return owrtInterfaceName, linuxName, owrtDeviceName end +--! Create a static interface at runtime via ubus +function network.createStatic(linuxBaseIfname) + local ipv4, ipv6 = network.primary_address() + local ubusIfaceName = network.sanitizeIfaceName( + network.LIME_UCI_IFNAME_PREFIX()..linuxBaseIfname.."_static") + local ifaceConf = { + name = ubusIfaceName, + proto = "static", + auto = "1", + ifname = linuxBaseIfname, + ipaddr = ipv4:host():string(), + netmask = "255.255.255.255" + } + + print('network', 'add_dynamic') + utils.dumptable(ifaceConf) + + local libubus = require("ubus") + local ubus = libubus.connect() + ubus:call('network', 'add_dynamic', ifaceConf) + ubus:call('network.interface.'..ifaceConf.name, 'up', {}) + +--! TODO: As of today ubus silently fails to properly setup the interface, +--! subsequent status query return NO_DEVICE error +--! ubus -v call network.interface.lm_net_lm_net_wlan0_peer1_static status +--! { +--! "up": false, +--! "pending": false, +--! "available": false, +--! "autostart": true, +--! "dynamic": true, +--! "proto": "static", +--! "data": { +--! +--! }, +--! "errors": [ +--! { +--! "subsystem": "interface", +--! "code": "NO_DEVICE" +--! } +--! ] +--! } +--! +--! ATM work around the problem configuring IP addresses via ip command + + utils.unsafe_shell("ip link set up dev "..ifaceConf.ifname) + utils.unsafe_shell("ip address add "..ifaceConf.ipaddr.."/32 dev "..ifaceConf.ifname) + + return ifaceConf.name +end + +--! Create a vlan at runtime via ubus +function network.createVlan(linuxBaseIfname, vid, vlanProtocol) + local vlanConf = { + name = linuxBaseIfname .. network.PROTO_VLAN_SEPARATOR() .. vid, + type = vlanProtocol or "8021ad", + ifname = linuxBaseIfname, + vid = vid + } + + utils.log("lime.network.createVlan(%s, ...)", linuxBaseIfname) + utils.dumptable(vlanConf) + + local libubus = require("ubus") + local ubus = libubus.connect() + ubus:call('network', 'add_dynamic_device', vlanConf) + +--! TODO: as of today ubus silently fails to properly creating a device +--! dinamycally work around it by using ip command instead + utils.unsafe_shell("ip link add name "..vlanConf.name.." link "..vlanConf.ifname.." type vlan proto 802.1ad id "..vlanConf.vid) + + return vlanConf.name +end + +--! Run protocols at runtime on top of linux network devices +-- TODO: probably some code between here and configure might be deduplicaded +function network.runProtocols(linuxBaseIfname) + utils.log("lime.network.runProtocols(%s, ...)", linuxBaseIfname) + local protoConfs = config.get("network", "protocols") + for _,protoConf in pairs(protoConfs) do + local args = utils.split(protoConf, network.PROTO_PARAM_SEPARATOR()) + local protoModule = "lime.proto."..args[1] + if utils.isModuleAvailable(protoModule) then + local proto = require(protoModule) + xpcall(function() proto.runOnDevice(linuxBaseIfname, args) end, + function(errmsg) print(errmsg) ; print(debug.traceback()) end) + end + end +end + return network diff --git a/packages/lime-system/files/usr/lib/lua/lime/proto/adhoc.lua b/packages/lime-system/files/usr/lib/lua/lime/proto/adhoc.lua index 1e7e99cbf..19402fedd 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/proto/adhoc.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/proto/adhoc.lua @@ -26,4 +26,6 @@ function adhoc.setup_interface(ifname, args) end end +function adhoc.runOnDevice(linuxDev, args) end + return adhoc diff --git a/packages/lime-system/files/usr/lib/lua/lime/proto/apbb.lua b/packages/lime-system/files/usr/lib/lua/lime/proto/apbb.lua index 1e767b159..26d8b8c0f 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/proto/apbb.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/proto/apbb.lua @@ -25,4 +25,6 @@ function apbb.setup_interface(ifname, args) end end +function apbb.runOnDevice(linuxDev, args) end + return apbb diff --git a/packages/lime-system/files/usr/lib/lua/lime/proto/client.lua b/packages/lime-system/files/usr/lib/lua/lime/proto/client.lua index f26088770..ff4137488 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/proto/client.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/proto/client.lua @@ -25,4 +25,6 @@ function client.setup_interface(ifname, args) end end +function client.runOnDevice(linuxDev, args) end + return client diff --git a/packages/lime-system/files/usr/lib/lua/lime/proto/ieee80211s.lua b/packages/lime-system/files/usr/lib/lua/lime/proto/ieee80211s.lua index cfcc3987b..53eb948b2 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/proto/ieee80211s.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/proto/ieee80211s.lua @@ -25,4 +25,6 @@ function ieee80211s.setup_interface(ifname, args) end end +function ieee80211s.runOnDevice(linuxDev, args) end + return ieee80211s diff --git a/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua b/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua index 9e2c1e6a8..208a598d2 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/proto/lan.lua @@ -91,4 +91,6 @@ protocol direct { return base_conf end +function lan.runOnDevice(linuxDev, args) end + return lan 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 b175a8ee6..25b33dbb1 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/utils.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/utils.lua @@ -329,7 +329,7 @@ function utils.shell_quote(s) end --! Excutes a shell command, waits for completion and returns stdout. ---! Warning! Use this function carefully as it could be exploted if used with +--! Warning! Use this function carefully as it could be exploited if used with --! untrusted input. Always use function utils.shell_quote() to escape untrusted --! input. function utils.unsafe_shell(command) @@ -602,4 +602,20 @@ function utils.is_dsa() return false end +function utils.dumptable(table, nesting) + local nesting = nesting or 1 + if type(table) ~= "table" then + print("dumptable: first argument is expected to be a table but you passed a", type(table), table) + else + if next(table) == nil then + print(table, "empty") + else + for k,v in pairs(table) do + print(string.rep('\t', nesting), k, ' = ', v) + if type(v) == 'table' then dumptable(v, nesting+1) end + end + end + end +end + return utils diff --git a/packages/lime-system/files/usr/lib/lua/lime/wireless.lua b/packages/lime-system/files/usr/lib/lua/lime/wireless.lua index 79e87236e..acd92ba27 100644 --- a/packages/lime-system/files/usr/lib/lua/lime/wireless.lua +++ b/packages/lime-system/files/usr/lib/lua/lime/wireless.lua @@ -9,7 +9,10 @@ local iwinfo = require("iwinfo") wireless = {} wireless.limeIfNamePrefix="lm_" -wireless.wifiModeSeparator="-" + +function wireless.WIFI_MODE_SEPARATOR() + return "-" +end function wireless.get_phy_mac(phy) local path = "/sys/class/ieee80211/"..phy.."/macaddress" @@ -97,13 +100,17 @@ function wireless.get_radio_ifaces(radio) return ifaces end +function wireless.calcIfname(radioName, mode, nameSuffix) + local phyIndex = tostring(utils.indexFromName(radioName)) + return "wlan"..phyIndex..wireless.WIFI_MODE_SEPARATOR()..mode..nameSuffix +end + function wireless.createBaseWirelessIface(radio, mode, nameSuffix, extras) --! checks("table", "string", "?string", "?table") --! checks(...) come from http://lua-users.org/wiki/LuaTypeChecking -> https://github.com/fab13n/checks nameSuffix = nameSuffix or "" local radioName = radio[".name"] - local phyIndex = tostring(utils.indexFromName(radioName)) - local ifname = "wlan"..phyIndex..wireless.wifiModeSeparator..mode..nameSuffix + local ifname = wireless.calcIfname(radioName, mode, nameSuffix) --! sanitize generated ifname for constructing uci section name --! because only alphanumeric and underscores are allowed local wirelessInterfaceName = wireless.limeIfNamePrefix..ifname:gsub("[^%w_]", "_").."_"..radioName