aboutsummaryrefslogtreecommitdiffstats
path: root/package/network
diff options
context:
space:
mode:
Diffstat (limited to 'package/network')
-rw-r--r--package/network/config/firewall/Makefile16
-rw-r--r--package/network/config/firewall/files/firewall.config6
-rw-r--r--package/network/config/firewall4/Makefile15
-rw-r--r--package/network/config/ipip/Makefile2
-rwxr-xr-xpackage/network/config/ipip/files/ipip.sh7
-rw-r--r--package/network/config/ltq-adsl-app/Makefile5
-rw-r--r--package/network/config/ltq-adsl-app/patches/100-add-more-script-notifications.patch2
-rw-r--r--package/network/config/ltq-vdsl-app/patches/200-autoboot.patch11
-rw-r--r--package/network/config/ltq-vdsl-vr11-app/Makefile92
-rw-r--r--package/network/config/ltq-vdsl-vr11-app/files/dsl_control264
-rwxr-xr-xpackage/network/config/ltq-vdsl-vr11-app/files/dsl_cpe_pipe.sh (renamed from package/network/config/ltq-vdsl-app/files/dsl_cpe_pipe.sh)0
-rw-r--r--package/network/config/ltq-vdsl-vr11-app/patches/100-compat.patch (renamed from package/network/config/ltq-vdsl-app/patches/100-compat.patch)11
-rw-r--r--package/network/config/ltq-vdsl-vr11-app/patches/101-warnings.patch87
-rw-r--r--package/network/config/ltq-vdsl-vr11-app/patches/200-autoboot.patch85
-rw-r--r--package/network/config/ltq-vdsl-vr11-app/patches/300-ubus.patch50
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/Makefile (renamed from package/network/config/ltq-vdsl-app/Makefile)30
-rwxr-xr-xpackage/network/config/ltq-vdsl-vr9-app/files/10_atm.sh (renamed from package/network/config/ltq-vdsl-app/files/10_atm.sh)0
-rwxr-xr-xpackage/network/config/ltq-vdsl-vr9-app/files/10_ptm.sh (renamed from package/network/config/ltq-vdsl-app/files/10_ptm.sh)0
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/files/dsl_control (renamed from package/network/config/ltq-vdsl-app/files/dsl_control)20
-rwxr-xr-xpackage/network/config/ltq-vdsl-vr9-app/files/dsl_cpe_pipe.sh18
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/patches/100-compat.patch11
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/patches/101-musl.patch (renamed from package/network/config/ltq-vdsl-app/patches/101-musl.patch)0
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/patches/200-autoboot.patch86
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/patches/201-sigterm.patch (renamed from package/network/config/ltq-vdsl-app/patches/201-sigterm.patch)2
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/patches/300-ubus.patch (renamed from package/network/config/ltq-vdsl-app/patches/300-ubus.patch)4
-rw-r--r--package/network/config/ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c (renamed from package/network/config/ltq-vdsl-app/src/src/dsl_cpe_ubus.c)378
-rw-r--r--package/network/config/netifd/Makefile20
-rwxr-xr-xpackage/network/config/netifd/files/etc/init.d/packet_steering18
-rwxr-xr-xpackage/network/config/netifd/files/lib/netifd/dhcp.script7
-rwxr-xr-xpackage/network/config/netifd/files/lib/netifd/proto/dhcp.sh4
-rwxr-xr-xpackage/network/config/netifd/files/sbin/ifup33
-rwxr-xr-x[-rw-r--r--]package/network/config/netifd/files/usr/libexec/network/packet-steering.sh (renamed from package/network/config/netifd/files/etc/hotplug.d/net/20-smp-packet-steering)7
-rw-r--r--package/network/config/qos-scripts/Makefile2
-rwxr-xr-xpackage/network/config/qos-scripts/files/usr/bin/qos-start2
-rwxr-xr-xpackage/network/config/qos-scripts/files/usr/bin/qos-stat2
-rwxr-xr-xpackage/network/config/qos-scripts/files/usr/lib/qos/generate.sh13
-rw-r--r--package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk1
-rw-r--r--package/network/config/qosify/Makefile76
-rw-r--r--package/network/config/qosify/files/qosify-defaults.conf17
-rw-r--r--package/network/config/qosify/files/qosify-status70
-rw-r--r--package/network/config/qosify/files/qosify.conf48
-rw-r--r--package/network/config/qosify/files/qosify.hotplug2
-rw-r--r--package/network/config/qosify/files/qosify.init171
-rw-r--r--package/network/config/swconfig/Makefile5
-rw-r--r--package/network/config/swconfig/src/cli.c23
-rw-r--r--package/network/config/swconfig/src/uci.c59
-rw-r--r--package/network/config/vti/Makefile43
-rw-r--r--package/network/config/wifi-scripts/Makefile45
-rw-r--r--package/network/config/wifi-scripts/files/etc/hotplug.d/ieee80211/10-wifi-detect5
-rw-r--r--package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh (renamed from package/network/services/hostapd/files/hostapd.sh)311
-rw-r--r--package/network/config/wifi-scripts/files/lib/netifd/netifd-wireless.sh439
-rwxr-xr-xpackage/network/config/wifi-scripts/files/lib/netifd/wireless/mac80211.sh1197
-rw-r--r--package/network/config/wifi-scripts/files/lib/wifi/mac80211.sh217
-rwxr-xr-xpackage/network/config/wifi-scripts/files/sbin/wifi273
-rw-r--r--package/network/config/wifi-scripts/files/usr/share/hostap/common.uc373
-rw-r--r--package/network/config/wifi-scripts/files/usr/share/hostap/wdev.uc185
-rw-r--r--package/network/config/wifi-scripts/files/usr/share/hostap/wifi-detect.uc155
-rw-r--r--package/network/ipv6/464xlat/Makefile2
-rwxr-xr-xpackage/network/ipv6/464xlat/files/464xlat.sh3
-rw-r--r--package/network/ipv6/6in4/Makefile2
-rw-r--r--package/network/ipv6/6rd/Makefile2
-rw-r--r--package/network/ipv6/6rd/files/6rd.sh4
-rw-r--r--package/network/ipv6/odhcp6c/Makefile8
-rwxr-xr-xpackage/network/ipv6/odhcp6c/files/dhcpv6.sh11
-rw-r--r--package/network/ipv6/thc-ipv6/Makefile6
-rw-r--r--package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch7
-rw-r--r--package/network/ipv6/thc-ipv6/patches/101-remove-march-native.patch (renamed from package/network/ipv6/thc-ipv6/patches/000-cflags_override.patch)15
-rw-r--r--package/network/services/bridger/Makefile62
-rw-r--r--package/network/services/bridger/files/bridger.conf3
-rw-r--r--package/network/services/bridger/files/bridger.init44
-rw-r--r--package/network/services/dnsmasq/Makefile25
-rwxr-xr-xpackage/network/services/dnsmasq/files/50-dnsmasq-migrate-ipset.sh32
-rw-r--r--package/network/services/dnsmasq/files/dhcp.conf4
-rwxr-xr-x[-rw-r--r--]package/network/services/dnsmasq/files/dnsmasq.init190
-rw-r--r--package/network/services/dnsmasq/files/dnsmasq_acl.json3
-rw-r--r--package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch8
-rw-r--r--package/network/services/dnsmasq/patches/200-ubus_dns.patch282
-rw-r--r--package/network/services/dropbear/Config.in117
-rw-r--r--package/network/services/dropbear/Makefile120
-rwxr-xr-xpackage/network/services/dropbear/files/dropbear.failsafe57
-rwxr-xr-xpackage/network/services/dropbear/files/dropbear.init340
-rw-r--r--package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch104
-rw-r--r--package/network/services/dropbear/patches/002-fix-y2038-issues.patch198
-rw-r--r--package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch25
-rw-r--r--package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch24
-rw-r--r--package/network/services/dropbear/patches/005-const-parameter-mp_int.patch123
-rw-r--r--package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch21
-rw-r--r--package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch29
-rw-r--r--package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch94
-rw-r--r--package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch27
-rw-r--r--package/network/services/dropbear/patches/010-remove-SO_LINGER.patch39
-rw-r--r--package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch147
-rw-r--r--package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch50
-rw-r--r--package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch74
-rw-r--r--package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch60
-rw-r--r--package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch121
-rw-r--r--package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch35
-rw-r--r--package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch32
-rw-r--r--package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch33
-rw-r--r--package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch34
-rw-r--r--package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch33
-rw-r--r--package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch216
-rw-r--r--package/network/services/dropbear/patches/100-pubkey_path.patch116
-rw-r--r--package/network/services/dropbear/patches/110-change_user.patch2
-rw-r--r--package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch14
-rw-r--r--package/network/services/dropbear/patches/140-disable_assert.patch2
-rw-r--r--package/network/services/dropbear/patches/160-lto-jobserver.patch4
-rw-r--r--package/network/services/dropbear/patches/600-allow-blank-root-password.patch2
-rw-r--r--package/network/services/dropbear/patches/900-configure-hardening.patch35
-rw-r--r--package/network/services/dropbear/patches/901-bundled-libs-cflags.patch71
-rw-r--r--package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch16
-rw-r--r--package/network/services/hostapd/Config.in39
-rw-r--r--package/network/services/hostapd/Makefile257
-rw-r--r--package/network/services/hostapd/README.md419
-rw-r--r--package/network/services/hostapd/files/dhcp-get-server.sh2
-rw-r--r--package/network/services/hostapd/files/hostapd-basic.config5
-rw-r--r--package/network/services/hostapd/files/hostapd-full.config11
-rw-r--r--package/network/services/hostapd/files/hostapd-mini.config3
-rw-r--r--package/network/services/hostapd/files/hostapd.uc901
-rw-r--r--package/network/services/hostapd/files/radius.clients1
-rw-r--r--package/network/services/hostapd/files/radius.config9
-rw-r--r--package/network/services/hostapd/files/radius.init42
-rw-r--r--package/network/services/hostapd/files/radius.users14
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant-basic.config4
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant-full.config6
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant-mini.config2
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant-p2p.config6
-rw-r--r--package/network/services/hostapd/files/wpa_supplicant.uc349
-rw-r--r--package/network/services/hostapd/files/wpad.init2
-rw-r--r--package/network/services/hostapd/files/wpad_acl.json10
-rw-r--r--package/network/services/hostapd/files/wps-hotplug.sh21
-rw-r--r--package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch6
-rw-r--r--package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch105
-rw-r--r--package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch10
-rw-r--r--package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch219
-rw-r--r--package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch4
-rw-r--r--package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch2
-rw-r--r--package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch19
-rw-r--r--package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch275
-rw-r--r--package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch34
-rw-r--r--package/network/services/hostapd/patches/050-build_fix.patch20
-rw-r--r--package/network/services/hostapd/patches/100-daemonize_fix.patch97
-rw-r--r--package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch8051
-rw-r--r--package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch114
-rw-r--r--package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch421
-rw-r--r--package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch91
-rw-r--r--package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch1358
-rw-r--r--package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch45
-rw-r--r--package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch26
-rw-r--r--package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch141
-rw-r--r--package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch20
-rw-r--r--package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch18
-rw-r--r--package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch34
-rw-r--r--package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch28
-rw-r--r--package/network/services/hostapd/patches/200-multicall.patch60
-rw-r--r--package/network/services/hostapd/patches/300-noscan.patch10
-rw-r--r--package/network/services/hostapd/patches/301-mesh-noscan.patch62
-rw-r--r--package/network/services/hostapd/patches/310-rescan_immediately.patch2
-rw-r--r--package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch6
-rw-r--r--package/network/services/hostapd/patches/340-reload_freq_change.patch75
-rw-r--r--package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch2
-rw-r--r--package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch43
-rw-r--r--package/network/services/hostapd/patches/360-ctrl_iface_reload.patch106
-rw-r--r--package/network/services/hostapd/patches/370-ap_sta_support.patch392
-rw-r--r--package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch86
-rw-r--r--package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch2
-rw-r--r--package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch4
-rw-r--r--package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch2
-rw-r--r--package/network/services/hostapd/patches/410-limit_debug_messages.patch22
-rw-r--r--package/network/services/hostapd/patches/420-indicate-features.patch35
-rw-r--r--package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch12
-rw-r--r--package/network/services/hostapd/patches/432-missing-typedef.patch10
-rw-r--r--package/network/services/hostapd/patches/450-scan_wait.patch73
-rw-r--r--package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch10
-rw-r--r--package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch59
-rw-r--r--package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch8
-rw-r--r--package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch22
-rw-r--r--package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch24
-rw-r--r--package/network/services/hostapd/patches/470-survey_data_fallback.patch35
-rw-r--r--package/network/services/hostapd/patches/500-lto-jobserver-support.patch6
-rw-r--r--package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch92
-rw-r--r--package/network/services/hostapd/patches/600-ubus_support.patch406
-rw-r--r--package/network/services/hostapd/patches/601-ucode_support.patch671
-rw-r--r--package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch33
-rw-r--r--package/network/services/hostapd/patches/700-wifi-reload.patch220
-rw-r--r--package/network/services/hostapd/patches/701-reload_config_inline.patch33
-rw-r--r--package/network/services/hostapd/patches/710-vlan_no_bridge.patch4
-rw-r--r--package/network/services/hostapd/patches/711-wds_bridge_force.patch22
-rw-r--r--package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch30
-rw-r--r--package/network/services/hostapd/patches/720-iface_max_num_sta.patch21
-rw-r--r--package/network/services/hostapd/patches/730-ft_iface.patch8
-rw-r--r--package/network/services/hostapd/patches/740-snoop_iface.patch139
-rw-r--r--package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch97
-rw-r--r--package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch12
-rw-r--r--package/network/services/hostapd/patches/760-dynamic_own_ip.patch109
-rw-r--r--package/network/services/hostapd/patches/761-shared_das_port.patch298
-rw-r--r--package/network/services/hostapd/patches/770-radius_server.patch154
-rw-r--r--package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch33
-rw-r--r--package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch63
-rw-r--r--package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch62
-rw-r--r--package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch25
-rw-r--r--package/network/services/hostapd/src/hostapd/radius.c715
-rw-r--r--package/network/services/hostapd/src/src/ap/ubus.c694
-rw-r--r--package/network/services/hostapd/src/src/ap/ubus.h35
-rw-r--r--package/network/services/hostapd/src/src/ap/ucode.c813
-rw-r--r--package/network/services/hostapd/src/src/ap/ucode.h54
-rw-r--r--package/network/services/hostapd/src/src/utils/build_features.h16
-rw-r--r--package/network/services/hostapd/src/src/utils/ucode.c502
-rw-r--r--package/network/services/hostapd/src/src/utils/ucode.h30
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ubus.c162
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ubus.h11
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ucode.c299
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ucode.h49
-rw-r--r--package/network/services/ipset-dns/Makefile2
-rw-r--r--package/network/services/lldpd/Makefile32
-rw-r--r--package/network/services/lldpd/files/lldpd.init273
-rw-r--r--package/network/services/odhcpd/Makefile8
-rw-r--r--package/network/services/omcproxy/Makefile6
-rw-r--r--package/network/services/ppp/Makefile6
-rwxr-xr-xpackage/network/services/ppp/files/ppp.sh18
-rw-r--r--package/network/services/ppp/patches/140-pppd-Fix-compilation-with-older-glibc-or-kernel-head.patch54
-rw-r--r--package/network/services/ppp/patches/141-Expand-byte-count-statistics-to-64-bits-298.patch518
-rw-r--r--package/network/services/ppp/patches/142-pppd-Add-support-for-registering-ppp-interface-via-L.patch299
-rw-r--r--package/network/services/ppp/patches/143-pppd-Workaround-for-generating-ppp-unit-id-on-Linux-.patch59
-rw-r--r--package/network/services/ppp/patches/144-pppd-Retry-registering-interface-when-on-rtnetlink-E.patch218
-rw-r--r--package/network/services/ppp/patches/208-fix_status_code.patch2
-rw-r--r--package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch4
-rw-r--r--package/network/services/ppp/patches/330-retain_foreign_default_routes.patch2
-rw-r--r--package/network/services/ppp/patches/340-populate_default_gateway.patch4
-rw-r--r--package/network/services/ppp/patches/400-simplify_kernel_checks.patch16
-rw-r--r--package/network/services/ppp/patches/401-no_record_file.patch2
-rw-r--r--package/network/services/ppp/patches/403-no_wtmp.patch4
-rw-r--r--package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch16
-rw-r--r--package/network/services/relayd/Makefile6
-rw-r--r--package/network/services/uhttpd/Makefile54
-rw-r--r--package/network/services/uhttpd/files/ubus.default6
-rw-r--r--package/network/services/uhttpd/files/uhttpd.config8
-rwxr-xr-xpackage/network/services/uhttpd/files/uhttpd.init85
-rw-r--r--package/network/services/umdns/Makefile12
-rw-r--r--package/network/services/umdns/files/umdns.json11
-rw-r--r--package/network/services/unetd/Makefile113
-rw-r--r--package/network/services/unetd/files/unet-dht.init24
-rw-r--r--package/network/services/unetd/files/unetd.init17
-rw-r--r--package/network/services/unetd/files/unetd.sh99
-rw-r--r--package/network/services/ustp/Makefile42
-rw-r--r--package/network/services/ustp/files/ustpd.init14
-rw-r--r--package/network/utils/arptables/Makefile26
-rw-r--r--package/network/utils/bpftool/Makefile99
-rw-r--r--package/network/utils/bpftool/patches/001-cflags.patch10
-rw-r--r--package/network/utils/bpftool/patches/002-includes.patch26
-rw-r--r--package/network/utils/bpftools/Makefile169
-rw-r--r--package/network/utils/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch51
-rw-r--r--package/network/utils/comgt/Makefile4
-rw-r--r--package/network/utils/comgt/files/3g.sh2
-rw-r--r--package/network/utils/comgt/files/ncm.json62
-rw-r--r--package/network/utils/comgt/files/ncm.sh66
-rw-r--r--package/network/utils/ebtables/Makefile36
-rw-r--r--package/network/utils/ethtool/Makefile35
-rw-r--r--package/network/utils/iproute2/Makefile62
-rw-r--r--package/network/utils/iproute2/patches/100-configure.patch12
-rw-r--r--package/network/utils/iproute2/patches/110-darwin_fixes.patch8
-rw-r--r--package/network/utils/iproute2/patches/115-add-config-xtlibdir.patch2
-rw-r--r--package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man.patch11
-rw-r--r--package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch14
-rw-r--r--package/network/utils/iproute2/patches/140-allow_pfifo_fast.patch2
-rw-r--r--package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch2
-rw-r--r--package/network/utils/iproute2/patches/145-keep_libelf_optional.patch2
-rw-r--r--package/network/utils/iproute2/patches/150-keep_libcap_optional.patch2
-rw-r--r--package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch11
-rw-r--r--package/network/utils/iproute2/patches/170-ip_tiny.patch36
-rw-r--r--package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch13
-rw-r--r--package/network/utils/iproute2/patches/180-drop_FAILED_POLICY.patch6
-rw-r--r--package/network/utils/iproute2/patches/185-libbpf-add-limits-h.patch45
-rw-r--r--package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch4
-rw-r--r--package/network/utils/iproute2/patches/195-build_variant_ip_tc.patch6
-rw-r--r--package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch6
-rw-r--r--package/network/utils/iproute2/patches/300-selinux-configurable.patch2
-rw-r--r--package/network/utils/ipset/Makefile8
-rw-r--r--package/network/utils/iptables/Makefile251
-rw-r--r--package/network/utils/iptables/patches/020-treewide-use-uint-instead-of-u_int.patch144
-rw-r--r--package/network/utils/iptables/patches/030-revert-fix-build-for-missing-ETH_ALEN-definition.patch60
-rw-r--r--package/network/utils/iptables/patches/040-xshared-Fix-build-for-Werror-format-security.patch23
-rw-r--r--package/network/utils/iptables/patches/050-build-fix-error-during-out-of-tree-build.patch28
-rw-r--r--package/network/utils/iptables/patches/060-libxtables-unexport-init_extensions-declarations.patch82
-rw-r--r--package/network/utils/iptables/patches/070-extensions-string-Review-parse_string-function.patch40
-rw-r--r--package/network/utils/iptables/patches/101-remove-check-already.patch4
-rw-r--r--package/network/utils/iptables/patches/102-iptables-disable-modprobe.patch13
-rw-r--r--package/network/utils/iptables/patches/200-configurable_builtin.patch2
-rw-r--r--package/network/utils/iptables/patches/600-shared-libext.patch2
-rw-r--r--package/network/utils/iptables/patches/700-disable-legacy-revisions.patch14
-rw-r--r--package/network/utils/iw/Makefile23
-rw-r--r--package/network/utils/iw/patches/001-nl80211_h_sync.patch302
-rw-r--r--package/network/utils/iw/patches/010-Revert-iw-allow-specifying-CFLAGS-LIBS-externally.patch68
-rw-r--r--package/network/utils/iw/patches/120-antenna_gain.patch33
-rw-r--r--package/network/utils/iw/patches/200-reduce_size.patch100
-rw-r--r--package/network/utils/iwinfo/Makefile10
-rw-r--r--package/network/utils/layerscape/restool/Makefile10
-rw-r--r--package/network/utils/layerscape/restool/patches/0001-restool-fix-get_device_file-function.patch107
-rw-r--r--package/network/utils/layerscape/restool/patches/remove-manpage.patch18
-rw-r--r--package/network/utils/linux-atm/Makefile3
-rw-r--r--package/network/utils/ltq-dsl-base/Makefile2
-rw-r--r--package/network/utils/nftables/Makefile28
-rw-r--r--package/network/utils/rssileds/Makefile2
-rw-r--r--package/network/utils/tcpdump/Makefile17
-rw-r--r--package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch6
-rw-r--r--package/network/utils/tcpdump/patches/100-tcpdump_mini.patch704
-rw-r--r--package/network/utils/tcpdump/patches/101-CVE-2020-8037.patch47
-rw-r--r--package/network/utils/umbim/Makefile13
-rwxr-xr-xpackage/network/utils/umbim/files/lib/netifd/proto/mbim.sh208
-rw-r--r--package/network/utils/uqmi/Makefile15
-rwxr-xr-xpackage/network/utils/uqmi/files/lib/netifd/proto/qmi.sh166
-rw-r--r--package/network/utils/wireguard-tools/Makefile8
-rw-r--r--package/network/utils/wireguard-tools/files/wireguard.sh26
-rw-r--r--package/network/utils/wireguard-tools/files/wireguard_watchdog10
-rw-r--r--package/network/utils/wireless-tools/Makefile1
-rw-r--r--package/network/utils/wpan-tools/Makefile15
-rw-r--r--package/network/utils/wpan-tools/patches/001-src-nl_extras.h-fix-compatibility-with-libnl-3.3.0.patch44
-rw-r--r--package/network/utils/wwan/Makefile2
-rw-r--r--package/network/utils/wwan/files/data/0e8d-00a55
-rw-r--r--package/network/utils/xdp-tools/Makefile139
-rw-r--r--package/network/utils/xdp-tools/patches/010-configure-respect-LDFLAGS.patch29
321 files changed, 29674 insertions, 4498 deletions
diff --git a/package/network/config/firewall/Makefile b/package/network/config/firewall/Makefile
index 5b1e23af8c9..0e00f386897 100644
--- a/package/network/config/firewall/Makefile
+++ b/package/network/config/firewall/Makefile
@@ -9,18 +9,20 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=firewall
-PKG_RELEASE:=1
+PKG_RELEASE:=3
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firewall3.git
-PKG_SOURCE_DATE:=2021-03-29
-PKG_SOURCE_VERSION:=a4355a6faea2c4d59c90cd52851fa9aab4ccee5c
-PKG_MIRROR_HASH:=747db79b11010bbfb708aae1793857c8d959d9270c7392f8c78d2d2110cf2fe7
+PKG_SOURCE_DATE:=2022-02-17
+PKG_SOURCE_VERSION:=4cd7d4f36bea731bf901cb067456f1d460294926
+PKG_MIRROR_HASH:=ce9e8ac1bcf22afbb0a80c3da1a8e8e887851299681097e3dfbfc347f2c4c80f
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=ISC
PKG_CONFIG_DEPENDS := CONFIG_IPV6
+PKG_BUILD_FLAGS:=gc-sections lto
+
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
@@ -28,7 +30,9 @@ define Package/firewall
SECTION:=net
CATEGORY:=Base system
TITLE:=OpenWrt C Firewall
- DEPENDS:=+libubox +libubus +libuci +libip4tc +IPV6:libip6tc +libxtables +kmod-ipt-core +kmod-ipt-conntrack +IPV6:kmod-nf-conntrack6 +kmod-ipt-nat
+ DEPENDS:=+libubox +libubus +libuci +libip4tc +IPV6:libip6tc +libiptext +IPV6:libiptext6 +libxtables +kmod-ipt-core +kmod-ipt-conntrack +IPV6:kmod-nf-conntrack6 +kmod-ipt-nat
+ PROVIDES:=uci-firewall
+ CONFLICTS:=firewall4
endef
define Package/firewall/description
@@ -40,8 +44,6 @@ define Package/firewall/conffiles
/etc/firewall.user
endef
-TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
-TARGET_LDFLAGS += -Wl,--gc-sections -flto
CMAKE_OPTIONS += $(if $(CONFIG_IPV6),,-DDISABLE_IPV6=1)
define Package/firewall/install
diff --git a/package/network/config/firewall/files/firewall.config b/package/network/config/firewall/files/firewall.config
index 5e22f984ce9..b90ac7af0a3 100644
--- a/package/network/config/firewall/files/firewall.config
+++ b/package/network/config/firewall/files/firewall.config
@@ -1,6 +1,6 @@
config defaults
option syn_flood 1
- option input ACCEPT
+ option input REJECT
option output ACCEPT
option forward REJECT
# Uncomment this line to disable ipv6 rules
@@ -54,13 +54,11 @@ config rule
option target ACCEPT
# Allow DHCPv6 replies
-# see https://dev.openwrt.org/ticket/10381
+# see https://github.com/openwrt/openwrt/issues/5066
config rule
option name Allow-DHCPv6
option src wan
option proto udp
- option src_ip fc00::/6
- option dest_ip fc00::/6
option dest_port 546
option family ipv6
option target ACCEPT
diff --git a/package/network/config/firewall4/Makefile b/package/network/config/firewall4/Makefile
index bfe10cfb8fe..6a54e28f0c2 100644
--- a/package/network/config/firewall4/Makefile
+++ b/package/network/config/firewall4/Makefile
@@ -9,9 +9,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firewall4.git
-PKG_SOURCE_DATE:=2021-03-31
-PKG_SOURCE_VERSION:=29fba840201287b9265888adba6298779b750af5
-PKG_MIRROR_HASH:=1d26a611aeecdf37f09e4cdee6b192e5da087abf6e0fc7a9ca97a80e58d14222
+PKG_SOURCE_DATE:=2023-11-03
+PKG_SOURCE_VERSION:=698a53354fd280aae097efe08803c0c9a10c14c2
+PKG_MIRROR_HASH:=e38484bffe11a04a67069128aa3b8a8c707ad58c79c0de2785a5d995421457aa
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=ISC
@@ -21,8 +21,13 @@ define Package/firewall4
SECTION:=net
CATEGORY:=Base system
TITLE:=OpenWrt 4th gen firewall
- DEPENDS:=+ucode +ucode-mod-fs +ucode-mod-uci +ucode-mod-ubus +kmod-nft-core +kmod-nft-fib +kmod-nft-nat +kmod-nft-nat6 +nftables-json
- CONFLICTS:=firewall kmod-ipt-nat
+ DEPENDS:= \
+ +kmod-nft-core +kmod-nft-fib +kmod-nft-offload \
+ +kmod-nft-nat \
+ +nftables-json \
+ +ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci
+ EXTRA_DEPENDS:=ucode (>= 2022-03-22)
+ PROVIDES:=uci-firewall
endef
define Package/firewall4/description
diff --git a/package/network/config/ipip/Makefile b/package/network/config/ipip/Makefile
index c262182558c..4494e1b81fd 100644
--- a/package/network/config/ipip/Makefile
+++ b/package/network/config/ipip/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ipip
-PKG_RELEASE:=3
+PKG_RELEASE:=4
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
diff --git a/package/network/config/ipip/files/ipip.sh b/package/network/config/ipip/files/ipip.sh
index 15b1c978e31..c433ee0de4d 100755
--- a/package/network/config/ipip/files/ipip.sh
+++ b/package/network/config/ipip/files/ipip.sh
@@ -12,7 +12,7 @@ proto_ipip_setup() {
local remoteip
local df ipaddr peeraddr tunlink ttl tos zone mtu
- json_get_vars df ipaddr peeraddr tunlink ttl tos zone mtu
+ json_get_vars df ipaddr peeraddr tunlink ttl tos zone mtu nohostroute
[ -z "$peeraddr" ] && {
proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
@@ -32,7 +32,9 @@ proto_ipip_setup() {
break
done
- ( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+ if [ "${nohostroute}" != "1" ]; then
+ ( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+ fi
[ -z "$ipaddr" ] && {
local wanif="$tunlink"
@@ -84,6 +86,7 @@ proto_ipip_init_config() {
proto_config_add_string "ipaddr"
proto_config_add_string "peeraddr"
proto_config_add_boolean "df"
+ proto_config_add_boolean "nohostroute"
}
[ -n "$INCLUDE_ONLY" ] || {
diff --git a/package/network/config/ltq-adsl-app/Makefile b/package/network/config/ltq-adsl-app/Makefile
index 2e4792266c1..472e3c0ed9c 100644
--- a/package/network/config/ltq-adsl-app/Makefile
+++ b/package/network/config/ltq-adsl-app/Makefile
@@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=dsl_cpe_control_danube
PKG_VERSION:=3.24.4.4
-PKG_RELEASE:=10
+PKG_RELEASE:=11
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_BUILD_DIR:=$(BUILD_DIR)/dsl_cpe_control-$(PKG_VERSION)
PKG_SOURCE_URL:=@OPENWRT
@@ -36,6 +36,7 @@ define Package/ltq-adsl-app
TITLE:=Lantiq DSL userland tool
URL:=http://www.lantiq.com/
DEPENDS:=@(TARGET_lantiq_xway||TARGET_lantiq_xway_legacy||TARGET_lantiq_ase) +libpthread +ltq-dsl-base +libubox +libubus
+ PROVIDES:=ltq-dsl-app
MENU:=1
endef
@@ -77,7 +78,7 @@ TARGET_CFLAGS += -I$(LINUX_DIR)/include
define Build/Prepare
$(call Build/Prepare/Default)
- $(CP) ../ltq-vdsl-app/src/src/dsl_cpe_ubus.c $(PKG_BUILD_DIR)/src/
+ $(CP) ../ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c $(PKG_BUILD_DIR)/src/
endef
define Package/ltq-adsl-app/install
diff --git a/package/network/config/ltq-adsl-app/patches/100-add-more-script-notifications.patch b/package/network/config/ltq-adsl-app/patches/100-add-more-script-notifications.patch
index 9d611c1caff..875b7ecbf57 100644
--- a/package/network/config/ltq-adsl-app/patches/100-add-more-script-notifications.patch
+++ b/package/network/config/ltq-adsl-app/patches/100-add-more-script-notifications.patch
@@ -3,7 +3,7 @@ From: Mathias Kresin <dev@kresin.me>
Date: Mon, 16 Oct 2017 21:08:26 +0200
Subject: ltq-adsl-app: add more script notifications
-Backport HANDSHAKE and TRAINING notification from ltq-vdsl-app. It
+Backport HANDSHAKE and TRAINING notification from ltq-vdsl-vr9-app. It
unifies the dsl led blinking pattern accross all subtargets and allows
to get the current line status from the dsl led.
diff --git a/package/network/config/ltq-vdsl-app/patches/200-autoboot.patch b/package/network/config/ltq-vdsl-app/patches/200-autoboot.patch
deleted file mode 100644
index 5b882bf30ff..00000000000
--- a/package/network/config/ltq-vdsl-app/patches/200-autoboot.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/src/dsl_cpe_init_cfg.c
-+++ b/src/dsl_cpe_init_cfg.c
-@@ -27,7 +27,7 @@ DSL_InitData_t gInitCfgData =
- DSL_CPE_FW2_SET(DSL_NULL, 0x0),
- DSL_CPE_XTU_SET(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7),
- DSL_CPE_LINE_INV_NE_SET(DSL_NULL),
-- DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_STOP),
-+ DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_START),
- DSL_CPE_AUTOBOOT_CFG_SET(DSL_FALSE, DSL_FALSE, DSL_FALSE),
- DSL_CPE_TEST_MODE_CTRL_SET(DSL_TESTMODE_DISABLE),
- DSL_CPE_LINE_ACTIVATE_CTRL_SET(DSL_G997_INHIBIT_LDSF, DSL_G997_INHIBIT_ACSF, DSL_G997_NORMAL_STARTUP),
diff --git a/package/network/config/ltq-vdsl-vr11-app/Makefile b/package/network/config/ltq-vdsl-vr11-app/Makefile
new file mode 100644
index 00000000000..bcbf41e65a1
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr11-app/Makefile
@@ -0,0 +1,92 @@
+# Copyright (C) 2010 OpenWrt.org
+# Copyright (C) 2015-2016 Lantiq Beteiligungs GmbH & Co KG.
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=ltq-vdsl-vr11-app
+PKG_VERSION:=4.23.1
+PKG_RELEASE:=2
+PKG_BASE_NAME:=dsl_cpe_control
+
+UGW_VERSION=8.5.2.10
+UGW_BASENAME=$(PKG_BASE_NAME)-ugw_$(UGW_VERSION)
+
+PKG_SOURCE:=$(UGW_BASENAME).tar.bz2
+PKG_SOURCE_URL:=https://gitlab.com/prpl-foundation/intel/$(PKG_BASE_NAME)/-/archive/ugw_$(UGW_VERSION)/
+PKG_HASH:=d21ec74ca30f7f3893a8aa26d2b74ec319652f6b112832efab6f1274c7e5d1fc
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(UGW_BASENAME)
+PKG_LICENSE:=BSD-2-Clause
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_BUILD_DEPENDS:=ltq-vdsl-vr11
+
+PKG_FLAGS:=nonshared
+PKG_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ltq-vdsl-vr11-app
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=Lantiq VDSL userland tool
+ URL:=http://www.lantiq.com/
+ DEPENDS:=@TARGET_ipq40xx +libpthread +librt +libubox +libubus +ltq-dsl-base +kmod-ltq-vdsl-vr11
+ PROVIDES:=ltq-dsl-app
+endef
+
+define Package/ltq-vdsl-vr11-app/description
+ Userland tool needed to control Lantiq VDSL CPE
+endef
+
+# ltq-vdsl-vr11-app uses a header provided by the MEI driver which has some
+# conditionals.
+#
+# Define them here with the default values they would get in the MEI driver,
+# have the same view on both sides.
+#
+# If you change them, you need to change them for the ltq-vdsl-vr11-app as well
+VDSL_APP_CFLAGS = \
+ -DMAX_CLI_PIPES=1 \
+ -DMEI_SUPPORT_DEBUG_STREAMS=1 \
+ -DMEI_SUPPORT_OPTIMIZED_FW_DL=1
+
+CONFIGURE_ARGS += \
+ --enable-debug-logger-support=no
+
+CONFIGURE_ARGS += \
+ --enable-vrx \
+ --enable-vrx-device=vr11 \
+ --enable-driver-include="-I$(STAGING_DIR)/usr/include/drv_vdsl_cpe_api" \
+ --enable-device-driver-include="-I$(STAGING_DIR)/usr/include/vdsl/" \
+ --enable-ifxos \
+ --enable-ifxos-include="-I$(STAGING_DIR)/usr/include/ifxos" \
+ --enable-ifxos-library="-I$(STAGING_DIR)/usr/lib" \
+ --enable-add-appl-cflags="$(VDSL_APP_CFLAGS)" \
+ --enable-debug \
+ --disable-dti
+
+CONFIGURE_ARGS += \
+ --enable-model=full \
+ --enable-dsl-ceoc=no
+#CONFIGURE_ARGS += --enable-model=lite
+#CONFIGURE_ARGS += --enable-model=footprint
+#CONFIGURE_ARGS += --enable-model=typical
+#CONFIGURE_ARGS += --enable-model=debug
+
+define Build/Prepare
+ $(call Build/Prepare/Default)
+ $(CP) ../ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c $(PKG_BUILD_DIR)/src/
+endef
+
+define Package/ltq-vdsl-vr11-app/install
+ $(INSTALL_DIR) $(1)/etc/init.d $(1)/sbin $(1)/etc/hotplug.d/dsl
+ $(INSTALL_BIN) ./files/dsl_control $(1)/etc/init.d/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/dsl_cpe_control $(1)/sbin/vdsl_cpe_control
+ $(INSTALL_BIN) ./files/dsl_cpe_pipe.sh $(1)/sbin/
+endef
+
+$(eval $(call BuildPackage,ltq-vdsl-vr11-app))
diff --git a/package/network/config/ltq-vdsl-vr11-app/files/dsl_control b/package/network/config/ltq-vdsl-vr11-app/files/dsl_control
new file mode 100644
index 00000000000..d960a772618
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr11-app/files/dsl_control
@@ -0,0 +1,264 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2012 OpenWrt.org
+
+START=97
+USE_PROCD=1
+
+dslstat() {
+ ubus call dsl metrics
+}
+
+extra_command "dslstat" "Get DSL status information"
+
+#
+# ITU-T G.997.1 (06/2012) - Section 7.3.1.1.1 (xTU transmission system enabling (XTSE))
+# ITU-T G.997.1 Amendment 2 (04/2013) - Section 2.1 - (Vectoring mode enable (VECTORMODE_ENABLE))
+#
+# G.992.1 Annex A
+# G.992.2 Annex A
+# G.992.3 Annex A / L-US1 / L_US-2 / M
+# G.992.5 Annex A / M
+# G.993.2 Annex A/B/C
+# G.993.5 Annex A/B/C
+xtse_xdsl_a="05_01_04_00_4C_01_04_07"
+
+# G.992.1 Annex B
+# G.992.3 Annex B
+# G.992.5 Annex B
+# G.993.2 Annex A/B/C
+# G.993.5 Annex A/B/C
+xtse_xdsl_b="10_00_10_00_00_04_00_07"
+
+# G.992.1 Annex B
+# G.992.3 Annex B
+# G.992.3 Annex J
+# G.992.5 Annex B
+# G.992.5 Annex J
+# G.993.2 Annex A/B/C
+# G.993.5 Annex A/B/C
+xtse_xdsl_j="10_00_10_40_00_04_01_07"
+
+# G.992.1 Annex B
+xtse_xdsl_bdmt="10_00_00_00_00_00_00_00"
+
+# G.992.3 Annex B
+xtse_xdsl_b2="00_00_10_00_00_00_00_00"
+
+# G.992.5 Annex B
+xtse_xdsl_b2p="00_00_00_00_00_04_00_00"
+
+# ANSI T1.413
+xtse_xdsl_at1="01_00_00_00_00_00_00_00"
+
+# G.992.2 Annex A
+xtse_xdsl_alite="00_01_00_00_00_00_00_00"
+
+# G.992.1 Annex A
+xtse_xdsl_admt="04_00_00_00_00_00_00_00"
+
+# G.992.3 Annex A
+xtse_xdsl_a2="00_00_04_00_00_00_00_00"
+
+# G.992.5 Annex A
+xtse_xdsl_a2p="00_00_00_00_00_01_00_00"
+
+# G.992.3 Annex L
+xtse_xdsl_l="00_00_00_00_0C_00_00_00"
+
+# G.992.3 Annex M
+# G.992.5 Annex M
+xtse_xdsl_m="00_00_00_00_40_00_04_00"
+
+# G.992.3 Annex M
+xtse_xdsl_m2="00_00_00_00_40_00_00_00"
+
+# G.992.5 Annex M
+xtse_xdsl_m2p="00_00_00_00_00_00_04_00"
+
+#
+# ITU-T G.994.1 (06/2012) - Table 2 (Mandatory carrier sets)
+#
+
+# A43
+tone_adsl_a="0x142" # A43C + J43 + A43
+tone_vdsl_a="0x142" # A43C + J43 + A43
+
+# A43 + V43
+tone_adsl_av="0x142" # A43C + J43 + A43
+tone_vdsl_av="0x146" # A43C + J43 + A43 + V43
+
+# B43
+tone_adsl_b="0x81" # B43 + B43c
+tone_vdsl_b="0x1" # B43
+
+# B43 + V43
+tone_adsl_bv="0x81" # B43 + B43c
+tone_vdsl_bv="0x5" # B43 + V43
+
+# create DSL autoboot script. Used for SNR margin tweak and to set MAC address for vectoring error reports
+autoboot_script() {
+ echo "[WaitForConfiguration]={
+locs nLine=0 0 $1
+dsmmcs nLine=0 $2
+}
+
+[WaitForLinkActivate]={
+}
+
+[WaitForRestart]={
+}
+
+[Common]={
+}" > /tmp/dsl.scr
+}
+
+lowlevel_cfg() {
+ echo "# VRX Low Level Configuration File
+#
+# Parameters must be separated by tabs or spaces.
+# Empty lines and comments will be ignored.
+#
+
+# nFilter
+#
+# NA = -1
+# OFF = 0
+# ISDN = 1
+# POTS = 2
+# POTS_2 = 3
+# POTS_3 = 4
+#
+# (dec)
+ -1
+
+# nHsToneGroupMode nHsToneGroup_A nHsToneGroup_V nHsToneGroup_AV
+#
+# NA = -1 NA = -1 see see
+# AUTO = 0 VDSL2_B43 = 0x0001 nHsToneGroup_A nHsToneGroup_A
+# MANUAL = 1 VDSL2_A43 = 0x0002
+# VDSL2_V43 = 0x0004
+# VDSL1_V43P = 0x0008
+# VDSL1_V43I = 0x0010
+# ADSL1_C43 = 0x0020
+# ADSL2_J43 = 0x0040
+# ADSL2_B43C = 0x0080
+# ADSL2_A43C = 0x0100
+#
+# (dec) (hex) (hex) (hex)
+ 1 $1 $2 0x0
+
+# nBaseAddr nIrqNum
+#
+# (hex) (dec)
+ 0x1e116000 63
+
+# nUtopiaPhyAdr nUtopiaBusWidth nPosPhyParity
+# default(16b) = 0 NA = -1
+# 8-bit = 1 ODD = 0
+# 16-bit = 2
+#
+#
+# (hex) (dec) (dec)
+ 0xFF 0 0
+
+# bNtrEnable
+#
+# (dec)
+ 0" > /tmp/lowlevel.cfg
+}
+
+get_macaddr() {
+ local name
+ config_get name $1 name
+ [ "$name" = "dsl0" ] && config_get $2 $1 macaddr
+}
+
+service_triggers() {
+ procd_add_reload_trigger network
+}
+
+start_service() {
+ local annex
+ local firmware
+ local tone
+ local tone_adsl
+ local tone_vdsl
+ local xtse
+ local xfer_mode
+ local line_mode
+ local tc_layer
+ local mode
+ local lowlevel
+ local snr
+ local macaddr
+
+ config_load network
+ config_get tone dsl tone
+ config_get annex dsl annex
+ config_get firmware dsl firmware
+ config_get xfer_mode dsl xfer_mode
+ config_get line_mode dsl line_mode
+ config_get snr dsl ds_snr_offset
+ config_foreach get_macaddr device macaddr
+
+ eval "xtse=\"\${xtse_xdsl_$annex}\""
+
+ case "${xfer_mode}" in
+ atm)
+ tc_layer="-T1:0x1:0x1_1:0x1:0x1"
+ ;;
+ ptm)
+ tc_layer="-T2:0x1:0x1_2:0x1:0x1"
+ ;;
+ esac
+
+ case "${line_mode}" in
+ adsl)
+ mode="-M1"
+
+ # mask out VDSL bits when ADSL is requested
+ xtse="${xtse%_*}_00"
+ ;;
+ vdsl)
+ mode="-M2"
+
+ # mask out ADSL bits when VDSL is requested
+ xtse="00_00_00_00_00_00_00_${xtse##*_}"
+ ;;
+ esac
+
+ [ -z "${firmware}" ] && firmware=/lib/firmware/vdsl.bin
+ [ -f "${firmware}" ] || {
+ echo failed to find $firmware
+ return 1
+ }
+
+ eval "tone_adsl=\"\${tone_adsl_$tone}\""
+ eval "tone_vdsl=\"\${tone_vdsl_$tone}\""
+ [ -n "${tone_adsl}" ] && [ -n "${tone_vdsl}" ] && {
+ lowlevel_cfg "${tone_adsl}" "${tone_vdsl}"
+ lowlevel="-l /tmp/lowlevel.cfg"
+ }
+
+ [ -z "${snr}" ] && snr=0
+ [ -z "${macaddr}" ] && macaddr="00:00:00:00:00:00"
+ autoboot_script "$snr" "$macaddr"
+ autoboot="-a /tmp/dsl.scr -A /tmp/dsl.scr"
+
+ procd_open_instance
+ procd_set_param command /sbin/vdsl_cpe_control \
+ -i$xtse \
+ -n /sbin/dsl_notify.sh \
+ -f ${firmware} \
+ $lowlevel \
+ ${mode} \
+ ${tc_layer} \
+ $autoboot
+ procd_close_instance
+}
+
+stop_service() {
+ DSL_NOTIFICATION_TYPE="DSL_INTERFACE_STATUS" \
+ DSL_INTERFACE_STATUS="DOWN" \
+ /sbin/dsl_notify.sh
+}
diff --git a/package/network/config/ltq-vdsl-app/files/dsl_cpe_pipe.sh b/package/network/config/ltq-vdsl-vr11-app/files/dsl_cpe_pipe.sh
index 9002b7b3164..9002b7b3164 100755
--- a/package/network/config/ltq-vdsl-app/files/dsl_cpe_pipe.sh
+++ b/package/network/config/ltq-vdsl-vr11-app/files/dsl_cpe_pipe.sh
diff --git a/package/network/config/ltq-vdsl-app/patches/100-compat.patch b/package/network/config/ltq-vdsl-vr11-app/patches/100-compat.patch
index 6b738cfe66c..6bc359c3cc9 100644
--- a/package/network/config/ltq-vdsl-app/patches/100-compat.patch
+++ b/package/network/config/ltq-vdsl-vr11-app/patches/100-compat.patch
@@ -9,14 +9,3 @@
DSL_CPE_SIC_SET(DSL_TC_ATM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII, \
DSL_TC_EFM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII),
DSL_CPE_MAC_CFG_SET(DSL_EFM_SPEED_100, DSL_EFM_DUPLEX_FULL, DSL_EFM_FLOWCTRL_ON, DSL_EFM_AUTONEG_OFF, \
---- a/src/dsl_cpe_control.c
-+++ b/src/dsl_cpe_control.c
-@@ -6761,7 +6761,7 @@ DSL_int_t dsl_cpe_daemon (
- for (nDevice = 0; nDevice < DSL_CPE_MAX_DSL_ENTITIES; nDevice++)
- {
- #if defined(INCLUDE_DSL_CPE_API_VRX)
-- sprintf (device, "%s/%d", DSL_CPE_DEVICE_NAME, nDevice);
-+ sprintf (device, "%s%d", DSL_CPE_DEVICE_NAME, nDevice);
- #else
- sprintf (device, "%s", DSL_CPE_DEVICE_NAME);
- #endif /* defined(INCLUDE_DSL_CPE_API_VRX)*/
diff --git a/package/network/config/ltq-vdsl-vr11-app/patches/101-warnings.patch b/package/network/config/ltq-vdsl-vr11-app/patches/101-warnings.patch
new file mode 100644
index 00000000000..0c02bb17b75
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr11-app/patches/101-warnings.patch
@@ -0,0 +1,87 @@
+--- a/src/dsl_cpe_control.h
++++ b/src/dsl_cpe_control.h
+@@ -13,6 +13,8 @@
+ #ifndef _DSL_CPE_CONTROL_H
+ #define _DSL_CPE_CONTROL_H
+
++#include <string.h>
++
+ /** \defgroup DSL_CPE_CONTROL Lantiq DSL CPE API Control Application
+ Lists the entire modules to the DSL CPE_API Control Application.
+ @{ */
+--- a/src/dsl_cpe_safec_wrapper.h
++++ b/src/dsl_cpe_safec_wrapper.h
+@@ -23,7 +23,7 @@
+ #define cpe_control_vsnprintf_s vsnprintf_s
+
+ /* snprintf_s symbol is not exported in SafeC lib */
+-static int cpe_control_snprintf_s(char *dest,
++static inline int cpe_control_snprintf_s(char *dest,
+ size_t dmax,
+ const char *fmt,
+ ...)
+@@ -40,7 +40,7 @@ static int cpe_control_snprintf_s(char *
+
+ #else
+
+-#warning "Safe C library is not available!"
++//#warning "Safe C library is not available!"
+
+ #include <stddef.h> /* size_t */
+ #include <stdarg.h> /* va_list */
+@@ -55,7 +55,7 @@ static __inline__ size_t safec_wrapper_m
+ #define cpe_control_memset_s(dest, destsz, src, srcsz) memset(dest, src, safec_wrapper_min(destsz,srcsz))
+ #define cpe_control_strncpy_s(dest, destsz, src, srcsz) strncpy(dest, src, safec_wrapper_min(destsz,srcsz))
+
+-static size_t cpe_control_strnlen_s(const char *str,
++static inline size_t cpe_control_strnlen_s(const char *str,
+ size_t smax)
+ {
+ /* preconditions */
+@@ -74,7 +74,7 @@ static size_t cpe_control_strnlen_s(cons
+ return size;
+ }
+
+-static char *cpe_control_strtok_s(char *dest,
++static inline char *cpe_control_strtok_s(char *dest,
+ size_t *dmax,
+ const char *delim,
+ char **ptr)
+@@ -123,7 +123,7 @@ static char *cpe_control_strtok_s(char *
+ return pTmp;
+ }
+
+-static int cpe_control_pipe_strcat_s(char *dest,
++static inline int cpe_control_pipe_strcat_s(char *dest,
+ size_t destsz,
+ char *src)
+ {
+@@ -157,7 +157,7 @@ static int cpe_control_pipe_strcat_s(cha
+ return 0;
+ }
+
+-static int cpe_control_snprintf_s(char *dest,
++static inline int cpe_control_snprintf_s(char *dest,
+ size_t dmax,
+ const char *fmt,
+ ...)
+@@ -181,7 +181,7 @@ static int cpe_control_snprintf_s(char *
+ return retVal;
+ }
+
+-static int cpe_control_vsnprintf_s(char *dest,
++static inline int cpe_control_vsnprintf_s(char *dest,
+ size_t dmax,
+ const char *fmt,
+ va_list vlist)
+--- a/tools/pipe/dsl_cpe_safec_wrapper.h
++++ b/tools/pipe/dsl_cpe_safec_wrapper.h
+@@ -27,7 +27,7 @@
+
+ #else
+
+-#warning "Safe C library is not available!"
++//#warning "Safe C library is not available!"
+
+ #include <stddef.h> /* size_t */
+ static __inline__ size_t safec_wrapper_min(size_t a, size_t b)
diff --git a/package/network/config/ltq-vdsl-vr11-app/patches/200-autoboot.patch b/package/network/config/ltq-vdsl-vr11-app/patches/200-autoboot.patch
new file mode 100644
index 00000000000..c3e9b966204
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr11-app/patches/200-autoboot.patch
@@ -0,0 +1,85 @@
+This enables automatic connection after the control daemon is started,
+and also changes the way the connection is stopped on termination.
+
+Using the autoboot restart command is necessary because the stop command
+would stop the autoboot thread, and the driver offers no working way to
+start it again later, short of unloading and reloading the module.
+
+--- a/src/dsl_cpe_init_cfg.c
++++ b/src/dsl_cpe_init_cfg.c
+@@ -27,7 +27,7 @@ DSL_InitData_t gInitCfgData =
+ DSL_CPE_FW2_SET(DSL_NULL, 0x0),
+ DSL_CPE_XTU_SET(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7),
+ DSL_CPE_LINE_INV_NE_SET(DSL_NULL),
+- DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_STOP),
++ DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_START),
+ DSL_CPE_AUTOBOOT_CFG_SET(DSL_FALSE, DSL_FALSE, DSL_FALSE),
+ DSL_CPE_TEST_MODE_CTRL_SET(DSL_TESTMODE_DISABLE),
+ DSL_CPE_LINE_ACTIVATE_CTRL_SET(DSL_G997_INHIBIT_LDSF, DSL_G997_INHIBIT_ACSF, DSL_G997_NORMAL_STARTUP),
+--- a/src/dsl_cpe_control.c
++++ b/src/dsl_cpe_control.c
+@@ -7338,6 +7338,7 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_Termi
+ {
+ DSL_Error_t nRet = DSL_SUCCESS;
+ DSL_int_t nDevice = 0;
++ DSL_AutobootConfig_t sAutobootCfg;
+ DSL_AutobootControl_t sAutobootCtl;
+ DSL_CPE_Control_Context_t *pCtrlCtx = DSL_NULL;
+
+@@ -7349,8 +7350,32 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_Termi
+
+ for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; ++nDevice)
+ {
++ g_bWaitBeforeConfigWrite[nDevice] = DSL_TRUE;
++ g_bWaitBeforeLinkActivation[nDevice] = DSL_TRUE;
++ g_bWaitBeforeRestart[nDevice] = DSL_TRUE;
++
++ g_bAutoContinueWaitBeforeConfigWrite[nDevice] = DSL_FALSE;
++ g_bAutoContinueWaitBeforeLinkActivation[nDevice] = DSL_FALSE;
++ g_bAutoContinueWaitBeforeRestart[nDevice] = DSL_FALSE;
++
++ memset(&sAutobootCfg, 0x0, sizeof(DSL_AutobootConfig_t));
++ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeConfigWrite = DSL_TRUE;
++ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeLinkActivation = DSL_TRUE;
++ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeRestart = DSL_TRUE;
++
++ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
++ DSL_CPE_GetGlobalContext()->fd[nDevice],
++ DSL_FIO_AUTOBOOT_CONFIG_SET, (DSL_int_t)&sAutobootCfg);
++
++ if (nRet < DSL_SUCCESS)
++ {
++ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
++ "Autoboot configuration for device (%d) failed!, nRet = %d!"
++ DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
++ }
++
+ memset(&sAutobootCtl, 0, sizeof(DSL_AutobootControl_t));
+- sAutobootCtl.data.nCommand = DSL_AUTOBOOT_CTRL_STOP;
++ sAutobootCtl.data.nCommand = DSL_AUTOBOOT_CTRL_RESTART;
+
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
+@@ -7359,13 +7384,13 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_Termi
+ if (nRet < DSL_SUCCESS)
+ {
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
+- "Autoboot stop for device (%d) failed!, nRet = %d!"
++ "Autoboot restart for device (%d) failed!, nRet = %d!"
+ DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
+ }
+ }
+
+ DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX
+- "Autoboot stop executed" DSL_CPE_CRLF));
++ "Autoboot restart executed" DSL_CPE_CRLF));
+
+ DSL_CPE_DaemonExit();
+
+@@ -8798,4 +8823,4 @@ DSL_CPE_STATIC DSL_Error_t DSL_CPE_Firmw
+ pDecimal));
+
+ return nErrCode;
+-}
+\ No newline at end of file
++}
diff --git a/package/network/config/ltq-vdsl-vr11-app/patches/300-ubus.patch b/package/network/config/ltq-vdsl-vr11-app/patches/300-ubus.patch
new file mode 100644
index 00000000000..fc0dd70bc1b
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr11-app/patches/300-ubus.patch
@@ -0,0 +1,50 @@
+--- a/src/dsl_cpe_control.c
++++ b/src/dsl_cpe_control.c
+@@ -221,6 +221,9 @@ extern DSL_Error_t DSL_CPE_Pipe_StaticRe
+ #endif /* INCLUDE_DSL_RESOURCE_STATISTICS*/
+ #endif
+
++extern void ubus_init();
++extern void ubus_deinit();
++
+ DSL_char_t *g_sFirmwareName1 = DSL_NULL;
+ DSL_FirmwareFeatures_t g_nFwFeatures1 = {DSL_FW_XDSLMODE_CLEANED, DSL_FW_XDSLFEATURE_CLEANED,
+ DSL_FW_XDSLFEATURE_CLEANED};
+@@ -7831,6 +7834,8 @@ DSL_int_t dsl_cpe_daemon (
+ #endif /* defined(INCLUDE_DSL_JSON_PARSING) && (INCLUDE_DSL_JSON_PARSING == 1) */
+ #endif /* RTEMS*/
+
++ ubus_init();
++
+ /* Open DSL_CPE_MAX_DSL_ENTITIES devices*/
+ for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; nDevice++)
+ {
+@@ -8367,6 +8372,7 @@ DSL_int_t dsl_cpe_daemon (
+ #endif /* INCLUDE_DSL_CPE_CLI_SUPPORT */
+
+ DSL_CPE_CONTROL_EXIT:
++ ubus_deinit();
+
+ if (INCLUDE_DSL_BONDING)
+ {
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -17,7 +17,7 @@ else
+ dsl_cpe_control_common_ldflags =
+ endif
+
+-dsl_cpe_control_LDADD = -lpthread -lrt
++dsl_cpe_control_LDADD = -lpthread -lrt -lubox -lubus
+
+ if INCLUDE_DSL_CPE_DTI_SUPPORT
+ dsl_cpe_control_LDADD += -ldti_agent
+@@ -118,7 +118,8 @@ dsl_cpe_control_SOURCES = \
+ dsl_cpe_control.c \
+ dsl_cpe_init_cfg.c \
+ dsl_cpe_linux.c \
+- dsl_cpe_debug.c
++ dsl_cpe_debug.c \
++ dsl_cpe_ubus.c
+
+ dsl_cpe_control_SOURCES += \
+ $(dsl_cpe_control_dti_sources)
diff --git a/package/network/config/ltq-vdsl-app/Makefile b/package/network/config/ltq-vdsl-vr9-app/Makefile
index 0823a0e7e9a..c51489e2c5f 100644
--- a/package/network/config/ltq-vdsl-app/Makefile
+++ b/package/network/config/ltq-vdsl-vr9-app/Makefile
@@ -7,9 +7,9 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
-PKG_NAME:=ltq-vdsl-app
+PKG_NAME:=ltq-vdsl-vr9-app
PKG_VERSION:=4.17.18.6
-PKG_RELEASE:=8
+PKG_RELEASE:=5
PKG_BASE_NAME:=dsl_cpe_control
PKG_SOURCE:=$(PKG_BASE_NAME)_vrx-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@OPENWRT
@@ -17,32 +17,33 @@ PKG_HASH:=da8bb929526a61aea0e153ef524331fcd472a1ebbc6d88ca017735a4f82ece02
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_BASE_NAME)-$(PKG_VERSION)
PKG_LICENSE:=BSD-2-Clause
-PKG_BUILD_DEPENDS:=ltq-vdsl
+PKG_BUILD_DEPENDS:=ltq-vdsl-vr9
PKG_FLAGS:=nonshared
PKG_FIXUP:=autoreconf
include $(INCLUDE_DIR)/package.mk
-define Package/ltq-vdsl-app
+define Package/ltq-vdsl-vr9-app
SECTION:=net
CATEGORY:=Network
TITLE:=Lantiq VDSL userland tool
URL:=http://www.lantiq.com/
DEPENDS:=@TARGET_lantiq_xrx200 +libpthread +librt +ltq-dsl-base +libubox +libubus
+ PROVIDES:=ltq-dsl-app
endef
-define Package/ltq-vdsl-app/description
+define Package/ltq-vdsl-vr9-app/description
Userland tool needed to control Lantiq VDSL CPE
endef
-# ltq-vdsl-app uses a header provided by the MEI driver which has some
+# ltq-vdsl-vr9-app uses a header provided by the MEI driver which has some
# conditionals.
#
# Define them here with the default values they would get in the MEI driver,
# have the same view on both sides.
#
-# If you change them, you need to change them for the ltq-vdsl-app as well
+# If you change them, you need to change them for the ltq-vdsl-vr9-app as well
VDSL_APP_CFLAGS = \
-DMAX_CLI_PIPES=1 \
-DMEI_SUPPORT_DEBUG_STREAMS=1 \
@@ -61,18 +62,15 @@ CONFIGURE_ARGS += \
--disable-dti \
--with-channels-per-line="1"
-#CONFIGURE_ARGS += --enable-model=full
+CONFIGURE_ARGS += \
+ --enable-model=full \
+ --enable-dsl-ceoc=no
#CONFIGURE_ARGS += --enable-model=lite
#CONFIGURE_ARGS += --enable-model=footprint
-CONFIGURE_ARGS += \
- --enable-model=typical \
- --enable-dsl-pm-showtime \
- --disable-dsl-ceoc \
- --enable-dsl-pm-retx-counters \
- --enable-dsl-pm-retx-thresholds
+#CONFIGURE_ARGS += --enable-model=typical
#CONFIGURE_ARGS += --enable-model=debug
-define Package/ltq-vdsl-app/install
+define Package/ltq-vdsl-vr9-app/install
$(INSTALL_DIR) $(1)/etc/init.d $(1)/sbin $(1)/etc/hotplug.d/dsl
$(INSTALL_BIN) ./files/dsl_control $(1)/etc/init.d/
$(INSTALL_BIN) ./files/10_atm.sh $(1)/etc/hotplug.d/dsl
@@ -82,4 +80,4 @@ define Package/ltq-vdsl-app/install
$(INSTALL_BIN) ./files/dsl_cpe_pipe.sh $(1)/sbin/
endef
-$(eval $(call BuildPackage,ltq-vdsl-app))
+$(eval $(call BuildPackage,ltq-vdsl-vr9-app))
diff --git a/package/network/config/ltq-vdsl-app/files/10_atm.sh b/package/network/config/ltq-vdsl-vr9-app/files/10_atm.sh
index e104a14b2e0..e104a14b2e0 100755
--- a/package/network/config/ltq-vdsl-app/files/10_atm.sh
+++ b/package/network/config/ltq-vdsl-vr9-app/files/10_atm.sh
diff --git a/package/network/config/ltq-vdsl-app/files/10_ptm.sh b/package/network/config/ltq-vdsl-vr9-app/files/10_ptm.sh
index 1c62617bba6..1c62617bba6 100755
--- a/package/network/config/ltq-vdsl-app/files/10_ptm.sh
+++ b/package/network/config/ltq-vdsl-vr9-app/files/10_ptm.sh
diff --git a/package/network/config/ltq-vdsl-app/files/dsl_control b/package/network/config/ltq-vdsl-vr9-app/files/dsl_control
index 54b739e2cd9..34642dbda5a 100644
--- a/package/network/config/ltq-vdsl-app/files/dsl_control
+++ b/package/network/config/ltq-vdsl-vr9-app/files/dsl_control
@@ -95,10 +95,11 @@ tone_vdsl_b="0x1" # B43
tone_adsl_bv="0x81" # B43 + B43c
tone_vdsl_bv="0x5" # B43 + V43
-# create ADSL autoboot script. Used for SNR margin tweak
+# create DSL autoboot script. Used for SNR margin tweak and to set MAC address for vectoring error reports
autoboot_script() {
echo "[WaitForConfiguration]={
locs 0 $1
+dsmmcs $2
}
[WaitForLinkActivate]={
@@ -166,6 +167,12 @@ lowlevel_cfg() {
0" > /tmp/lowlevel.cfg
}
+get_macaddr() {
+ local name
+ config_get name $1 name
+ [ "$name" = "dsl0" ] && config_get $2 $1 macaddr
+}
+
service_triggers() {
procd_add_reload_trigger network
}
@@ -183,6 +190,7 @@ start_service() {
local mode
local lowlevel
local snr
+ local macaddr
config_load network
config_get tone dsl tone
@@ -191,6 +199,7 @@ start_service() {
config_get xfer_mode dsl xfer_mode
config_get line_mode dsl line_mode
config_get snr dsl ds_snr_offset
+ config_foreach get_macaddr device macaddr
eval "xtse=\"\${xtse_xdsl_$annex}\""
@@ -289,11 +298,10 @@ start_service() {
lowlevel="-l /tmp/lowlevel.cfg"
}
- [ -z "${snr}" ] || {
- # for SNR offset setting
- autoboot_script "$snr"
- autoboot="-a /tmp/dsl.scr -A /tmp/dsl.scr"
- }
+ [ -z "${snr}" ] && snr=0
+ [ -z "${macaddr}" ] && macaddr="00:00:00:00:00:00"
+ autoboot_script "$snr" "$macaddr"
+ autoboot="-a /tmp/dsl.scr -A /tmp/dsl.scr"
procd_open_instance
procd_set_param command /sbin/vdsl_cpe_control \
diff --git a/package/network/config/ltq-vdsl-vr9-app/files/dsl_cpe_pipe.sh b/package/network/config/ltq-vdsl-vr9-app/files/dsl_cpe_pipe.sh
new file mode 100755
index 00000000000..9002b7b3164
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr9-app/files/dsl_cpe_pipe.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+pipe_no=0
+
+# use specified pipe no
+case "$1" in
+0|1|2)
+pipe_no=$1; shift; ;;
+esac
+
+
+#echo "Call dsl_pipe with $*"
+lock /var/lock/dsl_pipe
+echo $* > /tmp/pipe/dsl_cpe${pipe_no}_cmd
+result=$(cat /tmp/pipe/dsl_cpe${pipe_no}_ack)
+lock -u /var/lock/dsl_pipe
+
+echo "$result"
diff --git a/package/network/config/ltq-vdsl-vr9-app/patches/100-compat.patch b/package/network/config/ltq-vdsl-vr9-app/patches/100-compat.patch
new file mode 100644
index 00000000000..6bc359c3cc9
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr9-app/patches/100-compat.patch
@@ -0,0 +1,11 @@
+--- a/src/dsl_cpe_init_cfg.c
++++ b/src/dsl_cpe_init_cfg.c
+@@ -38,7 +38,7 @@ DSL_InitData_t gInitCfgData =
+ DSL_DEV_HS_TONE_GROUP_CLEANED, \
+ DSL_DEV_HS_TONE_GROUP_CLEANED, \
+ DSL_DEV_HS_TONE_GROUP_CLEANED, \
+- 0x1E116000, 0x37, -1),
++ 0x1E116000, 0x3f, -1),
+ DSL_CPE_SIC_SET(DSL_TC_ATM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII, \
+ DSL_TC_EFM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII),
+ DSL_CPE_MAC_CFG_SET(DSL_EFM_SPEED_100, DSL_EFM_DUPLEX_FULL, DSL_EFM_FLOWCTRL_ON, DSL_EFM_AUTONEG_OFF, \
diff --git a/package/network/config/ltq-vdsl-app/patches/101-musl.patch b/package/network/config/ltq-vdsl-vr9-app/patches/101-musl.patch
index d66045db614..d66045db614 100644
--- a/package/network/config/ltq-vdsl-app/patches/101-musl.patch
+++ b/package/network/config/ltq-vdsl-vr9-app/patches/101-musl.patch
diff --git a/package/network/config/ltq-vdsl-vr9-app/patches/200-autoboot.patch b/package/network/config/ltq-vdsl-vr9-app/patches/200-autoboot.patch
new file mode 100644
index 00000000000..cc6feb94aa9
--- /dev/null
+++ b/package/network/config/ltq-vdsl-vr9-app/patches/200-autoboot.patch
@@ -0,0 +1,86 @@
+This enables automatic connection after the control daemon is started,
+and also stops the connection on termination.
+
+Using the autoboot restart command is necessary because the stop command
+doesn't actually stop the connection, and would also leave the driver in
+a state where an explicit start command is necessary to connect again.
+
+--- a/src/dsl_cpe_init_cfg.c
++++ b/src/dsl_cpe_init_cfg.c
+@@ -27,7 +27,7 @@ DSL_InitData_t gInitCfgData =
+ DSL_CPE_FW2_SET(DSL_NULL, 0x0),
+ DSL_CPE_XTU_SET(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7),
+ DSL_CPE_LINE_INV_NE_SET(DSL_NULL),
+- DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_STOP),
++ DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_START),
+ DSL_CPE_AUTOBOOT_CFG_SET(DSL_FALSE, DSL_FALSE, DSL_FALSE),
+ DSL_CPE_TEST_MODE_CTRL_SET(DSL_TESTMODE_DISABLE),
+ DSL_CPE_LINE_ACTIVATE_CTRL_SET(DSL_G997_INHIBIT_LDSF, DSL_G997_INHIBIT_ACSF, DSL_G997_NORMAL_STARTUP),
+--- a/src/dsl_cpe_control.c
++++ b/src/dsl_cpe_control.c
+@@ -6515,10 +6515,13 @@ DSL_CPE_STATIC void DSL_CPE_Termination
+ DSL_CPE_STATIC DSL_void_t DSL_CPE_Termination (void)
+ {
+ #ifdef INCLUDE_DSL_CPE_CLI_SUPPORT
+- DSL_int_t nDevice = 0;
+ DSL_char_t buf[32] = "quit";
+ #endif
+
++ DSL_Error_t nRet = DSL_SUCCESS;
++ DSL_int_t nDevice = 0;
++ DSL_AutobootConfig_t sAutobootCfg;
++ DSL_AutobootControl_t sAutobootCtl;
+ DSL_CPE_Control_Context_t *pCtrlCtx;
+
+ pCtrlCtx = DSL_CPE_GetGlobalContext();
+@@ -6527,6 +6530,50 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_Termi
+ pCtrlCtx->bRun = DSL_FALSE;
+ }
+
++ for (nDevice = 0; nDevice < DSL_CPE_MAX_DSL_ENTITIES; ++nDevice)
++ {
++ g_bWaitBeforeConfigWrite[nDevice] = DSL_TRUE;
++ g_bWaitBeforeLinkActivation[nDevice] = DSL_TRUE;
++ g_bWaitBeforeRestart[nDevice] = DSL_TRUE;
++
++ g_bAutoContinueWaitBeforeConfigWrite[nDevice] = DSL_FALSE;
++ g_bAutoContinueWaitBeforeLinkActivation[nDevice] = DSL_FALSE;
++ g_bAutoContinueWaitBeforeRestart[nDevice] = DSL_FALSE;
++
++ memset(&sAutobootCfg, 0x0, sizeof(DSL_AutobootConfig_t));
++ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeConfigWrite = DSL_TRUE;
++ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeLinkActivation = DSL_TRUE;
++ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeRestart = DSL_TRUE;
++
++ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
++ DSL_CPE_GetGlobalContext()->fd[nDevice],
++ DSL_FIO_AUTOBOOT_CONFIG_SET, (DSL_int_t)&sAutobootCfg);
++
++ if (nRet < DSL_SUCCESS)
++ {
++ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
++ "Autoboot configuration for device (%d) failed!, nRet = %d!"
++ DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
++ }
++
++ memset(&sAutobootCtl, 0, sizeof(DSL_AutobootControl_t));
++ sAutobootCtl.data.nCommand = DSL_AUTOBOOT_CTRL_RESTART;
++
++ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
++ DSL_CPE_GetGlobalContext()->fd[nDevice],
++ DSL_FIO_AUTOBOOT_CONTROL_SET, (DSL_int_t)&sAutobootCtl);
++
++ if (nRet < DSL_SUCCESS)
++ {
++ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
++ "Autoboot restart for device (%d) failed!, nRet = %d!"
++ DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
++ }
++ }
++
++ DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX
++ "Autoboot restart executed" DSL_CPE_CRLF));
++
+ #ifdef INCLUDE_DSL_CPE_CLI_SUPPORT
+ for (nDevice = 0; nDevice < DSL_CPE_MAX_DSL_ENTITIES; nDevice++)
+ {
diff --git a/package/network/config/ltq-vdsl-app/patches/201-sigterm.patch b/package/network/config/ltq-vdsl-vr9-app/patches/201-sigterm.patch
index 68a416ce24f..4e978359835 100644
--- a/package/network/config/ltq-vdsl-app/patches/201-sigterm.patch
+++ b/package/network/config/ltq-vdsl-vr9-app/patches/201-sigterm.patch
@@ -9,7 +9,7 @@
{
DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX "terminated" DSL_CPE_CRLF));
DSL_CPE_Termination ();
-@@ -6756,6 +6756,7 @@ DSL_int_t dsl_cpe_daemon (
+@@ -6803,6 +6803,7 @@ DSL_int_t dsl_cpe_daemon (
#ifndef RTEMS
signal (SIGINT, DSL_CPE_TerminationHandler);
diff --git a/package/network/config/ltq-vdsl-app/patches/300-ubus.patch b/package/network/config/ltq-vdsl-vr9-app/patches/300-ubus.patch
index f218ea2208d..d257ca2fc4a 100644
--- a/package/network/config/ltq-vdsl-app/patches/300-ubus.patch
+++ b/package/network/config/ltq-vdsl-vr9-app/patches/300-ubus.patch
@@ -10,7 +10,7 @@
DSL_char_t *g_sFirmwareName1 = DSL_NULL;
DSL_FirmwareFeatures_t g_nFwFeatures1 = {DSL_FW_XDSLMODE_CLEANED, DSL_FW_XDSLFEATURE_CLEANED,
DSL_FW_XDSLFEATURE_CLEANED};
-@@ -6759,6 +6762,8 @@ DSL_int_t dsl_cpe_daemon (
+@@ -6806,6 +6809,8 @@ DSL_int_t dsl_cpe_daemon (
signal (SIGTERM, DSL_CPE_TerminationHandler);
#endif /* RTEMS*/
@@ -19,7 +19,7 @@
/* Open DSL_CPE_MAX_DSL_ENTITIES devices*/
for (nDevice = 0; nDevice < DSL_CPE_MAX_DSL_ENTITIES; nDevice++)
{
-@@ -7213,6 +7218,7 @@ DSL_int_t dsl_cpe_daemon (
+@@ -7260,6 +7265,7 @@ DSL_int_t dsl_cpe_daemon (
#endif /* INCLUDE_DSL_CPE_CLI_SUPPORT */
DSL_CPE_CONTROL_EXIT:
diff --git a/package/network/config/ltq-vdsl-app/src/src/dsl_cpe_ubus.c b/package/network/config/ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c
index 9137d797f91..77a1c67b6ae 100644
--- a/package/network/config/ltq-vdsl-app/src/src/dsl_cpe_ubus.c
+++ b/package/network/config/ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c
@@ -133,10 +133,25 @@ enum {
PSTATE_MAP_L3,
};
+/* These values are exported via ubus and backwards compability
+ * needs to be kept!
+ */
+enum {
+ RAMODE_MAP_UNKNOWN = -1,
+ RAMODE_MAP_MANUAL,
+ RAMODE_MAP_AT_INIT,
+ RAMODE_MAP_DYNAMIC,
+ RAMODE_MAP_DYNAMIC_SOS,
+};
+
static DSL_CPE_ThreadCtrl_t thread;
static struct ubus_context *ctx;
static struct blob_buf b;
+static inline void m_null() {
+ blobmsg_add_field(&b, BLOBMSG_TYPE_UNSPEC, "", NULL, 0);
+}
+
static inline void m_double(const char *id, double value) {
blobmsg_add_double(&b, id, value);
}
@@ -146,21 +161,31 @@ static inline void m_bool(const char *id, bool value) {
}
static inline void m_u32(const char *id, uint32_t value) {
- blobmsg_add_u32(&b, id, value);
+ blobmsg_add_u64(&b, id, value);
}
static inline void m_str(const char *id, const char *value) {
blobmsg_add_string(&b, id, value);
}
-static inline void m_db(const char *id, int value) {
- m_double(id, (double)value / 10);
+static inline void m_db(const char *id, int value, int invalid) {
+ if (value != invalid)
+ m_double(id, (double)value / 10);
}
-static inline void m_array(const char *id, const uint8_t *value, uint8_t len) {
+static inline void m_array(const char *id, const uint8_t *value, size_t len) {
void *c = blobmsg_open_array(&b, id);
- for (uint8_t i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
+ blobmsg_add_u16(&b, "", value[i]);
+
+ blobmsg_close_array(&b, c);
+}
+
+static inline void m_array_u16(const char *id, const uint16_t *value, size_t len) {
+ void *c = blobmsg_open_array(&b, id);
+
+ for (size_t i = 0; i < len; ++i)
blobmsg_add_u16(&b, "", value[i]);
blobmsg_close_array(&b, c);
@@ -413,6 +438,94 @@ static void g997_line_inventory(int fd) {
m_array("serial", out.data.SerialNumber, DSL_G997_LI_MAXLEN_SERIAL);
}
+static void pilot_tones_status(int fd) {
+#ifndef INCLUDE_DSL_CPE_API_DANUBE
+ IOCTL(DSL_PilotTonesStatus_t, DSL_FIO_PILOT_TONES_STATUS_GET);
+
+ m_array_u16("pilot_tones", out.data.nPilotTone, out.data.nNumData);
+#endif
+}
+
+static void band_border_status(int fd, DSL_AccessDir_t direction) {
+ IOCTL(DSL_BandBorderStatus_t, DSL_FIO_BAND_BORDER_STATUS_GET);
+
+ void *c, *c2;
+
+ c = blobmsg_open_array(&b, "limits");
+
+ for (size_t i = 0; i < out.data.nNumData; i++) {
+ c2 = blobmsg_open_table(&b, "");
+ blobmsg_add_u16(&b, "first", out.data.nBandLimits[i].nFirstToneIndex);
+ blobmsg_add_u16(&b, "last", out.data.nBandLimits[i].nLastToneIndex);
+ blobmsg_close_table(&b, c2);
+ }
+
+ blobmsg_close_array(&b, c);
+}
+
+static void g977_get_bit_allocation(int fd, DSL_AccessDir_t direction) {
+ IOCTL_DIR(DSL_G997_BitAllocationNsc_t, DSL_FIO_G997_BIT_ALLOCATION_NSC_GET, direction);
+
+ // create default value to obtain consistent JSON structure
+ m_u32("groupsize", 1);
+ m_u32("groups", out.data.bitAllocationNsc.nNumData);
+ m_array("data", out.data.bitAllocationNsc.nNSCData, out.data.bitAllocationNsc.nNumData);
+}
+
+static void g977_get_snr(int fd, DSL_AccessDir_t direction) {
+ IOCTL_DIR_DELT(DSL_G997_DeltSnr_t, DSL_FIO_G997_DELT_SNR_GET, direction, DSL_DELT_DATA_SHOWTIME);
+
+ m_u32("groupsize", out.data.nGroupSize);
+ m_u32("groups", out.data.deltSnr.nNumData);
+
+ void *c = blobmsg_open_array(&b, "data");
+
+ // SNR -32 ... 95 dB
+ for (uint16_t i = 0 ; i < out.data.deltSnr.nNumData ; i++)
+ if (out.data.deltSnr.nNSCData[i] != 255 && out.data.deltSnr.nNSCData[i] != 0)
+ m_double("", -32 + (double)out.data.deltSnr.nNSCData[i] / 2);
+ else
+ m_null();
+
+ blobmsg_close_array(&b, c);
+}
+
+static void g977_get_qln(int fd, DSL_AccessDir_t direction) {
+ IOCTL_DIR_DELT(DSL_G997_DeltQln_t, DSL_FIO_G997_DELT_QLN_GET, direction, DSL_DELT_DATA_SHOWTIME);
+
+ m_u32("groupsize", out.data.nGroupSize);
+ m_u32("groups", out.data.deltQln.nNumData);
+
+ void *c = blobmsg_open_array(&b, "data");
+
+ // QLN -150 ... -23 dBm/Hz
+ for (uint16_t i = 0 ; i < out.data.deltQln.nNumData ; i++)
+ if (out.data.deltQln.nNSCData[i] != 255 && out.data.deltQln.nNSCData[i] != 0)
+ m_double("", -23 - (double)out.data.deltQln.nNSCData[i] / 2);
+ else
+ m_null();
+
+ blobmsg_close_array(&b, c);
+}
+
+static void g977_get_hlog(int fd, DSL_AccessDir_t direction) {
+ IOCTL_DIR_DELT(DSL_G997_DeltHlog_t, DSL_FIO_G997_DELT_HLOG_GET, direction, DSL_DELT_DATA_SHOWTIME);
+
+ m_u32("groupsize", out.data.nGroupSize);
+ m_u32("groups", out.data.deltHlog.nNumData);
+
+ void *c = blobmsg_open_array(&b, "data");
+
+ // HLOG +6 ... -96 dB
+ for (uint16_t i = 0 ; i < out.data.deltHlog.nNumData ; i++)
+ if (out.data.deltHlog.nNSCData[i] != 1023 && out.data.deltHlog.nNSCData[i] != 0)
+ m_double("", 6 - (double)out.data.deltHlog.nNSCData[i] / 10);
+ else
+ m_null();
+
+ blobmsg_close_array(&b, c);
+}
+
static void g997_power_management_status(int fd) {
IOCTL(DSL_G997_PowerManagementStatus_t, DSL_FIO_G997_POWER_MANAGEMENT_STATUS_GET)
@@ -477,32 +590,40 @@ static void g997_xtu_system_enabling(int fd, standard_t *standard) {
m_str("standard", str);
}
-static vector_t get_vector_status() {
+static void get_vector_status(int fd, vector_t *status) {
+ *status = VECTOR_UNKNOWN;
+
#ifdef INCLUDE_DSL_CPE_API_VRX
- int fd = open(DSL_CPE_DSL_LOW_DEV "/0", O_RDWR, 0644);
if (fd < 0)
- return VECTOR_UNKNOWN;
-
- IOCTL_MEI_dsmStatus_t out;
- memset(&out, 0, sizeof(IOCTL_MEI_dsmStatus_t));
- int ret = ioctl(fd, FIO_MEI_DSM_STATUS_GET, &out);
- close(fd);
+ return;
- if (ret)
- return VECTOR_UNKNOWN;
+ IOCTL(IOCTL_MEI_dsmStatus_t, FIO_MEI_DSM_STATUS_GET);
switch (out.eVectorStatus) {
case e_MEI_VECTOR_STAT_OFF:
- return VECTOR_OFF;
+ *status = VECTOR_OFF;
+ break;
case e_MEI_VECTOR_STAT_ON_DS:
- return VECTOR_ON_DS;
+ *status = VECTOR_ON_DS;
+ break;
case e_MEI_VECTOR_STAT_ON_DS_US:
- return VECTOR_ON_DS_US;
+ *status = VECTOR_ON_DS_US;
+ break;
default:
- return VECTOR_UNKNOWN;
+ break;
};
-#else
- return VECTOR_UNKNOWN;
+#endif
+}
+
+static void vector_erb(int fd) {
+#ifdef INCLUDE_DSL_CPE_API_VRX
+ if (fd < 0)
+ return;
+
+ IOCTL(IOCTL_MEI_dsmStatistics_t, FIO_MEI_DSM_STATISTICS_GET);
+
+ m_u32("sent", out.n_processed);
+ m_u32("discarded", out.n_fw_dropped_size + out.n_mei_dropped_size + out.n_mei_dropped_no_pp_cb + out.n_pp_dropped);
#endif
}
@@ -563,19 +684,46 @@ static void band_plan_status(int fd, profile_t *profile) {
#endif
}
-static void line_feature_config(int fd, DSL_AccessDir_t direction) {
+static void line_feature_config(int fd, DSL_AccessDir_t direction, bool *retx) {
IOCTL_DIR(DSL_LineFeature_t, DSL_FIO_LINE_FEATURE_STATUS_GET, direction)
m_bool("trellis", out.data.bTrellisEnable);
m_bool("bitswap", out.data.bBitswapEnable);
m_bool("retx", out.data.bReTxEnable);
m_bool("virtual_noise", out.data.bVirtualNoiseSupport);
+
+ *retx = out.data.bReTxEnable;
+}
+
+static void g997_rate_adaptation_status(int fd, DSL_AccessDir_t direction) {
+#ifndef INCLUDE_DSL_CPE_API_DANUBE
+ IOCTL_DIR(DSL_G997_RateAdaptationStatus_t, DSL_FIO_G997_RATE_ADAPTATION_STATUS_GET, direction);
+
+ int map = RAMODE_MAP_UNKNOWN;
+ const char *str;
+ switch (out.data.RA_MODE) {
+ STR_CASE_MAP(DSL_G997_RA_MODE_MANUAL, "Manual", RAMODE_MAP_MANUAL)
+ STR_CASE_MAP(DSL_G997_RA_MODE_AT_INIT, "At initialization", RAMODE_MAP_AT_INIT)
+ STR_CASE_MAP(DSL_G997_RA_MODE_DYNAMIC, "Dynamic", RAMODE_MAP_DYNAMIC)
+ STR_CASE_MAP(DSL_G997_RA_MODE_DYNAMIC_SOS, "Dynamic with SOS", RAMODE_MAP_DYNAMIC_SOS)
+ default:
+ str = NULL;
+ break;
+ };
+
+ if (str)
+ m_str("ra_mode", str);
+
+ if (map != PSTATE_MAP_UNKNOWN)
+ m_u32("ra_mode_num", map);
+#endif
}
static void g997_channel_status(int fd, DSL_AccessDir_t direction) {
IOCTL_DIR(DSL_G997_ChannelStatus_t, DSL_FIO_G997_CHANNEL_STATUS_GET, direction);
m_u32("interleave_delay", out.data.ActualInterleaveDelay * 10);
+ m_double("inp", (double)out.data.ActualImpulseNoiseProtection / 10);
#ifndef INCLUDE_DSL_CPE_API_DANUBE
// prefer ACTNDR, see comments in drv_dsl_cpe_api_g997.h
m_u32("data_rate", out.data.ActualNetDataRate);
@@ -587,14 +735,50 @@ static void g997_channel_status(int fd, DSL_AccessDir_t direction) {
static void g997_line_status(int fd, DSL_AccessDir_t direction) {
IOCTL_DIR_DELT(DSL_G997_LineStatus_t, DSL_FIO_G997_LINE_STATUS_GET, direction, DSL_DELT_DATA_SHOWTIME);
- m_db("latn", out.data.LATN);
- m_db("satn", out.data.SATN);
- m_db("snr", out.data.SNR);
- m_db("actps", out.data.ACTPS);
- m_db("actatp", out.data.ACTATP);
+ // invalid value indicators taken from drv_dsl_cpe_api_g997.h
+ m_db("latn", out.data.LATN, 1271);
+ m_db("satn", out.data.SATN, 1271);
+ m_db("snr", out.data.SNR, -641);
+ m_db("actps", out.data.ACTPS, -901);
+ m_db("actatp", out.data.ACTATP, -512);
m_u32("attndr", out.data.ATTNDR);
}
+static void pm_retx_counters_showtime(int fd, DSL_XTUDir_t direction) {
+#ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
+ IOCTL_DIR(DSL_PM_ReTxCounters_t, DSL_FIO_PM_RETX_COUNTERS_SHOWTIME_GET, direction);
+
+ m_u32("mineftr", out.data.nEftrMin);
+#endif
+}
+
+#ifndef INCLUDE_DSL_CPE_API_DANUBE
+static void olr_statistics(int fd, DSL_AccessDir_t direction) {
+ IOCTL_DIR(DSL_OlrStatistics_t, DSL_FIO_OLR_STATISTICS_GET, direction)
+
+ void *c = blobmsg_open_table(&b, "bitswap");
+ m_u32("requested", out.data.nBitswapRequested + out.data.nBitswapRequested);
+ m_u32("executed", out.data.nBitswapExecuted);
+ m_u32("rejected", out.data.nBitswapRejected);
+ m_u32("timeout", out.data.nBitswapTimeout);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "sra");
+ m_u32("requested", out.data.nSraRequested);
+ m_u32("executed", out.data.nSraExecuted);
+ m_u32("rejected", out.data.nSraRejected);
+ m_u32("timeout", out.data.nSraTimeout);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "sos");
+ m_u32("requested", out.data.nSosRequested);
+ m_u32("executed", out.data.nSosExecuted);
+ m_u32("rejected", out.data.nSosRejected);
+ m_u32("timeout", out.data.nSosTimeout);
+ blobmsg_close_table(&b, c);
+}
+#endif
+
static void pm_line_sec_counters_total(int fd, DSL_XTUDir_t direction) {
IOCTL_DIR(DSL_PM_LineSecCountersTotal_t, DSL_FIO_PM_LINE_SEC_COUNTERS_TOTAL_GET, direction)
@@ -608,6 +792,21 @@ static void pm_line_sec_counters_total(int fd, DSL_XTUDir_t direction) {
#endif
}
+static void pm_retx_counters_total(int fd, DSL_XTUDir_t direction) {
+#ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
+ IOCTL_DIR(DSL_PM_ReTxCountersTotal_t, DSL_FIO_PM_RETX_COUNTERS_TOTAL_GET, direction);
+
+ m_u32("leftrs", out.data.nLeftr);
+#endif
+}
+
+static void pm_channel_counters_total(int fd, DSL_XTUDir_t direction) {
+ IOCTL_DIR(DSL_PM_ChannelCountersTotal_t, DSL_FIO_PM_CHANNEL_COUNTERS_TOTAL_GET, direction);
+
+ m_u32("cv_c", out.data.nCodeViolations);
+ m_u32("fec_c", out.data.nFEC);
+}
+
static void pm_data_path_counters_total(int fd, DSL_XTUDir_t direction) {
IOCTL_DIR(DSL_PM_DataPathCountersTotal_t, DSL_FIO_PM_DATA_PATH_COUNTERS_TOTAL_GET, direction);
@@ -716,24 +915,102 @@ static void describe_mode(standard_t standard, profile_t profile, vector_t vecto
m_str("mode", buf);
}
+static int line_statistics(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int fd;
+ void *c, *c2;
+
+#ifndef INCLUDE_DSL_CPE_API_DANUBE
+ fd = open(DSL_CPE_DEVICE_NAME "/0", O_RDWR, 0644);
+#else
+ fd = open(DSL_CPE_DEVICE_NAME, O_RDWR, 0644);
+#endif
+ if (fd < 0)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ blob_buf_init(&b, 0);
+
+ pilot_tones_status(fd);
+
+ c = blobmsg_open_table(&b, "bands");
+ c2 = blobmsg_open_table(&b, "downstream");
+ band_border_status(fd, DSL_DOWNSTREAM);
+ blobmsg_close_table(&b, c2);
+ c2 = blobmsg_open_table(&b, "upstream");
+ band_border_status(fd, DSL_UPSTREAM);
+ blobmsg_close_table(&b, c2);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "bits");
+ c2 = blobmsg_open_table(&b, "downstream");
+ g977_get_bit_allocation(fd, DSL_DOWNSTREAM);
+ blobmsg_close_table(&b, c2);
+ c2 = blobmsg_open_table(&b, "upstream");
+ g977_get_bit_allocation(fd, DSL_UPSTREAM);
+ blobmsg_close_table(&b, c2);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "snr");
+ c2 = blobmsg_open_table(&b, "downstream");
+ g977_get_snr(fd, DSL_DOWNSTREAM);
+ blobmsg_close_table(&b, c2);
+ c2 = blobmsg_open_table(&b, "upstream");
+ g977_get_snr(fd, DSL_UPSTREAM);
+ blobmsg_close_table(&b, c2);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "qln");
+ c2 = blobmsg_open_table(&b, "downstream");
+ g977_get_qln(fd, DSL_DOWNSTREAM);
+ blobmsg_close_table(&b, c2);
+ c2 = blobmsg_open_table(&b, "upstream");
+ g977_get_qln(fd, DSL_UPSTREAM);
+ blobmsg_close_table(&b, c2);
+ blobmsg_close_table(&b, c);
+
+ c = blobmsg_open_table(&b, "hlog");
+ c2 = blobmsg_open_table(&b, "downstream");
+ g977_get_hlog(fd, DSL_DOWNSTREAM);
+ blobmsg_close_table(&b, c2);
+ c2 = blobmsg_open_table(&b, "upstream");
+ g977_get_hlog(fd, DSL_UPSTREAM);
+ blobmsg_close_table(&b, c2);
+ blobmsg_close_table(&b, c);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ close(fd);
+
+ return 0;
+}
+
static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
- int fd;
+ int fd, fd_mei;
void *c, *c2;
standard_t standard = STD_UNKNOWN;
profile_t profile = PROFILE_UNKNOWN;
vector_t vector = VECTOR_UNKNOWN;
+ bool retx_up = false, retx_down = false;
#ifndef INCLUDE_DSL_CPE_API_DANUBE
- fd = open(DSL_CPE_DEVICE_NAME "0", O_RDWR, 0644);
+ fd = open(DSL_CPE_DEVICE_NAME "/0", O_RDWR, 0644);
#else
fd = open(DSL_CPE_DEVICE_NAME, O_RDWR, 0644);
#endif
if (fd < 0)
return UBUS_STATUS_UNKNOWN_ERROR;
+#ifdef INCLUDE_DSL_CPE_API_VRX
+ fd_mei = open(DSL_CPE_DSL_LOW_DEV "/0", O_RDWR, 0644);
+#else
+ fd_mei = -1;
+#endif
+
blob_buf_init(&b, 0);
version_information(fd);
@@ -749,7 +1026,7 @@ static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
if (standard == STD_G_993_2) {
band_plan_status(fd, &profile);
- vector = get_vector_status();
+ get_vector_status(fd_mei, &vector);
}
describe_mode(standard, profile, vector);
@@ -765,9 +1042,12 @@ static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
default:
break;
};
- line_feature_config(fd, DSL_UPSTREAM);
+ line_feature_config(fd, DSL_UPSTREAM, &retx_up);
+ g997_rate_adaptation_status(fd, DSL_UPSTREAM);
g997_channel_status(fd, DSL_UPSTREAM);
g997_line_status(fd, DSL_UPSTREAM);
+ if (retx_up)
+ pm_retx_counters_showtime(fd, DSL_FAR_END);
blobmsg_close_table(&b, c);
c = blobmsg_open_table(&b, "downstream");
@@ -782,27 +1062,60 @@ static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
default:
break;
};
- line_feature_config(fd, DSL_DOWNSTREAM);
+ line_feature_config(fd, DSL_DOWNSTREAM, &retx_down);
+ g997_rate_adaptation_status(fd, DSL_DOWNSTREAM);
g997_channel_status(fd, DSL_DOWNSTREAM);
g997_line_status(fd, DSL_DOWNSTREAM);
+ if (retx_down)
+ pm_retx_counters_showtime(fd, DSL_NEAR_END);
+ blobmsg_close_table(&b, c);
+
+#ifndef INCLUDE_DSL_CPE_API_DANUBE
+ c = blobmsg_open_table(&b, "olr");
+ c2 = blobmsg_open_table(&b, "downstream");
+ olr_statistics(fd, DSL_DOWNSTREAM);
+ blobmsg_close_table(&b, c2);
+ c2 = blobmsg_open_table(&b, "upstream");
+ olr_statistics(fd, DSL_UPSTREAM);
+ blobmsg_close_table(&b, c2);
blobmsg_close_table(&b, c);
+#endif
c = blobmsg_open_table(&b, "errors");
c2 = blobmsg_open_table(&b, "near");
pm_line_sec_counters_total(fd, DSL_NEAR_END);
+ if (retx_down)
+ pm_retx_counters_total(fd, DSL_NEAR_END);
+ pm_channel_counters_total(fd, DSL_NEAR_END);
pm_data_path_counters_total(fd, DSL_NEAR_END);
retx_statistics(fd, DSL_NEAR_END);
blobmsg_close_table(&b, c2);
c2 = blobmsg_open_table(&b, "far");
pm_line_sec_counters_total(fd, DSL_FAR_END);
+ if (retx_up)
+ pm_retx_counters_total(fd, DSL_FAR_END);
+ pm_channel_counters_total(fd, DSL_FAR_END);
pm_data_path_counters_total(fd, DSL_FAR_END);
retx_statistics(fd, DSL_FAR_END);
blobmsg_close_table(&b, c2);
blobmsg_close_table(&b, c);
+ switch (vector) {
+ case VECTOR_ON_DS:
+ case VECTOR_ON_DS_US:
+ c = blobmsg_open_table(&b, "erb");
+ vector_erb(fd_mei);
+ blobmsg_close_table(&b, c);
+ break;
+ default:
+ break;
+ };
+
ubus_send_reply(ctx, req, b.head);
+ if (fd_mei >= 0)
+ close(fd_mei);
close(fd);
return 0;
@@ -810,6 +1123,7 @@ static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
static const struct ubus_method dsl_methods[] = {
UBUS_METHOD_NOARG("metrics", metrics),
+ UBUS_METHOD_NOARG("statistics", line_statistics)
};
static struct ubus_object_type dsl_object_type =
diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile
index 62f3b600862..ba4516c1dc6 100644
--- a/package/network/config/netifd/Makefile
+++ b/package/network/config/netifd/Makefile
@@ -5,21 +5,23 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
-PKG_SOURCE_DATE:=2021-07-14
-PKG_SOURCE_VERSION:=7f24a063475e1e2be4e0c516a5b62c3fae5ec542
-PKG_MIRROR_HASH:=3fad25b8655e01e20f54b6c6decad6a660a34ab3ca2de97fe3c9b7db5aa485fe
+PKG_SOURCE_DATE:=2024-01-04
+PKG_SOURCE_VERSION:=f01345ec13b9b27ffd314d8689fb2d3f9c81a47d
+PKG_MIRROR_HASH:=58e92e9ce1a2c8ccb487e95dadf806f38b38abbe7cb3cde61ff880de5eb85c2f
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=
+PKG_BUILD_FLAGS:=lto
+
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/netifd
SECTION:=base
CATEGORY:=Base system
- DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox
+ DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox +libudebug
TITLE:=OpenWrt Network Interface Configuration Daemon
endef
@@ -30,10 +32,7 @@ endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include/libnl-tiny \
- -I$(STAGING_DIR)/usr/include \
- -flto
-
-TARGET_LDFLAGS += -flto -fuse-linker-plugin
+ -I$(STAGING_DIR)/usr/include
CMAKE_OPTIONS += \
-DLIBNL_LIBS=-lnl-tiny \
@@ -44,7 +43,10 @@ define Package/netifd/install
$(INSTALL_BIN) $(PKG_BUILD_DIR)/netifd $(1)/sbin/
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/etc/udhcpc.user.d/
- $(CP) $(PKG_BUILD_DIR)/scripts/* $(1)/lib/netifd/
+ $(CP) \
+ $(PKG_BUILD_DIR)/scripts/utils.sh \
+ $(PKG_BUILD_DIR)/scripts/netifd-proto.sh \
+ $(1)/lib/netifd/
endef
$(eval $(call BuildPackage,netifd))
diff --git a/package/network/config/netifd/files/etc/init.d/packet_steering b/package/network/config/netifd/files/etc/init.d/packet_steering
new file mode 100755
index 00000000000..9d8f791e23b
--- /dev/null
+++ b/package/network/config/netifd/files/etc/init.d/packet_steering
@@ -0,0 +1,18 @@
+#!/bin/sh /etc/rc.common
+
+START=25
+USE_PROCD=1
+
+start_service() {
+ reload_service
+}
+
+service_triggers() {
+ procd_add_reload_trigger "network"
+ procd_add_reload_trigger "firewall"
+ procd_add_raw_trigger "interface.*" 1000 /etc/init.d/packet_steering reload
+}
+
+reload_service() {
+ /usr/libexec/network/packet-steering.sh
+}
diff --git a/package/network/config/netifd/files/lib/netifd/dhcp.script b/package/network/config/netifd/files/lib/netifd/dhcp.script
index e46005d84c6..db8deac9e67 100755
--- a/package/network/config/netifd/files/lib/netifd/dhcp.script
+++ b/package/network/config/netifd/files/lib/netifd/dhcp.script
@@ -18,13 +18,13 @@ setup_interface () {
proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
# TODO: apply $broadcast
- local ip_net
- eval "$(ipcalc.sh "$ip/$mask")";ip_net="$NETWORK"
+ local ip_net IP PREFIX NETWORK NETMASK BROADCAST
+ ipcalc "$ip/$mask" && ip_net="$NETWORK"
local i
for i in $router; do
local gw_net
- eval "$(ipcalc.sh "$i/$mask")";gw_net="$NETWORK"
+ ipcalc "$i/$mask" && gw_net="$NETWORK"
[ "$ip_net" != "$gw_net" ] && proto_add_ipv4_route "$i" 32 "" "$ip"
proto_add_ipv4_route 0.0.0.0 0 "$i" "$ip"
@@ -60,6 +60,7 @@ setup_interface () {
[ -n "$message" ] && json_add_string message "$message"
[ -n "$timezone" ] && json_add_int timezone "$timezone"
[ -n "$lease" ] && json_add_int leasetime "$lease"
+ [ -n "$serverid" ] && json_add_string dhcpserver "$serverid"
proto_close_data
proto_send_update "$INTERFACE"
diff --git a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
index 3034b2ba68e..636b4654ff0 100755
--- a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
+++ b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-[ -L /sbin/udhcpc ] || exit 0
+[ -x /sbin/udhcpc ] || exit 0
. /lib/functions.sh
. ../netifd-proto.sh
@@ -67,7 +67,7 @@ proto_dhcp_setup() {
-p /var/run/udhcpc-$iface.pid \
-s /lib/netifd/dhcp.script \
-f -t 0 -i "$iface" \
- ${ipaddr:+-r $ipaddr} \
+ ${ipaddr:+-r ${ipaddr/\/*/}} \
${hostname:+-x "hostname:$hostname"} \
${vendorid:+-V "$vendorid"} \
$clientid $defaultreqopts $broadcast $norelease $dhcpopts
diff --git a/package/network/config/netifd/files/sbin/ifup b/package/network/config/netifd/files/sbin/ifup
index 15be535bbfc..fbf2fd80c7e 100755
--- a/package/network/config/netifd/files/sbin/ifup
+++ b/package/network/config/netifd/files/sbin/ifup
@@ -1,7 +1,6 @@
#!/bin/sh
ifup_all=
-setup_wifi=
if_call() {
local interface="$1"
@@ -14,7 +13,6 @@ case "$0" in
*ifdown) modes=down;;
*ifup)
modes="down up"
- setup_wifi=1
;;
*) echo "Invalid command: $0";;
esac
@@ -25,10 +23,6 @@ while :; do
ifup_all=1
shift
;;
- -w)
- setup_wifi=
- shift
- ;;
*)
break
;;
@@ -40,7 +34,6 @@ if [ -n "$ifup_all" ]; then
for interface in $(ubus -S list 'network.interface.*'); do
if_call "${interface##network.interface.}"
done
- [ -n "$setup_wifi" ] && /sbin/wifi up
exit
else
ubus -S list "network.interface.$1" > /dev/null || {
@@ -49,29 +42,3 @@ else
}
if_call "$1"
fi
-
-if [ -n "$setup_wifi" ] && grep -sq config /etc/config/wireless; then
- . /lib/functions.sh
-
- find_related_radios() {
- local wdev wnet
- config_get wdev "$1" device
- config_get wnet "$1" network
-
- if [ -n "$wdev" ]; then
- for wnet in $wnet; do
- if [ "$wnet" = "$network" ]; then
- append radio_devs "$wdev" "$N"
- fi
- done
- fi
- }
-
- network="$1"
- config_load wireless
- config_foreach find_related_radios wifi-iface
-
- for dev in $(echo "$radio_devs" | sort -u); do
- /sbin/wifi up "$dev"
- done
-fi
diff --git a/package/network/config/netifd/files/etc/hotplug.d/net/20-smp-packet-steering b/package/network/config/netifd/files/usr/libexec/network/packet-steering.sh
index 8a86bf75f60..799c0808053 100644..100755
--- a/package/network/config/netifd/files/etc/hotplug.d/net/20-smp-packet-steering
+++ b/package/network/config/netifd/files/usr/libexec/network/packet-steering.sh
@@ -1,6 +1,4 @@
#!/bin/sh
-[ "$ACTION" = add ] || exit
-
NPROCS="$(grep -c "^processor.*:" /proc/cpuinfo)"
[ "$NPROCS" -gt 1 ] || exit
@@ -40,6 +38,11 @@ packet_steering="$(uci get "network.@globals[0].packet_steering")"
exec 512>/var/lock/smp_tune.lock
flock 512 || exit 1
+[ -e "/usr/libexec/platform/packet-steering.sh" ] && {
+ /usr/libexec/platform/packet-steering.sh
+ exit 0
+}
+
for dev in /sys/class/net/*; do
[ -d "$dev" ] || continue
diff --git a/package/network/config/qos-scripts/Makefile b/package/network/config/qos-scripts/Makefile
index d6e7df14670..774ce4d94a4 100644
--- a/package/network/config/qos-scripts/Makefile
+++ b/package/network/config/qos-scripts/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=qos-scripts
PKG_VERSION:=1.3.1
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=33
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
diff --git a/package/network/config/qos-scripts/files/usr/bin/qos-start b/package/network/config/qos-scripts/files/usr/bin/qos-start
index 68dae706389..13d77720958 100755
--- a/package/network/config/qos-scripts/files/usr/bin/qos-start
+++ b/package/network/config/qos-scripts/files/usr/bin/qos-start
@@ -1,4 +1,4 @@
#!/bin/sh
-qos-stop
+qos-stop
/usr/lib/qos/generate.sh all | sh
diff --git a/package/network/config/qos-scripts/files/usr/bin/qos-stat b/package/network/config/qos-scripts/files/usr/bin/qos-stat
index 03b737c89dc..454e18aa72e 100755
--- a/package/network/config/qos-scripts/files/usr/bin/qos-stat
+++ b/package/network/config/qos-scripts/files/usr/bin/qos-stat
@@ -32,7 +32,7 @@ print_comments() {
echo '# Direction: '"$2"
echo '# Stats: '"$3"
echo ''
-}
+}
get_device() {
( config_load network; scan_interfaces; config_get "$1" ifname )
diff --git a/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh b/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
index 62e7283633e..13aa173d182 100755
--- a/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
+++ b/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
@@ -2,11 +2,10 @@
[ -e /lib/functions.sh ] && . /lib/functions.sh || . ./functions.sh
[ -x /sbin/modprobe ] && {
insmod="modprobe"
- rmmod="$insmod -r"
} || {
insmod="insmod"
- rmmod="rmmod"
}
+rmmod="rmmod"
add_insmod() {
eval "export isset=\${insmod_$1}"
@@ -65,7 +64,7 @@ parse_matching_rule() {
append "$var" "${proto:+-p $proto}"
for option in $options; do
config_get value "$section" "$option"
-
+
case "$pkt:$option" in
*:srchost)
append "$var" "-s $value"
@@ -283,14 +282,14 @@ start_interface() {
config_get device "$iface" device
config_get_bool enabled "$iface" enabled 1
[ -z "$device" -o 1 -ne "$enabled" ] && {
- return 1
+ return 1
}
config_get upload "$iface" upload
config_get_bool halfduplex "$iface" halfduplex
config_get download "$iface" download
config_get classgroup "$iface" classgroup
config_get_bool overhead "$iface" overhead 0
-
+
download="${download:-${halfduplex:+$upload}}"
enum_classes "$classgroup"
for dir in ${halfduplex:-up} ${download:+down}; do
@@ -374,7 +373,7 @@ add_rules() {
local var="$1"
local rules="$2"
local prefix="$3"
-
+
for rule in $rules; do
unset iptrule
config_get target "$rule" target
@@ -438,7 +437,7 @@ EOF
for command in $iptables; do
cat <<EOF
- $command -w -t mangle -N qos_${cg}
+ $command -w -t mangle -N qos_${cg}
$command -w -t mangle -N qos_${cg}_ct
EOF
done
diff --git a/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk b/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
index 21df391054f..be95f99b01d 100644
--- a/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
+++ b/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
@@ -103,4 +103,3 @@ END {
}
}
}
-
diff --git a/package/network/config/qosify/Makefile b/package/network/config/qosify/Makefile
new file mode 100644
index 00000000000..f4ad0422354
--- /dev/null
+++ b/package/network/config/qosify/Makefile
@@ -0,0 +1,76 @@
+#
+# Copyright (C) 2021 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=qosify
+PKG_SOURCE_URL=$(PROJECT_GIT)/project/qosify.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_DATE:=2023-03-07
+PKG_SOURCE_VERSION:=9a47ea4b683dd845ec94534fcd82d3117c9ab313
+PKG_MIRROR_HASH:=c4c313aed4a405492201612bdfef5e219c9a994a35f35acc84fc8327d9aa73d2
+PKG_RELEASE:=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_DEPENDS:=bpf-headers
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+include $(INCLUDE_DIR)/bpf.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/qosify
+ SECTION:=utils
+ CATEGORY:=Base system
+ TITLE:=A simple QoS solution based eBPF + CAKE
+ DEPENDS:=+libbpf +libubox +libubus +libnl-tiny +kmod-sched-cake +kmod-sched-bpf +kmod-ifb +tc $(BPF_DEPENDS)
+endef
+
+TARGET_CFLAGS += \
+ -Wno-error=deprecated-declarations \
+ -I$(STAGING_DIR)/usr/include/libnl-tiny \
+ -I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS += \
+ -DLIBNL_LIBS=-lnl-tiny
+
+define Build/Compile
+ $(call CompileBPF,$(PKG_BUILD_DIR)/qosify-bpf.c)
+ $(Build/Compile/Default)
+endef
+
+define Package/qosify/conffiles
+/etc/config/qosify
+/etc/qosify/00-defaults.conf
+endef
+
+define Package/qosify/install
+ $(INSTALL_DIR) \
+ $(1)/lib/bpf \
+ $(1)/usr/sbin \
+ $(1)/etc/init.d \
+ $(1)/etc/config \
+ $(1)/etc/qosify \
+ $(1)/etc/hotplug.d/net \
+ $(1)/etc/hotplug.d/iface
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/qosify-bpf.o $(1)/lib/bpf
+ $(INSTALL_BIN) \
+ $(PKG_INSTALL_DIR)/usr/bin/qosify \
+ ./files/qosify-status \
+ $(1)/usr/sbin/
+ $(INSTALL_BIN) ./files/qosify.init $(1)/etc/init.d/qosify
+ $(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify/00-defaults.conf
+ $(INSTALL_DATA) ./files/qosify.conf $(1)/etc/config/qosify
+ $(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/net/10-qosify
+ $(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/iface/10-qosify
+endef
+
+$(eval $(call BuildPackage,qosify))
diff --git a/package/network/config/qosify/files/qosify-defaults.conf b/package/network/config/qosify/files/qosify-defaults.conf
new file mode 100644
index 00000000000..ff8a0bef5b1
--- /dev/null
+++ b/package/network/config/qosify/files/qosify-defaults.conf
@@ -0,0 +1,17 @@
+# DNS
+tcp:53 voice
+tcp:5353 voice
+udp:53 voice
+udp:5353 voice
+
+# NTP
+udp:123 voice
+
+# SSH
+tcp:22 +video
+
+# HTTP/QUIC
+tcp:80 +besteffort
+tcp:443 +besteffort
+udp:80 +besteffort
+udp:443 +besteffort
diff --git a/package/network/config/qosify/files/qosify-status b/package/network/config/qosify/files/qosify-status
new file mode 100644
index 00000000000..dc582322681
--- /dev/null
+++ b/package/network/config/qosify/files/qosify-status
@@ -0,0 +1,70 @@
+#!/bin/sh
+. /usr/share/libubox/jshn.sh
+
+dev_status() {
+ tc -s qdisc sh dev "$1" root
+ echo
+}
+
+common_status() {
+ json_get_vars ifname ingress egress
+
+ [ -n "$ifname" ] || return
+
+ [ "$egress" -gt 0 ] && {
+ echo "egress status:"
+ dev_status "$ifname"
+ }
+ [ "$ingress" -gt 0 ] && {
+ echo "ingress status:"
+ dev_status "$(printf %.16s "ifb-$ifname")"
+ }
+}
+
+is_active() {
+ json_get_vars active
+
+ [ "${active:-0}" -gt 0 ]
+}
+
+device_status() {
+ local name="$2"
+
+ json_select "$name"
+
+ if is_active; then
+ status="active"
+ else
+ status="not found"
+ fi
+
+ echo "===== device $name: $status ====="
+
+ is_active && common_status
+
+ json_select ..
+}
+
+interface_status() {
+ local name="$2"
+
+ json_select "$name"
+
+ if is_active; then
+ status="active"
+ elif ubus -S -t 0 wait_for "network.interface.$name"; then
+ status="down"
+ else
+ status="not found"
+ fi
+
+ echo "===== interface $name: $status ====="
+
+ is_active && common_status
+
+ json_select ..
+}
+
+json_load "$(ubus call qosify status)"
+json_for_each_item device_status devices
+json_for_each_item interface_status interfaces
diff --git a/package/network/config/qosify/files/qosify.conf b/package/network/config/qosify/files/qosify.conf
new file mode 100644
index 00000000000..7a3d0d068ad
--- /dev/null
+++ b/package/network/config/qosify/files/qosify.conf
@@ -0,0 +1,48 @@
+config defaults
+ list defaults /etc/qosify/*.conf
+ option dscp_prio video
+ option dscp_icmp +besteffort
+ option dscp_default_udp besteffort
+ option prio_max_avg_pkt_len 500
+
+config class besteffort
+ option ingress CS0
+ option egress CS0
+
+config class bulk
+ option ingress LE
+ option egress LE
+
+config class video
+ option ingress AF41
+ option egress AF41
+
+config class voice
+ option ingress CS6
+ option egress CS6
+ option bulk_trigger_pps 100
+ option bulk_trigger_timeout 5
+ option dscp_bulk CS0
+
+config interface wan
+ option name wan
+ option disabled 1
+ option bandwidth_up 100mbit
+ option bandwidth_down 100mbit
+ option overhead_type none
+ # defaults:
+ option ingress 1
+ option egress 1
+ option mode diffserv4
+ option nat 1
+ option host_isolate 1
+ option autorate_ingress 0
+ option ingress_options ""
+ option egress_options ""
+ option options ""
+
+config device wandev
+ option disabled 1
+ option name wan
+ option bandwidth 100mbit
+
diff --git a/package/network/config/qosify/files/qosify.hotplug b/package/network/config/qosify/files/qosify.hotplug
new file mode 100644
index 00000000000..950812c03c2
--- /dev/null
+++ b/package/network/config/qosify/files/qosify.hotplug
@@ -0,0 +1,2 @@
+#!/bin/sh
+ubus call qosify check_devices
diff --git a/package/network/config/qosify/files/qosify.init b/package/network/config/qosify/files/qosify.init
new file mode 100644
index 00000000000..f676d92a52e
--- /dev/null
+++ b/package/network/config/qosify/files/qosify.init
@@ -0,0 +1,171 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2021 OpenWrt.org
+
+START=19
+
+USE_PROCD=1
+PROG=/usr/sbin/qosify
+
+add_option() {
+ local type="$1"
+ local name="$2"
+
+ config_get val "$cfg" "$name"
+
+ [ -n "$val" ] && json_add_$type "$name" "$val"
+}
+
+add_flow_config() {
+ local cfg="$1"
+
+ add_option string dscp_prio
+ add_option string dscp_bulk
+ add_option int bulk_trigger_timeout
+ add_option int bulk_trigger_pps
+ add_option int prio_max_avg_pkt_len
+}
+
+add_defaults() {
+ cfg="$1"
+
+ json_add_boolean reset 1
+
+ config_get files "$cfg" defaults
+ json_add_array files
+ for i in $files; do
+ json_add_string "" "$i"
+ done
+ json_close_array
+
+ add_flow_config "$cfg"
+ add_option int timeout
+ add_option string dscp_icmp
+ add_option string dscp_default_udp
+ add_option string dscp_default_tcp
+}
+
+add_interface() {
+ local cfg="$1"
+
+ config_get_bool disabled "$cfg" disabled 0
+ [ "$disabled" -gt 0 ] && return
+
+ config_get name "$cfg" name
+ json_add_object "$name"
+
+ config_get bw "$cfg" bandwidth
+
+ config_get bw_up "$cfg" bandwidth_up
+ bw_up="${bw_up:-$bw}"
+ [ -n "$bw_up" ] && json_add_string bandwidth_up "$bw_up"
+
+ config_get bw_down "$cfg" bandwidth_down
+ bw_down="${bw_down:-$bw}"
+ [ -n "$bw_down" ] && json_add_string bandwidth_down "$bw_down"
+
+ add_option string bandwidth
+ add_option boolean ingress
+ add_option boolean egress
+ add_option string mode
+ add_option boolean nat
+ add_option boolean host_isolate
+ add_option boolean autorate_ingress
+ add_option string ingress_options
+ add_option string egress_options
+
+ config_get user_options "$cfg" options
+
+ config_get otype "$cfg" overhead_type
+ options=
+ case "$otype" in
+ none);;
+ manual)
+ config_get overhead "$cfg" overhead
+ [ -n "$overhead" ] && append options "overhead $overhead"
+
+ config_get encap "$cfg" overhead_encap
+ [ -n "$encap" ] && append options "$encap"
+ ;;
+ conservative|\
+ pppoa-vcmux|\
+ pppoa-llc|\
+ pppoe-vcmux|\
+ pppoe-llcsnap|\
+ bridged-vcmux|\
+ bridged-llcsnap|\
+ ipoa-vcmux|\
+ ipoa-llcsnap|\
+ pppoe-ptm|\
+ bridged-ptm|\
+ docsis|\
+ ethernet)
+ append options "$otype"
+ ;;
+ esac
+
+ config_get mpu "$cfg" overhead_mpu
+ [ -n "$mpu" ] && append options "mpu $mpu"
+
+ config_get ovlan "$cfg" overhead_vlan
+ [ "${ovlan:-0}" -ge 2 ] && append options "ether-vlan"
+ [ "${ovlan:-0}" -ge 1 ] && append options "ether-vlan"
+
+ [ -n "$user_options" ] && append options "$user_options"
+ [ -n "$options" ] && json_add_string options "$options"
+
+ json_close_object
+}
+
+add_class() {
+ local cfg="$1"
+
+ config_get value "$cfg" value
+ config_get ingress "$cfg" ingress
+ config_get egress "$cfg" egress
+
+ json_add_object "$cfg"
+ json_add_string ingress "${ingress:-$value}"
+ json_add_string egress "${egress:-$value}"
+ add_flow_config "$cfg"
+ json_close_object
+}
+
+
+reload_service() {
+ json_init
+
+ config_load qosify
+
+ config_foreach add_defaults defaults
+
+ json_add_object interfaces
+ config_foreach add_interface interface
+ json_close_object
+
+ json_add_object classes
+ config_foreach add_class class
+ config_foreach add_class alias
+ json_close_object
+
+ json_add_object devices
+ config_foreach add_interface device
+ json_close_object
+
+ ubus call qosify config "$(json_dump)"
+}
+
+service_triggers() {
+ procd_add_reload_trigger qosify
+}
+
+start_service() {
+ procd_open_instance
+ procd_set_param command "$PROG"
+ procd_set_param respawn
+ procd_close_instance
+}
+
+service_started() {
+ ubus -t 10 wait_for qosify
+ [ $? = 0 ] && reload_service
+}
diff --git a/package/network/config/swconfig/Makefile b/package/network/config/swconfig/Makefile
index 4d3e572d824..6549075e5c5 100644
--- a/package/network/config/swconfig/Makefile
+++ b/package/network/config/swconfig/Makefile
@@ -13,6 +13,8 @@ PKG_RELEASE:=12
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
+PKG_BUILD_FLAGS:=lto
+
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/kernel.mk
@@ -23,9 +25,6 @@ define Package/swconfig
TITLE:=Switch configuration utility
endef
-TARGET_CFLAGS += -flto
-TARGET_LDFLAGS += -flto=jobserver
-
TARGET_CPPFLAGS := \
-D_GNU_SOURCE \
-I$(STAGING_DIR)/usr/include/libnl-tiny \
diff --git a/package/network/config/swconfig/src/cli.c b/package/network/config/swconfig/src/cli.c
index eab6c64742e..2601f346db1 100644
--- a/package/network/config/swconfig/src/cli.c
+++ b/package/network/config/swconfig/src/cli.c
@@ -102,6 +102,24 @@ speed_str(int speed)
}
static void
+free_attr_val(const struct switch_attr *attr, const struct switch_val *val)
+{
+ switch (attr->type) {
+ case SWITCH_TYPE_STRING:
+ free(val->value.s);
+ break;
+ case SWITCH_TYPE_PORTS:
+ free(val->value.ports);
+ break;
+ case SWITCH_TYPE_LINK:
+ free(val->value.link);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
print_attr_val(const struct switch_attr *attr, const struct switch_val *val)
{
struct switch_port_link *link;
@@ -150,8 +168,10 @@ show_attrs(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *
printf("\t%s: ", attr->name);
if (swlib_get_attr(dev, attr, val) < 0)
printf("???");
- else
+ else {
print_attr_val(attr, val);
+ free_attr_val(attr, val);
+ }
putchar('\n');
}
attr = attr->next;
@@ -354,6 +374,7 @@ int main(int argc, char **argv)
goto out;
}
print_attr_val(a, &val);
+ free_attr_val(a, &val);
putchar('\n');
break;
case CMD_LOAD:
diff --git a/package/network/config/swconfig/src/uci.c b/package/network/config/swconfig/src/uci.c
index f99583b483a..200069f94f3 100644
--- a/package/network/config/swconfig/src/uci.c
+++ b/package/network/config/swconfig/src/uci.c
@@ -164,32 +164,7 @@ found:
struct uci_element *os;
s = uci_to_section(e);
- if (!strcmp(s->type, "switch_port")) {
- char *devn = NULL, *port = NULL, *port_err = NULL;
- int port_n;
-
- uci_foreach_element(&s->options, os) {
- o = uci_to_option(os);
- if (o->type != UCI_TYPE_STRING)
- continue;
-
- if (!strcmp(os->name, "device")) {
- devn = o->v.string;
- if (!swlib_match_name(dev, devn))
- devn = NULL;
- } else if (!strcmp(os->name, "port")) {
- port = o->v.string;
- }
- }
- if (!devn || !port || !port[0])
- continue;
-
- port_n = strtoul(port, &port_err, 0);
- if (port_err && port_err[0])
- continue;
-
- swlib_map_settings(dev, SWLIB_ATTR_GROUP_PORT, port_n, s);
- } else if (!strcmp(s->type, "switch_vlan")) {
+ if (!strcmp(s->type, "switch_vlan")) {
char *devn = NULL, *vlan = NULL, *vlan_err = NULL;
int vlan_n;
@@ -216,6 +191,38 @@ found:
swlib_map_settings(dev, SWLIB_ATTR_GROUP_VLAN, vlan_n, s);
}
}
+ uci_foreach_element(&p->sections, e) {
+ struct uci_element *os;
+ char *devn = NULL, *port = NULL, *port_err = NULL;
+ int port_n;
+
+ s = uci_to_section(e);
+
+ if (strcmp(s->type, "switch_port"))
+ continue;
+
+ uci_foreach_element(&s->options, os) {
+ o = uci_to_option(os);
+ if (o->type != UCI_TYPE_STRING)
+ continue;
+
+ if (!strcmp(os->name, "device")) {
+ devn = o->v.string;
+ if (!swlib_match_name(dev, devn))
+ devn = NULL;
+ } else if (!strcmp(os->name, "port")) {
+ port = o->v.string;
+ }
+ }
+ if (!devn || !port || !port[0])
+ continue;
+
+ port_n = strtoul(port, &port_err, 0);
+ if (port_err && port_err[0])
+ continue;
+
+ swlib_map_settings(dev, SWLIB_ATTR_GROUP_PORT, port_n, s);
+ }
for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
struct swlib_setting *st = &early_settings[i];
diff --git a/package/network/config/vti/Makefile b/package/network/config/vti/Makefile
index 292ab111e5c..548b8f951f7 100644
--- a/package/network/config/vti/Makefile
+++ b/package/network/config/vti/Makefile
@@ -8,47 +8,28 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=vti
-PKG_RELEASE:=4
+PKG_RELEASE:=5
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define Package/vti/Default
- SECTION:=net
- CATEGORY:=Network
- MAINTAINER:=Andre Valentin <avalentin@marcant.net>
- PKGARCH:=all
endef
define Package/vti
-$(call Package/vti/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ MAINTAINER:=Andre Valentin <avalentin@marcant.net>
TITLE:=Virtual IPsec Tunnel Interface config support
+ DEPENDS:=+kmod-ip-vti +IPV6:kmod-ip6-vti
+ PROVIDES:=vtiv4 vtiv6
+ PKGARCH:=all
endef
define Package/vti/description
Virtual IPsec Tunnel Interface config support (IPv4 and IPv6) in /etc/config/network.
endef
-define Package/vtiv4
-$(call Package/vti/Default)
- TITLE:=Virtual IPsec Tunnel Interface (IPv4) config support
- DEPENDS:=@(PACKAGE_vti) +kmod-ip-vti
-endef
-
-define Package/vtiv4/description
- Virtual IPsec Tunnel Interface config support (IPv4) in /etc/config/network.
-endef
-
-define Package/vtiv6
-$(call Package/vti/Default)
- TITLE:=Virtual IPsec Tunnel Interface (IPv6) config support
- DEPENDS:=@(PACKAGE_vti) @IPV6 +kmod-ip6-vti
-endef
-
-define Package/vtiv6/description
- Virtual IPsec Tunnel Interface config support (IPv6) in /etc/config/network.
-endef
-
define Build/Compile
endef
@@ -60,14 +41,4 @@ define Package/vti/install
$(INSTALL_BIN) ./files/vti.sh $(1)/lib/netifd/proto/vti.sh
endef
-define Package/vtiv4/install
- :
-endef
-
-define Package/vtiv6/install
- :
-endef
-
$(eval $(call BuildPackage,vti))
-$(eval $(call BuildPackage,vtiv4))
-$(eval $(call BuildPackage,vtiv6))
diff --git a/package/network/config/wifi-scripts/Makefile b/package/network/config/wifi-scripts/Makefile
new file mode 100644
index 00000000000..085860d7c69
--- /dev/null
+++ b/package/network/config/wifi-scripts/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2024 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wifi-scripts
+PKG_VERSION:=1.0
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-2.0
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/wifi-scripts
+ SECTION:=utils
+ CATEGORY:=Base system
+ DEPENDS:=+netifd +ucode +ucode-mod-nl80211 +ucode-mod-ubus
+ TITLE:=Wi-Fi configuration scripts
+ PKGARCH:=all
+endef
+
+define Package/wifi-scripts/description
+ A set of scripts that handle setup and configuration of Wi-Fi devices.
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/wifi-scripts/install
+ $(INSTALL_DIR) $(1)
+ $(CP) ./files/* $(1)/
+endef
+
+$(eval $(call BuildPackage,wifi-scripts))
diff --git a/package/network/config/wifi-scripts/files/etc/hotplug.d/ieee80211/10-wifi-detect b/package/network/config/wifi-scripts/files/etc/hotplug.d/ieee80211/10-wifi-detect
new file mode 100644
index 00000000000..b8655526613
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/etc/hotplug.d/ieee80211/10-wifi-detect
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "${ACTION}" = "add" ] && {
+ /sbin/wifi config
+}
diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
index 7d035a299bf..763702e76b1 100644
--- a/package/network/services/hostapd/files/hostapd.sh
+++ b/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
@@ -24,12 +24,12 @@ hostapd_append_wep_key() {
[1234])
for idx in 1 2 3 4; do
local zidx
- zidx=$(($idx - 1))
+ zidx="$(($idx - 1))"
json_get_var ckey "key${idx}"
[ -n "$ckey" ] && \
append $var "wep_key${zidx}=$(prepare_key_wep "$ckey")" "$N$T"
done
- wep_keyidx=$((key - 1))
+ wep_keyidx="$((key - 1))"
;;
*)
append $var "wep_key0=$(prepare_key_wep "$key")" "$N$T"
@@ -43,18 +43,21 @@ hostapd_append_wpa_key_mgmt() {
case "$auth_type" in
psk|eap)
append wpa_key_mgmt "WPA-$auth_type_l"
- [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-${auth_type_l}"
+ [ "${wpa:-2}" -ge 2 ] && [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-${auth_type_l}"
[ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-${auth_type_l}-SHA256"
;;
eap192)
append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
- [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
+ [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP-SHA384"
;;
- eap-eap192)
- append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
+ eap-eap2)
append wpa_key_mgmt "WPA-EAP"
+ append wpa_key_mgmt "WPA-EAP-SHA256"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
- [ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-EAP-SHA256"
+ ;;
+ eap2)
+ [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
+ append wpa_key_mgmt "WPA-EAP-SHA256"
;;
sae)
append wpa_key_mgmt "SAE"
@@ -72,6 +75,19 @@ hostapd_append_wpa_key_mgmt() {
;;
esac
+ [ "$fils" -gt 0 ] && {
+ case "$auth_type" in
+ eap192)
+ append wpa_key_mgmt FILS-SHA384
+ [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt FT-FILS-SHA384
+ ;;
+ eap*)
+ append wpa_key_mgmt FILS-SHA256
+ [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt FT-FILS-SHA256
+ ;;
+ esac
+ }
+
[ "$auth_osen" = "1" ] && append wpa_key_mgmt "OSEN"
}
@@ -109,6 +125,7 @@ hostapd_common_add_device_config() {
config_add_array hostapd_options
config_add_int airtime_mode
+ config_add_int mbssid
hostapd_add_log_config
}
@@ -119,9 +136,10 @@ hostapd_prepare_device_config() {
local base_cfg=
- json_get_vars country country3 country_ie beacon_int:100 dtim_period:2 doth require_mode legacy_rates \
+ json_get_vars country country3 country_ie beacon_int:100 doth require_mode legacy_rates \
acs_chan_bias local_pwr_constraint spectrum_mgmt_required airtime_mode cell_density \
- rts_threshold beacon_rate rssi_reject_assoc_rssi rssi_ignore_probe_request maxassoc
+ rts_threshold beacon_rate rssi_reject_assoc_rssi rssi_ignore_probe_request maxassoc \
+ mbssid:0
hostapd_set_log_options base_cfg
@@ -220,9 +238,9 @@ hostapd_prepare_device_config() {
[ -n "$brlist" ] && append base_cfg "basic_rates=$brlist" "$N"
append base_cfg "beacon_int=$beacon_int" "$N"
[ -n "$rts_threshold" ] && append base_cfg "rts_threshold=$rts_threshold" "$N"
- append base_cfg "dtim_period=$dtim_period" "$N"
[ "$airtime_mode" -gt 0 ] && append base_cfg "airtime_mode=$airtime_mode" "$N"
[ -n "$maxassoc" ] && append base_cfg "iface_max_num_sta=$maxassoc" "$N"
+ [ "$mbssid" -gt 0 ] && [ "$mbssid" -le 2 ] && append base_cfg "mbssid=$mbssid" "$N"
json_get_values opts hostapd_options
for val in $opts; do
@@ -237,7 +255,7 @@ EOF
hostapd_common_add_bss_config() {
config_add_string 'bssid:macaddr' 'ssid:string'
- config_add_boolean wds wmm uapsd hidden utf8_ssid
+ config_add_boolean wds wmm uapsd hidden utf8_ssid ppsk
config_add_int maxassoc max_inactivity
config_add_boolean disassoc_low_ack isolate short_preamble skip_inactivity_poll
@@ -254,11 +272,11 @@ hostapd_common_add_bss_config() {
config_add_int ieee80211w
config_add_int eapol_version
- config_add_string 'auth_server:host' 'server:host'
+ config_add_array auth_server acct_server
+ config_add_string 'server:host'
config_add_string auth_secret key
config_add_int 'auth_port:port' 'port:port'
- config_add_string acct_server
config_add_string acct_secret
config_add_int acct_port
config_add_int acct_interval
@@ -295,7 +313,7 @@ hostapd_common_add_bss_config() {
config_add_string wps_device_type wps_device_name wps_manufacturer wps_pin
config_add_string multi_ap_backhaul_ssid multi_ap_backhaul_key
- config_add_boolean wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition
+ config_add_boolean wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition mbo
config_add_int time_advertisement
config_add_string time_zone
config_add_string vendor_elements
@@ -326,6 +344,7 @@ hostapd_common_add_bss_config() {
config_add_int sae_pwe
config_add_string 'owe_transition_bssid:macaddr' 'owe_transition_ssid:string'
+ config_add_string owe_transition_ifname
config_add_boolean iw_enabled iw_internet iw_asra iw_esr iw_uesa
config_add_int iw_access_network_type iw_venue_group iw_venue_type
@@ -348,7 +367,7 @@ hostapd_common_add_bss_config() {
config_add_array airtime_sta_weight
config_add_int airtime_bss_weight airtime_bss_limit
- config_add_boolean multicast_to_unicast proxy_arp per_sta_vif
+ config_add_boolean multicast_to_unicast multicast_to_unicast_all proxy_arp per_sta_vif
config_add_array hostapd_bss_options
config_add_boolean default_disabled
@@ -359,6 +378,11 @@ hostapd_common_add_bss_config() {
config_add_int eap_server
config_add_string eap_user_file ca_cert server_cert private_key private_key_passwd server_id
+
+ config_add_boolean fils
+ config_add_string fils_dhcp
+
+ config_add_int ocv
}
hostapd_set_vlan_file() {
@@ -507,6 +531,20 @@ append_airtime_sta_weight() {
[ -n "$1" ] && append bss_conf "airtime_sta_weight=$1" "$N"
}
+append_auth_server() {
+ [ -n "$1" ] || return
+ append bss_conf "auth_server_addr=$1" "$N"
+ append bss_conf "auth_server_port=$auth_port" "$N"
+ [ -n "$auth_secret" ] && append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
+}
+
+append_acct_server() {
+ [ -n "$1" ] || return
+ append bss_conf "acct_server_addr=$1" "$N"
+ append bss_conf "acct_server_port=$acct_port" "$N"
+ [ -n "$acct_secret" ] && append bss_conf "acct_server_shared_secret=$acct_secret" "$N"
+}
+
hostapd_set_bss_options() {
local var="$1"
local phy="$2"
@@ -514,7 +552,7 @@ hostapd_set_bss_options() {
wireless_vif_parse_encryption
- local bss_conf bss_md5sum
+ local bss_conf bss_md5sum ft_key
local wep_rekey wpa_group_rekey wpa_pair_rekey wpa_master_rekey wpa_key_mgmt
json_get_vars \
@@ -525,14 +563,15 @@ hostapd_set_bss_options() {
wps_independent wps_device_type wps_device_name wps_manufacturer wps_pin \
macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \
iapp_interface eapol_version dynamic_vlan ieee80211w nasid \
- acct_server acct_secret acct_port acct_interval \
+ acct_secret acct_port acct_interval \
bss_load_update_period chan_util_avg_period sae_require_mfp sae_pwe \
multi_ap multi_ap_backhaul_ssid multi_ap_backhaul_key skip_inactivity_poll \
- airtime_bss_weight airtime_bss_limit airtime_sta_weight \
- multicast_to_unicast proxy_arp per_sta_vif \
+ ppsk airtime_bss_weight airtime_bss_limit airtime_sta_weight \
+ multicast_to_unicast_all proxy_arp per_sta_vif \
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
- vendor_elements
+ vendor_elements fils ocv
+ set_default fils 0
set_default isolate 0
set_default maxassoc 0
set_default max_inactivity 0
@@ -550,10 +589,13 @@ hostapd_set_bss_options() {
set_default chan_util_avg_period 600
set_default utf8_ssid 1
set_default multi_ap 0
+ set_default ppsk 0
set_default airtime_bss_weight 0
set_default airtime_bss_limit 0
set_default eap_server 0
+ /usr/sbin/hostapd -vfils || fils=0
+
append bss_conf "ctrl_interface=/var/run/hostapd"
if [ "$isolate" -gt 0 ]; then
append bss_conf "ap_isolate=$isolate" "$N"
@@ -591,24 +633,24 @@ hostapd_set_bss_options() {
}
[ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N"
- [ -n "$acct_server" ] && {
- append bss_conf "acct_server_addr=$acct_server" "$N"
- append bss_conf "acct_server_port=$acct_port" "$N"
- [ -n "$acct_secret" ] && \
- append bss_conf "acct_server_shared_secret=$acct_secret" "$N"
- [ -n "$acct_interval" ] && \
- append bss_conf "radius_acct_interim_interval=$acct_interval" "$N"
- json_for_each_item append_radius_acct_req_attr radius_acct_req_attr
- }
+
+ [ -n "$acct_interval" ] && \
+ append bss_conf "radius_acct_interim_interval=$acct_interval" "$N"
+ json_for_each_item append_acct_server acct_server
+ json_for_each_item append_radius_acct_req_attr radius_acct_req_attr
+
+ [ -n "$ocv" ] && append bss_conf "ocv=$ocv" "$N"
case "$auth_type" in
- sae|owe|eap192|eap-eap192)
+ sae|owe|eap2|eap192)
set_default ieee80211w 2
set_default sae_require_mfp 1
+ set_default sae_pwe 2
;;
- psk-sae)
+ psk-sae|eap-eap2)
set_default ieee80211w 1
set_default sae_require_mfp 1
+ set_default sae_pwe 2
;;
esac
[ -n "$sae_require_mfp" ] && append bss_conf "sae_require_mfp=$sae_require_mfp" "$N"
@@ -618,10 +660,11 @@ hostapd_set_bss_options() {
case "$auth_type" in
none|owe)
- json_get_vars owe_transition_bssid owe_transition_ssid
+ json_get_vars owe_transition_bssid owe_transition_ssid owe_transition_ifname
[ -n "$owe_transition_ssid" ] && append bss_conf "owe_transition_ssid=\"$owe_transition_ssid\"" "$N"
[ -n "$owe_transition_bssid" ] && append bss_conf "owe_transition_bssid=$owe_transition_bssid" "$N"
+ [ -n "$owe_transition_ifname" ] && append bss_conf "owe_transition_ifname=$owe_transition_ifname" "$N"
wps_possible=1
# Here we make the assumption that if we're in open mode
@@ -630,7 +673,13 @@ hostapd_set_bss_options() {
;;
psk|sae|psk-sae)
json_get_vars key wpa_psk_file
- if [ ${#key} -eq 64 ]; then
+ if [ "$auth_type" = "psk" ] && [ "$ppsk" -ne 0 ] ; then
+ json_get_vars auth_secret auth_port
+ set_default auth_port 1812
+ json_for_each_item append_auth_server auth_server
+ append bss_conf "macaddr_acl=2" "$N"
+ append bss_conf "wpa_psk_radius=2" "$N"
+ elif [ ${#key} -eq 64 ]; then
append bss_conf "wpa_psk=$key" "$N"
elif [ ${#key} -ge 8 ] && [ ${#key} -le 63 ]; then
append bss_conf "wpa_passphrase=$key" "$N"
@@ -649,31 +698,54 @@ hostapd_set_bss_options() {
vlan_possible=1
wps_possible=1
;;
- eap|eap192|eap-eap192)
+ eap|eap2|eap-eap2|eap192)
json_get_vars \
auth_server auth_secret auth_port \
dae_client dae_secret dae_port \
- ownip radius_client_addr \
- eap_reauth_period request_cui
+ dynamic_ownip ownip radius_client_addr \
+ eap_reauth_period request_cui \
+ erp_domain mobility_domain \
+ fils_realm fils_dhcp
# radius can provide VLAN ID for clients
vlan_possible=1
+ set_default dynamic_ownip 1
+
# legacy compatibility
[ -n "$auth_server" ] || json_get_var auth_server server
[ -n "$auth_port" ] || json_get_var auth_port port
[ -n "$auth_secret" ] || json_get_var auth_secret key
+ [ "$fils" -gt 0 ] && {
+ set_default erp_domain "$mobility_domain"
+ set_default erp_domain "$(echo "$ssid" | md5sum | head -c 8)"
+ set_default fils_realm "$erp_domain"
+
+ append bss_conf "erp_send_reauth_start=1" "$N"
+ append bss_conf "erp_domain=$erp_domain" "$N"
+ append bss_conf "fils_realm=$fils_realm" "$N"
+ append bss_conf "fils_cache_id=$(echo "$fils_realm" | md5sum | head -c 4)" "$N"
+
+ [ "$fils_dhcp" = "*" ] && {
+ json_get_values network network
+ fils_dhcp=
+ for net in $network; do
+ fils_dhcp="$(ifstatus "$net" | jsonfilter -e '@.data.dhcpserver')"
+ [ -n "$fils_dhcp" ] && break
+ done
+
+ [ -z "$fils_dhcp" -a -n "$network_bridge" -a -n "$network_ifname" ] && \
+ fils_dhcp="$(udhcpc -B -n -q -s /lib/netifd/dhcp-get-server.sh -t 1 -i "$network_ifname" 2>/dev/null)"
+ }
+ [ -n "$fils_dhcp" ] && append bss_conf "dhcp_server=$fils_dhcp" "$N"
+ }
+
set_default auth_port 1812
set_default dae_port 3799
set_default request_cui 0
- [ "$eap_server" -eq 0 ] && {
- append bss_conf "auth_server_addr=$auth_server" "$N"
- append bss_conf "auth_server_port=$auth_port" "$N"
- append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
- }
-
+ [ "$eap_server" -eq 0 ] && json_for_each_item append_auth_server auth_server
[ "$request_cui" -gt 0 ] && append bss_conf "radius_request_cui=$request_cui" "$N"
[ -n "$eap_reauth_period" ] && append bss_conf "eap_reauth_period=$eap_reauth_period" "$N"
@@ -683,7 +755,12 @@ hostapd_set_bss_options() {
}
json_for_each_item append_radius_auth_req_attr radius_auth_req_attr
- [ -n "$ownip" ] && append bss_conf "own_ip_addr=$ownip" "$N"
+ if [ -n "$ownip" ]; then
+ append bss_conf "own_ip_addr=$ownip" "$N"
+ elif [ "$dynamic_ownip" -gt 0 ]; then
+ append bss_conf "dynamic_own_ip_addr=$dynamic_ownip" "$N"
+ fi
+
[ -n "$radius_client_addr" ] && append bss_conf "radius_client_addr=$radius_client_addr" "$N"
append bss_conf "eapol_key_index_workaround=1" "$N"
append bss_conf "ieee8021x=1" "$N"
@@ -699,7 +776,24 @@ hostapd_set_bss_options() {
;;
esac
- local auth_algs=$((($auth_mode_shared << 1) | $auth_mode_open))
+ case "$auth_type" in
+ none|owe|psk|sae|psk-sae|wep)
+ json_get_vars \
+ auth_server auth_port auth_secret \
+ ownip radius_client_addr
+
+ [ -n "$auth_server" ] && {
+ set_default auth_port 1812
+
+ json_for_each_item append_auth_server auth_server
+ [ -n "$ownip" ] && append bss_conf "own_ip_addr=$ownip" "$N"
+ [ -n "$radius_client_addr" ] && append bss_conf "radius_client_addr=$radius_client_addr" "$N"
+ append bss_conf "macaddr_acl=2" "$N"
+ }
+ ;;
+ esac
+
+ local auth_algs="$((($auth_mode_shared << 1) | $auth_mode_open))"
append bss_conf "auth_algs=${auth_algs:-1}" "$N"
append bss_conf "wpa=$wpa" "$N"
[ -n "$wpa_pairwise" ] && append bss_conf "wpa_pairwise=$wpa_pairwise" "$N"
@@ -753,17 +847,19 @@ hostapd_set_bss_options() {
}
append bss_conf "ssid=$ssid" "$N"
- [ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge" "$N"
+ [ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge${N}wds_bridge=" "$N"
+ [ -n "$network_ifname" ] && append bss_conf "snoop_iface=$network_ifname" "$N"
[ -n "$iapp_interface" ] && {
local ifname
network_get_device ifname "$iapp_interface" || ifname="$iapp_interface"
append bss_conf "iapp_interface=$ifname" "$N"
}
- json_get_vars time_advertisement time_zone wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition
+ json_get_vars time_advertisement time_zone wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition mbo
set_default bss_transition 0
set_default wnm_sleep_mode 0
set_default wnm_sleep_mode_no_keys 0
+ set_default mbo 0
[ -n "$time_advertisement" ] && append bss_conf "time_advertisement=$time_advertisement" "$N"
[ -n "$time_zone" ] && append bss_conf "time_zone=$time_zone" "$N"
@@ -772,9 +868,11 @@ hostapd_set_bss_options() {
[ "$wnm_sleep_mode_no_keys" -eq "1" ] && append bss_conf "wnm_sleep_mode_no_keys=1" "$N"
fi
[ "$bss_transition" -eq "1" ] && append bss_conf "bss_transition=1" "$N"
+ [ "$mbo" -eq 1 ] && append bss_conf "mbo=1" "$N"
- json_get_vars ieee80211k rrm_neighbor_report rrm_beacon_report
+ json_get_vars ieee80211k rrm_neighbor_report rrm_beacon_report rnr
set_default ieee80211k 0
+ set_default rnr 0
if [ "$ieee80211k" -eq "1" ]; then
set_default rrm_neighbor_report 1
set_default rrm_beacon_report 1
@@ -785,6 +883,7 @@ hostapd_set_bss_options() {
[ "$rrm_neighbor_report" -eq "1" ] && append bss_conf "rrm_neighbor_report=1" "$N"
[ "$rrm_beacon_report" -eq "1" ] && append bss_conf "rrm_beacon_report=1" "$N"
+ [ "$rnr" -eq "1" ] && append bss_conf "rnr=1" "$N"
json_get_vars ftm_responder stationary_ap lci civic
set_default ftm_responder 0
@@ -798,19 +897,30 @@ hostapd_set_bss_options() {
}
fi
+ json_get_vars ieee80211r
+ set_default ieee80211r 0
if [ "$wpa" -ge "1" ]; then
- json_get_vars ieee80211r
- set_default ieee80211r 0
+ if [ "$fils" -gt 0 ]; then
+ json_get_vars fils_realm
+ set_default fils_realm "$(echo "$ssid" | md5sum | head -c 8)"
+ fi
+
+ append bss_conf "wpa_disable_eapol_key_retries=$wpa_disable_eapol_key_retries" "$N"
+
+ hostapd_append_wpa_key_mgmt
+ [ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N"
+ fi
+ if [ "$wpa" -ge "2" ]; then
if [ "$ieee80211r" -gt "0" ]; then
json_get_vars mobility_domain ft_psk_generate_local ft_over_ds reassociation_deadline
set_default mobility_domain "$(echo "$ssid" | md5sum | head -c 4)"
- set_default ft_over_ds 1
+ set_default ft_over_ds 0
set_default reassociation_deadline 1000
case "$auth_type" in
- psk|sae|psk-sae)
+ psk)
set_default ft_psk_generate_local 1
;;
*)
@@ -823,7 +933,6 @@ hostapd_set_bss_options() {
append bss_conf "ft_psk_generate_local=$ft_psk_generate_local" "$N"
append bss_conf "ft_over_ds=$ft_over_ds" "$N"
append bss_conf "reassociation_deadline=$reassociation_deadline" "$N"
- [ -n "$nasid" ] || append bss_conf "nas_identifier=${macaddr//\:}" "$N"
if [ "$ft_psk_generate_local" -eq "0" ]; then
json_get_vars r0_key_lifetime r1_key_holder pmk_r1_push
@@ -834,10 +943,14 @@ hostapd_set_bss_options() {
set_default pmk_r1_push 0
[ -n "$r0kh" -a -n "$r1kh" ] || {
- key=`echo -n "$mobility_domain/$auth_secret" | md5sum | awk '{print $1}'`
+ if [ -z "$auth_secret" -a -z "$key" ]; then
+ wireless_setup_vif_failed FT_KEY_CANT_BE_DERIVED
+ return 1
+ fi
+ ft_key=`echo -n "$mobility_domain/${auth_secret:-${key}}" | md5sum | awk '{print $1}'`
- set_default r0kh "ff:ff:ff:ff:ff:ff,*,$key"
- set_default r1kh "00:00:00:00:00:00,00:00:00:00:00:00,$key"
+ set_default r0kh "ff:ff:ff:ff:ff:ff,*,$ft_key"
+ set_default r1kh "00:00:00:00:00:00,00:00:00:00:00:00,$ft_key"
}
[ -n "$r1_key_holder" ] && append bss_conf "r1_key_holder=$r1_key_holder" "$N"
@@ -853,13 +966,6 @@ hostapd_set_bss_options() {
fi
fi
- append bss_conf "wpa_disable_eapol_key_retries=$wpa_disable_eapol_key_retries" "$N"
-
- hostapd_append_wpa_key_mgmt
- [ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N"
- fi
-
- if [ "$wpa" -ge "2" ]; then
if [ -n "$network_bridge" -a "$rsn_preauth" = 1 ]; then
set_default auth_cache 1
append bss_conf "rsn_preauth=1" "$N"
@@ -876,7 +982,7 @@ hostapd_set_bss_options() {
fi
append bss_conf "okc=$auth_cache" "$N"
- [ "$auth_cache" = 0 ] && append bss_conf "disable_pmksa_caching=1" "$N"
+ [ "$auth_cache" = 0 -a "$fils" = 0 ] && append bss_conf "disable_pmksa_caching=1" "$N"
# RSN -> allow management frame protection
case "$ieee80211w" in
@@ -884,7 +990,11 @@ hostapd_set_bss_options() {
json_get_vars ieee80211w_mgmt_cipher ieee80211w_max_timeout ieee80211w_retry_timeout
append bss_conf "ieee80211w=$ieee80211w" "$N"
[ "$ieee80211w" -gt "0" ] && {
- append bss_conf "group_mgmt_cipher=${ieee80211w_mgmt_cipher:-AES-128-CMAC}" "$N"
+ if [ "$auth_type" = "eap192" ]; then
+ append bss_conf "group_mgmt_cipher=BIP-GMAC-256" "$N"
+ else
+ append bss_conf "group_mgmt_cipher=${ieee80211w_mgmt_cipher:-AES-128-CMAC}" "$N"
+ fi
[ -n "$ieee80211w_max_timeout" ] && \
append bss_conf "assoc_sa_query_max_timeout=$ieee80211w_max_timeout" "$N"
[ -n "$ieee80211w_retry_timeout" ] && \
@@ -972,7 +1082,6 @@ hostapd_set_bss_options() {
[ -n "$iw_network_auth_type" ] && \
append bss_conf "network_auth_type=$iw_network_auth_type" "$N"
[ -n "$iw_gas_address3" ] && append bss_conf "gas_address3=$iw_gas_address3" "$N"
- [ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N"
json_for_each_item append_iw_roaming_consortium iw_roaming_consortium
json_for_each_item append_iw_anqp_elem iw_anqp_elem
@@ -991,6 +1100,12 @@ hostapd_set_bss_options() {
append bss_conf "anqp_3gpp_cell_net=$iw_anqp_3gpp_cell_net_conf" "$N"
fi
+ set_default iw_qos_map_set 0,0,2,16,1,1,255,255,18,22,24,38,40,40,44,46,48,56
+ case "$iw_qos_map_set" in
+ *,*);;
+ *) iw_qos_map_set="";;
+ esac
+ [ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N"
local hs20 disable_dgaf osen anqp_domain_id hs20_deauth_req_timeout \
osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \
@@ -1025,6 +1140,7 @@ hostapd_set_bss_options() {
if [ "$eap_server" = "1" ]; then
append bss_conf "eap_server=1" "$N"
+ append bss_conf "eap_server_erp=1" "$N"
[ -n "$eap_user_file" ] && append bss_conf "eap_user_file=$eap_user_file" "$N"
[ -n "$ca_cert" ] && append bss_conf "ca_cert=$ca_cert" "$N"
[ -n "$server_cert" ] && append bss_conf "server_cert=$server_cert" "$N"
@@ -1033,9 +1149,9 @@ hostapd_set_bss_options() {
[ -n "$server_id" ] && append bss_conf "server_id=$server_id" "$N"
fi
- set_default multicast_to_unicast 0
- if [ "$multicast_to_unicast" -gt 0 ]; then
- append bss_conf "multicast_to_unicast=$multicast_to_unicast" "$N"
+ set_default multicast_to_unicast_all 0
+ if [ "$multicast_to_unicast_all" -gt 0 ]; then
+ append bss_conf "multicast_to_unicast=$multicast_to_unicast_all" "$N"
fi
set_default proxy_arp 0
if [ "$proxy_arp" -gt 0 ]; then
@@ -1052,9 +1168,6 @@ hostapd_set_bss_options() {
append bss_conf "$val" "$N"
done
- bss_md5sum=$(echo $bss_conf | md5sum | cut -d" " -f1)
- append bss_conf "config_id=$bss_md5sum" "$N"
-
append "$var" "$bss_conf" "$N"
return 0
}
@@ -1074,7 +1187,7 @@ hostapd_set_log_options() {
set_default log_iapp 1
set_default log_mlme 1
- local log_mask=$(( \
+ local log_mask="$(( \
($log_80211 << 0) | \
($log_8021x << 1) | \
($log_radius << 2) | \
@@ -1082,7 +1195,7 @@ hostapd_set_log_options() {
($log_driver << 4) | \
($log_iapp << 5) | \
($log_mlme << 6) \
- ))
+ ))"
append "$var" "logger_syslog=$log_mask" "$N"
append "$var" "logger_syslog_level=$log_level" "$N"
@@ -1165,8 +1278,8 @@ wpa_supplicant_set_fixed_freq() {
append network_data "frequency=$freq" "$N$T"
case "$htmode" in
NOHT) append network_data "disable_ht=1" "$N$T";;
- HT20|VHT20) append network_data "disable_ht40=1" "$N$T";;
- HT40*|VHT40*|VHT80*|VHT160*) append network_data "ht40=1" "$N$T";;
+ HE20|HT20|VHT20) append network_data "disable_ht40=1" "$N$T";;
+ HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160) append network_data "ht40=1" "$N$T";;
esac
case "$htmode" in
VHT*) append network_data "vht=1" "$N$T";;
@@ -1191,12 +1304,12 @@ wpa_supplicant_add_network() {
json_get_vars \
ssid bssid key \
basic_rate mcast_rate \
- ieee80211w ieee80211r \
+ ieee80211w ieee80211r fils ocv \
multi_ap \
default_disabled
case "$auth_type" in
- sae|owe|eap192|eap-eap192)
+ sae|owe|eap2|eap192)
set_default ieee80211w 2
;;
psk-sae)
@@ -1226,7 +1339,7 @@ wpa_supplicant_add_network() {
}
[ "$_w_mode" = "mesh" ] && {
- json_get_vars mesh_id mesh_fwding mesh_rssi_threshold
+ json_get_vars mesh_id mesh_fwding mesh_rssi_threshold encryption
[ -n "$mesh_id" ] && ssid="${mesh_id}"
append network_data "mode=5" "$N$T"
@@ -1234,7 +1347,7 @@ wpa_supplicant_add_network() {
[ -n "$mesh_rssi_threshold" ] && append network_data "mesh_rssi_threshold=${mesh_rssi_threshold}" "$N$T"
[ -n "$freq" ] && wpa_supplicant_set_fixed_freq "$freq" "$htmode"
[ "$noscan" = "1" ] && append network_data "noscan=1" "$N$T"
- append wpa_key_mgmt "SAE"
+ [ "$encryption" = "none" -o -z "$encryption" ] || append wpa_key_mgmt "SAE"
scan_ssid=""
}
@@ -1243,6 +1356,8 @@ wpa_supplicant_add_network() {
[ "$default_disabled" = 1 ] && append network_data "disabled=1" "$N$T"
}
+ [ -n "$ocv" ] && append network_data "ocv=$ocv" "$N$T"
+
case "$auth_type" in
none) ;;
owe)
@@ -1266,23 +1381,24 @@ wpa_supplicant_add_network() {
key_mgmt="$wpa_key_mgmt"
- if [ ${#key} -eq 64 ]; then
- passphrase="psk=${key}"
+ if [ "$_w_mode" = "mesh" ] || [ "$auth_type" = "sae" ]; then
+ passphrase="sae_password=\"${key}\""
else
- if [ "$_w_mode" = "mesh" ]; then
- passphrase="sae_password=\"${key}\""
+ if [ ${#key} -eq 64 ]; then
+ passphrase="psk=${key}"
else
passphrase="psk=\"${key}\""
fi
fi
append network_data "$passphrase" "$N$T"
;;
- eap|eap192|eap-eap192)
+ eap|eap2|eap192)
hostapd_append_wpa_key_mgmt
key_mgmt="$wpa_key_mgmt"
json_get_vars eap_type identity anonymous_identity ca_cert ca_cert_usesystem
+ [ "$fils" -gt 0 ] && append network_data "erp=1" "$N$T"
if [ "$ca_cert_usesystem" -eq "1" -a -f "/etc/ssl/certs/ca-certificates.crt" ]; then
append network_data "ca_cert=\"/etc/ssl/certs/ca-certificates.crt\"" "$N$T"
else
@@ -1480,30 +1596,3 @@ EOF
fi
return 0
}
-
-wpa_supplicant_run() {
- local ifname="$1"
- local hostapd_ctrl="$2"
-
- _wpa_supplicant_common "$ifname"
-
- ubus wait_for wpa_supplicant
- local supplicant_res="$(ubus call wpa_supplicant config_add "{ \
- \"driver\": \"${_w_driver:-wext}\", \"ctrl\": \"$_rpath\", \
- \"iface\": \"$ifname\", \"config\": \"$_config\" \
- ${network_bridge:+, \"bridge\": \"$network_bridge\"} \
- ${hostapd_ctrl:+, \"hostapd_ctrl\": \"$hostapd_ctrl\"} \
- }")"
-
- ret="$?"
-
- [ "$ret" != 0 -o -z "$supplicant_res" ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED
-
- wireless_add_process "$(jsonfilter -s "$supplicant_res" -l 1 -e @.pid)" "/usr/sbin/wpa_supplicant" 1 1
-
- return $ret
-}
-
-hostapd_common_cleanup() {
- killall meshd-nl80211
-}
diff --git a/package/network/config/wifi-scripts/files/lib/netifd/netifd-wireless.sh b/package/network/config/wifi-scripts/files/lib/netifd/netifd-wireless.sh
new file mode 100644
index 00000000000..5b852e09376
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/lib/netifd/netifd-wireless.sh
@@ -0,0 +1,439 @@
+NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
+
+. /usr/share/libubox/jshn.sh
+. $NETIFD_MAIN_DIR/utils.sh
+
+CMD_UP=0
+CMD_SET_DATA=1
+CMD_PROCESS_ADD=2
+CMD_PROCESS_KILL_ALL=3
+CMD_SET_RETRY=4
+
+add_driver() {
+ return
+}
+
+wireless_setup_vif_failed() {
+ local error="$1"
+ echo "Interface $_w_iface setup failed: $error"
+}
+
+wireless_setup_failed() {
+ local error="$1"
+
+ echo "Device setup failed: $error"
+ wireless_set_retry 0
+}
+
+prepare_key_wep() {
+ local key="$1"
+ local hex=1
+
+ echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
+ [ "${#key}" -eq 10 -a $hex -eq 1 ] || \
+ [ "${#key}" -eq 26 -a $hex -eq 1 ] || {
+ [ "${key:0:2}" = "s:" ] && key="${key#s:}"
+ key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
+ }
+ echo "$key"
+}
+
+_wdev_prepare_channel() {
+ json_get_vars channel band hwmode
+
+ auto_channel=0
+ enable_ht=0
+ htmode=
+ hwmode="${hwmode##11}"
+
+ case "$channel" in
+ ""|0|auto)
+ channel=0
+ auto_channel=1
+ ;;
+ [0-9]*) ;;
+ *)
+ wireless_setup_failed "INVALID_CHANNEL"
+ ;;
+ esac
+
+ case "$hwmode" in
+ a|b|g|ad) ;;
+ *)
+ if [ "$channel" -gt 14 ]; then
+ hwmode=a
+ else
+ hwmode=g
+ fi
+ ;;
+ esac
+
+ case "$band" in
+ 2g) hwmode=g;;
+ 5g|6g) hwmode=a;;
+ 60g) hwmode=ad;;
+ *)
+ case "$hwmode" in
+ *a) band=5g;;
+ *ad) band=60g;;
+ *b|*g) band=2g;;
+ esac
+ ;;
+ esac
+}
+
+_wdev_handler() {
+ json_load "$data"
+
+ json_select config
+ _wdev_prepare_channel
+ json_select ..
+
+ eval "drv_$1_$2 \"$interface\""
+}
+
+_wdev_msg_call() {
+ local old_cb
+
+ json_set_namespace wdev old_cb
+ "$@"
+ json_set_namespace $old_cb
+}
+
+_wdev_wrapper() {
+ while [ -n "$1" ]; do
+ eval "$1() { _wdev_msg_call _$1 \"\$@\"; }"
+ shift
+ done
+}
+
+_wdev_notify_init() {
+ local command="$1"; shift;
+
+ json_init
+ json_add_int "command" "$command"
+ json_add_string "device" "$__netifd_device"
+ while [ -n "$1" ]; do
+ local name="$1"; shift
+ local value="$1"; shift
+ json_add_string "$name" "$value"
+ done
+ json_add_object "data"
+}
+
+_wdev_notify() {
+ local options="$1"
+
+ json_close_object
+ ubus $options call network.wireless notify "$(json_dump)"
+}
+
+_wdev_add_variables() {
+ while [ -n "$1" ]; do
+ local var="${1%%=*}"
+ local val="$1"
+ shift
+ [[ "$var" = "$val" ]] && continue
+ val="${val#*=}"
+ json_add_string "$var" "$val"
+ done
+}
+
+_wireless_add_vif() {
+ local name="$1"; shift
+ local ifname="$1"; shift
+
+ _wdev_notify_init $CMD_SET_DATA "interface" "$name"
+ json_add_string "ifname" "$ifname"
+ _wdev_add_variables "$@"
+ _wdev_notify
+}
+
+_wireless_add_vlan() {
+ local name="$1"; shift
+ local ifname="$1"; shift
+
+ _wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
+ json_add_string "ifname" "$ifname"
+ _wdev_add_variables "$@"
+ _wdev_notify
+}
+
+_wireless_set_up() {
+ _wdev_notify_init $CMD_UP
+ _wdev_notify
+}
+
+_wireless_set_data() {
+ _wdev_notify_init $CMD_SET_DATA
+ _wdev_add_variables "$@"
+ _wdev_notify
+}
+
+_wireless_add_process() {
+ _wdev_notify_init $CMD_PROCESS_ADD
+ local exe="$2"
+ [ -L "$exe" ] && exe="$(readlink -f "$exe")"
+ json_add_int pid "$1"
+ json_add_string exe "$exe"
+ [ -n "$3" ] && json_add_boolean required 1
+ [ -n "$4" ] && json_add_boolean keep 1
+ exe2="$(readlink -f /proc/$1/exe)"
+ [ "$exe" != "$exe2" ] && echo "WARNING (wireless_add_process): executable path $exe does not match process $1 path ($exe2)"
+ _wdev_notify
+}
+
+_wireless_process_kill_all() {
+ _wdev_notify_init $CMD_PROCESS_KILL_ALL
+ [ -n "$1" ] && json_add_int signal "$1"
+ _wdev_notify
+}
+
+_wireless_set_retry() {
+ _wdev_notify_init $CMD_SET_RETRY
+ json_add_int retry "$1"
+ _wdev_notify
+}
+
+_wdev_wrapper \
+ wireless_add_vif \
+ wireless_add_vlan \
+ wireless_set_up \
+ wireless_set_data \
+ wireless_add_process \
+ wireless_process_kill_all \
+ wireless_set_retry \
+
+wireless_vif_parse_encryption() {
+ json_get_vars encryption
+ set_default encryption none
+
+ auth_mode_open=1
+ auth_mode_shared=0
+ auth_type=none
+
+ if [ "$hwmode" = "ad" ]; then
+ wpa_cipher="GCMP"
+ else
+ wpa_cipher="CCMP"
+ fi
+
+ case "$encryption" in
+ *tkip+aes|*tkip+ccmp|*aes+tkip|*ccmp+tkip) wpa_cipher="CCMP TKIP";;
+ *ccmp256) wpa_cipher="CCMP-256";;
+ *aes|*ccmp) wpa_cipher="CCMP";;
+ *tkip) wpa_cipher="TKIP";;
+ *gcmp256) wpa_cipher="GCMP-256";;
+ *gcmp) wpa_cipher="GCMP";;
+ wpa3-192*) wpa_cipher="GCMP-256";;
+ esac
+
+ # 802.11n requires CCMP for WPA
+ [ "$enable_ht:$wpa_cipher" = "1:TKIP" ] && wpa_cipher="CCMP TKIP"
+
+ # Examples:
+ # psk-mixed/tkip => WPA1+2 PSK, TKIP
+ # wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
+ # wpa2/tkip+aes => WPA2 RADIUS, CCMP+TKIP
+
+ case "$encryption" in
+ wpa2*|wpa3*|*psk2*|psk3*|sae*|owe*)
+ wpa=2
+ ;;
+ wpa*mixed*|*psk*mixed*)
+ wpa=3
+ ;;
+ wpa*|*psk*)
+ wpa=1
+ ;;
+ *)
+ wpa=0
+ wpa_cipher=
+ ;;
+ esac
+ wpa_pairwise="$wpa_cipher"
+
+ case "$encryption" in
+ owe*)
+ auth_type=owe
+ ;;
+ wpa3-192*)
+ auth_type=eap192
+ ;;
+ wpa3-mixed*)
+ auth_type=eap-eap2
+ ;;
+ wpa3*)
+ auth_type=eap2
+ ;;
+ psk3-mixed*|sae-mixed*)
+ auth_type=psk-sae
+ ;;
+ psk3*|sae*)
+ auth_type=sae
+ ;;
+ *psk*)
+ auth_type=psk
+ ;;
+ *wpa*|*8021x*)
+ auth_type=eap
+ ;;
+ *wep*)
+ auth_type=wep
+ case "$encryption" in
+ *shared*)
+ auth_mode_open=0
+ auth_mode_shared=1
+ ;;
+ *mixed*)
+ auth_mode_shared=1
+ ;;
+ esac
+ ;;
+ esac
+
+ case "$encryption" in
+ *osen*)
+ auth_osen=1
+ ;;
+ esac
+}
+
+_wireless_set_brsnoop_isolation() {
+ local multicast_to_unicast="$1"
+ local isolate
+
+ json_get_vars isolate proxy_arp
+
+ [ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
+ [ ${multicast_to_unicast:-1} -gt 0 -o ${proxy_arp:-0} -gt 0 ] && json_add_boolean isolate 1
+}
+
+for_each_interface() {
+ local _w_types="$1"; shift
+ local _w_ifaces _w_iface
+ local _w_type
+ local _w_found
+
+ local multicast_to_unicast
+
+ json_get_keys _w_ifaces interfaces
+ json_select interfaces
+ for _w_iface in $_w_ifaces; do
+ json_select "$_w_iface"
+ if [ -n "$_w_types" ]; then
+ json_get_var network_bridge bridge
+ json_get_var network_ifname bridge-ifname
+ json_get_var multicast_to_unicast multicast_to_unicast
+ json_select config
+ _wireless_set_brsnoop_isolation "$multicast_to_unicast"
+ json_get_var _w_type mode
+ json_select ..
+ _w_types=" $_w_types "
+ [[ "${_w_types%$_w_type*}" = "$_w_types" ]] && {
+ json_select ..
+ continue
+ }
+ fi
+ __cur_interface="$_w_iface"
+ "$@" "$_w_iface"
+ json_select ..
+ done
+ json_select ..
+}
+
+for_each_vlan() {
+ local _w_vlans _w_vlan
+
+ json_get_keys _w_vlans vlans
+ json_select vlans
+ for _w_vlan in $_w_vlans; do
+ json_select "$_w_vlan"
+ json_select config
+ "$@" "$_w_vlan"
+ json_select ..
+ json_select ..
+ done
+ json_select ..
+}
+
+for_each_station() {
+ local _w_stas _w_sta
+
+ json_get_keys _w_stas stas
+ json_select stas
+ for _w_sta in $_w_stas; do
+ json_select "$_w_sta"
+ json_select config
+ "$@" "$_w_sta"
+ json_select ..
+ json_select ..
+ done
+ json_select ..
+}
+
+_wdev_common_device_config() {
+ config_add_string channel hwmode band htmode noscan
+}
+
+_wdev_common_iface_config() {
+ config_add_string mode ssid encryption 'key:wpakey'
+ config_add_boolean bridge_isolate
+}
+
+_wdev_common_vlan_config() {
+ config_add_string name vid iface
+ config_add_boolean bridge_isolate
+}
+
+_wdev_common_station_config() {
+ config_add_string mac key vid iface
+}
+
+init_wireless_driver() {
+ name="$1"; shift
+ cmd="$1"; shift
+
+ case "$cmd" in
+ dump)
+ add_driver() {
+ eval "drv_$1_cleanup"
+
+ json_init
+ json_add_string name "$1"
+
+ json_add_array device
+ _wdev_common_device_config
+ eval "drv_$1_init_device_config"
+ json_close_array
+
+ json_add_array iface
+ _wdev_common_iface_config
+ eval "drv_$1_init_iface_config"
+ json_close_array
+
+ json_add_array vlan
+ _wdev_common_vlan_config
+ eval "drv_$1_init_vlan_config"
+ json_close_array
+
+ json_add_array station
+ _wdev_common_station_config
+ eval "drv_$1_init_station_config"
+ json_close_array
+
+ json_dump
+ }
+ ;;
+ setup|teardown)
+ interface="$1"; shift
+ data="$1"; shift
+ export __netifd_device="$interface"
+
+ add_driver() {
+ [[ "$name" == "$1" ]] || return 0
+ _wdev_handler "$1" "$cmd"
+ }
+ ;;
+ esac
+}
diff --git a/package/network/config/wifi-scripts/files/lib/netifd/wireless/mac80211.sh b/package/network/config/wifi-scripts/files/lib/netifd/wireless/mac80211.sh
new file mode 100755
index 00000000000..49ffb219bcd
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/lib/netifd/wireless/mac80211.sh
@@ -0,0 +1,1197 @@
+#!/bin/sh
+. /lib/netifd/netifd-wireless.sh
+. /lib/netifd/hostapd.sh
+. /lib/functions/system.sh
+
+init_wireless_driver "$@"
+
+MP_CONFIG_INT="mesh_retry_timeout mesh_confirm_timeout mesh_holding_timeout mesh_max_peer_links
+ mesh_max_retries mesh_ttl mesh_element_ttl mesh_hwmp_max_preq_retries
+ mesh_path_refresh_time mesh_min_discovery_timeout mesh_hwmp_active_path_timeout
+ mesh_hwmp_preq_min_interval mesh_hwmp_net_diameter_traversal_time mesh_hwmp_rootmode
+ mesh_hwmp_rann_interval mesh_gate_announcements mesh_sync_offset_max_neighor
+ mesh_rssi_threshold mesh_hwmp_active_path_to_root_timeout mesh_hwmp_root_interval
+ mesh_hwmp_confirmation_interval mesh_awake_window mesh_plink_timeout"
+MP_CONFIG_BOOL="mesh_auto_open_plinks mesh_fwding"
+MP_CONFIG_STRING="mesh_power_mode"
+
+wdev_tool() {
+ ucode /usr/share/hostap/wdev.uc "$@"
+}
+
+ubus_call() {
+ flock /var/run/hostapd.lock ubus call "$@"
+}
+
+drv_mac80211_init_device_config() {
+ hostapd_common_add_device_config
+
+ config_add_string path phy 'macaddr:macaddr'
+ config_add_string tx_burst
+ config_add_string distance
+ config_add_int beacon_int chanbw frag rts
+ config_add_int rxantenna txantenna txpower min_tx_power
+ config_add_int num_global_macaddr multiple_bssid
+ config_add_boolean noscan ht_coex acs_exclude_dfs background_radar
+ config_add_array ht_capab
+ config_add_array channels
+ config_add_array scan_list
+ config_add_boolean \
+ rxldpc \
+ short_gi_80 \
+ short_gi_160 \
+ tx_stbc_2by1 \
+ su_beamformer \
+ su_beamformee \
+ mu_beamformer \
+ mu_beamformee \
+ he_su_beamformer \
+ he_su_beamformee \
+ he_mu_beamformer \
+ vht_txop_ps \
+ htc_vht \
+ rx_antenna_pattern \
+ tx_antenna_pattern \
+ he_spr_sr_control \
+ he_spr_psr_enabled \
+ he_bss_color_enabled \
+ he_twt_required
+ config_add_int \
+ beamformer_antennas \
+ beamformee_antennas \
+ vht_max_a_mpdu_len_exp \
+ vht_max_mpdu \
+ vht_link_adapt \
+ vht160 \
+ rx_stbc \
+ tx_stbc \
+ he_bss_color \
+ he_spr_non_srg_obss_pd_max_offset
+ config_add_boolean \
+ ldpc \
+ greenfield \
+ short_gi_20 \
+ short_gi_40 \
+ max_amsdu \
+ dsss_cck_40
+}
+
+drv_mac80211_init_iface_config() {
+ hostapd_common_add_bss_config
+
+ config_add_string 'macaddr:macaddr' ifname
+
+ config_add_boolean wds powersave enable
+ config_add_string wds_bridge
+ config_add_int maxassoc
+ config_add_int max_listen_int
+ config_add_int dtim_period
+ config_add_int start_disabled
+
+ # mesh
+ config_add_string mesh_id
+ config_add_int $MP_CONFIG_INT
+ config_add_boolean $MP_CONFIG_BOOL
+ config_add_string $MP_CONFIG_STRING
+}
+
+mac80211_add_capabilities() {
+ local __var="$1"; shift
+ local __mask="$1"; shift
+ local __out= oifs
+
+ oifs="$IFS"
+ IFS=:
+ for capab in "$@"; do
+ set -- $capab
+
+ [ "$(($4))" -gt 0 ] || continue
+ [ "$(($__mask & $2))" -eq "$((${3:-$2}))" ] || continue
+ __out="$__out[$1]"
+ done
+ IFS="$oifs"
+
+ export -n -- "$__var=$__out"
+}
+
+mac80211_add_he_capabilities() {
+ local __out= oifs
+
+ oifs="$IFS"
+ IFS=:
+ for capab in "$@"; do
+ set -- $capab
+ [ "$(($4))" -gt 0 ] || continue
+ [ "$(((0x$2) & $3))" -gt 0 ] || {
+ eval "$1=0"
+ continue
+ }
+ append base_cfg "$1=1" "$N"
+ done
+ IFS="$oifs"
+}
+
+mac80211_hostapd_setup_base() {
+ local phy="$1"
+
+ json_select config
+
+ [ "$auto_channel" -gt 0 ] && channel=acs_survey
+
+ [ "$auto_channel" -gt 0 ] && json_get_vars acs_exclude_dfs
+ [ -n "$acs_exclude_dfs" ] && [ "$acs_exclude_dfs" -gt 0 ] &&
+ append base_cfg "acs_exclude_dfs=1" "$N"
+
+ json_get_vars noscan ht_coex min_tx_power:0 tx_burst
+ json_get_values ht_capab_list ht_capab
+ json_get_values channel_list channels
+
+ [ "$auto_channel" = 0 ] && [ -z "$channel_list" ] && \
+ channel_list="$channel"
+
+ [ "$min_tx_power" -gt 0 ] && append base_cfg "min_tx_power=$min_tx_power" "$N"
+
+ set_default noscan 0
+
+ [ "$noscan" -gt 0 ] && hostapd_noscan=1
+ [ "$tx_burst" = 0 ] && tx_burst=
+
+ chan_ofs=0
+ [ "$band" = "6g" ] && chan_ofs=1
+
+ ieee80211n=1
+ ht_capab=
+ case "$htmode" in
+ VHT20|HT20|HE20) ;;
+ HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160)
+ case "$hwmode" in
+ a)
+ case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in
+ 1) ht_capab="[HT40+]";;
+ 0) ht_capab="[HT40-]";;
+ esac
+ ;;
+ *)
+ case "$htmode" in
+ HT40+) ht_capab="[HT40+]";;
+ HT40-) ht_capab="[HT40-]";;
+ *)
+ if [ "$channel" -lt 7 ]; then
+ ht_capab="[HT40+]"
+ else
+ ht_capab="[HT40-]"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ [ "$auto_channel" -gt 0 ] && ht_capab="[HT40+]"
+ ;;
+ *) ieee80211n= ;;
+ esac
+
+ [ -n "$ieee80211n" ] && {
+ append base_cfg "ieee80211n=1" "$N"
+
+ set_default ht_coex 0
+ append base_cfg "ht_coex=$ht_coex" "$N"
+
+ json_get_vars \
+ ldpc:1 \
+ greenfield:0 \
+ short_gi_20:1 \
+ short_gi_40:1 \
+ tx_stbc:1 \
+ rx_stbc:3 \
+ max_amsdu:1 \
+ dsss_cck_40:1
+
+ ht_cap_mask=0
+ for cap in $(iw phy "$phy" info | grep 'Capabilities:' | cut -d: -f2); do
+ ht_cap_mask="$(($ht_cap_mask | $cap))"
+ done
+
+ cap_rx_stbc=$((($ht_cap_mask >> 8) & 3))
+ [ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
+ ht_cap_mask="$(( ($ht_cap_mask & ~(0x300)) | ($cap_rx_stbc << 8) ))"
+
+ mac80211_add_capabilities ht_capab_flags $ht_cap_mask \
+ LDPC:0x1::$ldpc \
+ GF:0x10::$greenfield \
+ SHORT-GI-20:0x20::$short_gi_20 \
+ SHORT-GI-40:0x40::$short_gi_40 \
+ TX-STBC:0x80::$tx_stbc \
+ RX-STBC1:0x300:0x100:1 \
+ RX-STBC12:0x300:0x200:1 \
+ RX-STBC123:0x300:0x300:1 \
+ MAX-AMSDU-7935:0x800::$max_amsdu \
+ DSSS_CCK-40:0x1000::$dsss_cck_40
+
+ ht_capab="$ht_capab$ht_capab_flags"
+ [ -n "$ht_capab" ] && append base_cfg "ht_capab=$ht_capab" "$N"
+ }
+
+ # 802.11ac
+ enable_ac=0
+ vht_oper_chwidth=0
+ vht_center_seg0=
+
+ idx="$channel"
+ case "$htmode" in
+ VHT20|HE20) enable_ac=1;;
+ VHT40|HE40)
+ case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in
+ 1) idx=$(($channel + 2));;
+ 0) idx=$(($channel - 2));;
+ esac
+ enable_ac=1
+ vht_center_seg0=$idx
+ ;;
+ VHT80|HE80)
+ case "$(( (($channel / 4) + $chan_ofs) % 4 ))" in
+ 1) idx=$(($channel + 6));;
+ 2) idx=$(($channel + 2));;
+ 3) idx=$(($channel - 2));;
+ 0) idx=$(($channel - 6));;
+ esac
+ enable_ac=1
+ vht_oper_chwidth=1
+ vht_center_seg0=$idx
+ ;;
+ VHT160|HE160)
+ if [ "$band" = "6g" ]; then
+ case "$channel" in
+ 1|5|9|13|17|21|25|29) idx=15;;
+ 33|37|41|45|49|53|57|61) idx=47;;
+ 65|69|73|77|81|85|89|93) idx=79;;
+ 97|101|105|109|113|117|121|125) idx=111;;
+ 129|133|137|141|145|149|153|157) idx=143;;
+ 161|165|169|173|177|181|185|189) idx=175;;
+ 193|197|201|205|209|213|217|221) idx=207;;
+ esac
+ else
+ case "$channel" in
+ 36|40|44|48|52|56|60|64) idx=50;;
+ 100|104|108|112|116|120|124|128) idx=114;;
+ esac
+ fi
+ enable_ac=1
+ vht_oper_chwidth=2
+ vht_center_seg0=$idx
+ ;;
+ esac
+ [ "$band" = "5g" ] && {
+ json_get_vars background_radar:0
+
+ [ "$background_radar" -eq 1 ] && append base_cfg "enable_background_radar=1" "$N"
+ }
+ [ "$band" = "6g" ] && {
+ op_class=
+ case "$htmode" in
+ HE20) op_class=131;;
+ HE*) op_class=$((132 + $vht_oper_chwidth))
+ esac
+ [ -n "$op_class" ] && append base_cfg "op_class=$op_class" "$N"
+ }
+ [ "$hwmode" = "a" ] || enable_ac=0
+
+ if [ "$enable_ac" != "0" ]; then
+ json_get_vars \
+ rxldpc:1 \
+ short_gi_80:1 \
+ short_gi_160:1 \
+ tx_stbc_2by1:1 \
+ su_beamformer:1 \
+ su_beamformee:1 \
+ mu_beamformer:1 \
+ mu_beamformee:1 \
+ vht_txop_ps:1 \
+ htc_vht:1 \
+ beamformee_antennas:4 \
+ beamformer_antennas:4 \
+ rx_antenna_pattern:1 \
+ tx_antenna_pattern:1 \
+ vht_max_a_mpdu_len_exp:7 \
+ vht_max_mpdu:11454 \
+ rx_stbc:4 \
+ vht_link_adapt:3 \
+ vht160:2
+
+ set_default tx_burst 2.0
+ append base_cfg "ieee80211ac=1" "$N"
+ vht_cap=0
+ for cap in $(iw phy "$phy" info | awk -F "[()]" '/VHT Capabilities/ { print $2 }'); do
+ vht_cap="$(($vht_cap | $cap))"
+ done
+
+ append base_cfg "vht_oper_chwidth=$vht_oper_chwidth" "$N"
+ append base_cfg "vht_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N"
+
+ cap_rx_stbc=$((($vht_cap >> 8) & 7))
+ [ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
+ vht_cap="$(( ($vht_cap & ~(0x700)) | ($cap_rx_stbc << 8) ))"
+
+ [ "$vht_oper_chwidth" -lt 2 ] && {
+ vht160=0
+ short_gi_160=0
+ }
+
+ mac80211_add_capabilities vht_capab $vht_cap \
+ RXLDPC:0x10::$rxldpc \
+ SHORT-GI-80:0x20::$short_gi_80 \
+ SHORT-GI-160:0x40::$short_gi_160 \
+ TX-STBC-2BY1:0x80::$tx_stbc_2by1 \
+ SU-BEAMFORMER:0x800::$su_beamformer \
+ SU-BEAMFORMEE:0x1000::$su_beamformee \
+ MU-BEAMFORMER:0x80000::$mu_beamformer \
+ MU-BEAMFORMEE:0x100000::$mu_beamformee \
+ VHT-TXOP-PS:0x200000::$vht_txop_ps \
+ HTC-VHT:0x400000::$htc_vht \
+ RX-ANTENNA-PATTERN:0x10000000::$rx_antenna_pattern \
+ TX-ANTENNA-PATTERN:0x20000000::$tx_antenna_pattern \
+ RX-STBC-1:0x700:0x100:1 \
+ RX-STBC-12:0x700:0x200:1 \
+ RX-STBC-123:0x700:0x300:1 \
+ RX-STBC-1234:0x700:0x400:1 \
+
+ [ "$(($vht_cap & 0x800))" -gt 0 -a "$su_beamformer" -gt 0 ] && {
+ cap_ant="$(( ( ($vht_cap >> 16) & 3 ) + 1 ))"
+ [ "$cap_ant" -gt "$beamformer_antennas" ] && cap_ant="$beamformer_antennas"
+ [ "$cap_ant" -gt 1 ] && vht_capab="$vht_capab[SOUNDING-DIMENSION-$cap_ant]"
+ }
+
+ [ "$(($vht_cap & 0x1000))" -gt 0 -a "$su_beamformee" -gt 0 ] && {
+ cap_ant="$(( ( ($vht_cap >> 13) & 3 ) + 1 ))"
+ [ "$cap_ant" -gt "$beamformee_antennas" ] && cap_ant="$beamformee_antennas"
+ [ "$cap_ant" -gt 1 ] && vht_capab="$vht_capab[BF-ANTENNA-$cap_ant]"
+ }
+
+ # supported Channel widths
+ vht160_hw=0
+ [ "$(($vht_cap & 12))" -eq 4 -a 1 -le "$vht160" ] && \
+ vht160_hw=1
+ [ "$(($vht_cap & 12))" -eq 8 -a 2 -le "$vht160" ] && \
+ vht160_hw=2
+ [ "$vht160_hw" = 1 ] && vht_capab="$vht_capab[VHT160]"
+ [ "$vht160_hw" = 2 ] && vht_capab="$vht_capab[VHT160-80PLUS80]"
+
+ # maximum MPDU length
+ vht_max_mpdu_hw=3895
+ [ "$(($vht_cap & 3))" -ge 1 -a 7991 -le "$vht_max_mpdu" ] && \
+ vht_max_mpdu_hw=7991
+ [ "$(($vht_cap & 3))" -ge 2 -a 11454 -le "$vht_max_mpdu" ] && \
+ vht_max_mpdu_hw=11454
+ [ "$vht_max_mpdu_hw" != 3895 ] && \
+ vht_capab="$vht_capab[MAX-MPDU-$vht_max_mpdu_hw]"
+
+ # maximum A-MPDU length exponent
+ vht_max_a_mpdu_len_exp_hw=0
+ [ "$(($vht_cap & 58720256))" -ge 8388608 -a 1 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=1
+ [ "$(($vht_cap & 58720256))" -ge 16777216 -a 2 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=2
+ [ "$(($vht_cap & 58720256))" -ge 25165824 -a 3 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=3
+ [ "$(($vht_cap & 58720256))" -ge 33554432 -a 4 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=4
+ [ "$(($vht_cap & 58720256))" -ge 41943040 -a 5 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=5
+ [ "$(($vht_cap & 58720256))" -ge 50331648 -a 6 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=6
+ [ "$(($vht_cap & 58720256))" -ge 58720256 -a 7 -le "$vht_max_a_mpdu_len_exp" ] && \
+ vht_max_a_mpdu_len_exp_hw=7
+ vht_capab="$vht_capab[MAX-A-MPDU-LEN-EXP$vht_max_a_mpdu_len_exp_hw]"
+
+ # whether or not the STA supports link adaptation using VHT variant
+ vht_link_adapt_hw=0
+ [ "$(($vht_cap & 201326592))" -ge 134217728 -a 2 -le "$vht_link_adapt" ] && \
+ vht_link_adapt_hw=2
+ [ "$(($vht_cap & 201326592))" -ge 201326592 -a 3 -le "$vht_link_adapt" ] && \
+ vht_link_adapt_hw=3
+ [ "$vht_link_adapt_hw" != 0 ] && \
+ vht_capab="$vht_capab[VHT-LINK-ADAPT-$vht_link_adapt_hw]"
+
+ [ -n "$vht_capab" ] && append base_cfg "vht_capab=$vht_capab" "$N"
+ fi
+
+ # 802.11ax
+ enable_ax=0
+ case "$htmode" in
+ HE*) enable_ax=1 ;;
+ esac
+
+ if [ "$enable_ax" != "0" ]; then
+ json_get_vars \
+ he_su_beamformer:1 \
+ he_su_beamformee:1 \
+ he_mu_beamformer:1 \
+ he_twt_required:0 \
+ he_spr_sr_control:3 \
+ he_spr_psr_enabled:0 \
+ he_spr_non_srg_obss_pd_max_offset:0 \
+ he_bss_color:128 \
+ he_bss_color_enabled:1
+
+ he_phy_cap=$(iw phy "$phy" info | sed -n '/HE Iftypes: AP/,$p' | awk -F "[()]" '/HE PHY Capabilities/ { print $2 }' | head -1)
+ he_phy_cap=${he_phy_cap:2}
+ he_mac_cap=$(iw phy "$phy" info | sed -n '/HE Iftypes: AP/,$p' | awk -F "[()]" '/HE MAC Capabilities/ { print $2 }' | head -1)
+ he_mac_cap=${he_mac_cap:2}
+
+ append base_cfg "ieee80211ax=1" "$N"
+ [ "$hwmode" = "a" ] && {
+ append base_cfg "he_oper_chwidth=$vht_oper_chwidth" "$N"
+ append base_cfg "he_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N"
+ }
+
+ mac80211_add_he_capabilities \
+ he_su_beamformer:${he_phy_cap:6:2}:0x80:$he_su_beamformer \
+ he_su_beamformee:${he_phy_cap:8:2}:0x1:$he_su_beamformee \
+ he_mu_beamformer:${he_phy_cap:8:2}:0x2:$he_mu_beamformer \
+ he_spr_psr_enabled:${he_phy_cap:14:2}:0x1:$he_spr_psr_enabled \
+ he_twt_required:${he_mac_cap:0:2}:0x6:$he_twt_required
+
+ if [ "$he_bss_color_enabled" -gt 0 ]; then
+ append base_cfg "he_bss_color=$he_bss_color" "$N"
+ [ "$he_spr_non_srg_obss_pd_max_offset" -gt 0 ] && { \
+ append base_cfg "he_spr_non_srg_obss_pd_max_offset=$he_spr_non_srg_obss_pd_max_offset" "$N"
+ he_spr_sr_control=$((he_spr_sr_control | (1 << 2)))
+ }
+ [ "$he_spr_psr_enabled" -gt 0 ] || he_spr_sr_control=$((he_spr_sr_control | (1 << 0)))
+ append base_cfg "he_spr_sr_control=$he_spr_sr_control" "$N"
+ else
+ append base_cfg "he_bss_color_disabled=1" "$N"
+ fi
+
+
+ append base_cfg "he_default_pe_duration=4" "$N"
+ append base_cfg "he_rts_threshold=1023" "$N"
+ append base_cfg "he_mu_edca_qos_info_param_count=0" "$N"
+ append base_cfg "he_mu_edca_qos_info_q_ack=0" "$N"
+ append base_cfg "he_mu_edca_qos_info_queue_request=0" "$N"
+ append base_cfg "he_mu_edca_qos_info_txop_request=0" "$N"
+ append base_cfg "he_mu_edca_ac_be_aifsn=8" "$N"
+ append base_cfg "he_mu_edca_ac_be_aci=0" "$N"
+ append base_cfg "he_mu_edca_ac_be_ecwmin=9" "$N"
+ append base_cfg "he_mu_edca_ac_be_ecwmax=10" "$N"
+ append base_cfg "he_mu_edca_ac_be_timer=255" "$N"
+ append base_cfg "he_mu_edca_ac_bk_aifsn=15" "$N"
+ append base_cfg "he_mu_edca_ac_bk_aci=1" "$N"
+ append base_cfg "he_mu_edca_ac_bk_ecwmin=9" "$N"
+ append base_cfg "he_mu_edca_ac_bk_ecwmax=10" "$N"
+ append base_cfg "he_mu_edca_ac_bk_timer=255" "$N"
+ append base_cfg "he_mu_edca_ac_vi_ecwmin=5" "$N"
+ append base_cfg "he_mu_edca_ac_vi_ecwmax=7" "$N"
+ append base_cfg "he_mu_edca_ac_vi_aifsn=5" "$N"
+ append base_cfg "he_mu_edca_ac_vi_aci=2" "$N"
+ append base_cfg "he_mu_edca_ac_vi_timer=255" "$N"
+ append base_cfg "he_mu_edca_ac_vo_aifsn=5" "$N"
+ append base_cfg "he_mu_edca_ac_vo_aci=3" "$N"
+ append base_cfg "he_mu_edca_ac_vo_ecwmin=5" "$N"
+ append base_cfg "he_mu_edca_ac_vo_ecwmax=7" "$N"
+ append base_cfg "he_mu_edca_ac_vo_timer=255" "$N"
+ fi
+
+ hostapd_prepare_device_config "$hostapd_conf_file" nl80211
+ cat >> "$hostapd_conf_file" <<EOF
+${channel:+channel=$channel}
+${channel_list:+chanlist=$channel_list}
+${hostapd_noscan:+noscan=1}
+${tx_burst:+tx_queue_data2_burst=$tx_burst}
+${multiple_bssid:+mbssid=$multiple_bssid}
+#num_global_macaddr=$num_global_macaddr
+$base_cfg
+
+EOF
+ json_select ..
+}
+
+mac80211_hostapd_setup_bss() {
+ local phy="$1"
+ local ifname="$2"
+ local macaddr="$3"
+ local type="$4"
+
+ hostapd_cfg=
+ append hostapd_cfg "$type=$ifname" "$N"
+
+ hostapd_set_bss_options hostapd_cfg "$phy" "$vif" || return 1
+ json_get_vars wds wds_bridge dtim_period max_listen_int start_disabled
+
+ set_default wds 0
+ set_default start_disabled 0
+
+ [ "$wds" -gt 0 ] && {
+ append hostapd_cfg "wds_sta=1" "$N"
+ [ -n "$wds_bridge" ] && append hostapd_cfg "wds_bridge=$wds_bridge" "$N"
+ }
+ [ "$staidx" -gt 0 -o "$start_disabled" -eq 1 ] && append hostapd_cfg "start_disabled=1" "$N"
+
+ cat >> /var/run/hostapd-$phy.conf <<EOF
+$hostapd_cfg
+bssid=$macaddr
+${default_macaddr:+#default_macaddr}
+${dtim_period:+dtim_period=$dtim_period}
+${max_listen_int:+max_listen_interval=$max_listen_int}
+EOF
+}
+
+mac80211_get_addr() {
+ local phy="$1"
+ local idx="$(($2 + 1))"
+
+ head -n $idx /sys/class/ieee80211/${phy}/addresses | tail -n1
+}
+
+mac80211_generate_mac() {
+ local phy="$1"
+ local id="${macidx:-0}"
+
+ wdev_tool "$phy" get_macaddr id=$id num_global=$num_global_macaddr mbssid=${multiple_bssid:-0}
+}
+
+get_board_phy_name() (
+ local path="$1"
+ local fallback_phy=""
+
+ __check_phy() {
+ local val="$1"
+ local key="$2"
+ local ref_path="$3"
+
+ json_select "$key"
+ json_get_vars path
+ json_select ..
+
+ [ "${ref_path%+*}" = "$path" ] && fallback_phy=$key
+ [ "$ref_path" = "$path" ] || return 0
+
+ echo "$key"
+ exit
+ }
+
+ json_load_file /etc/board.json
+ json_for_each_item __check_phy wlan "$path"
+ [ -n "$fallback_phy" ] && echo "${fallback_phy}.${path##*+}"
+)
+
+rename_board_phy_by_path() {
+ local path="$1"
+
+ local new_phy="$(get_board_phy_name "$path")"
+ [ -z "$new_phy" -o "$new_phy" = "$phy" ] && return
+
+ iw "$phy" set name "$new_phy" && phy="$new_phy"
+}
+
+rename_board_phy_by_name() (
+ local phy="$1"
+ local suffix="${phy##*.}"
+ [ "$suffix" = "$phy" ] && suffix=
+
+ json_load_file /etc/board.json
+ json_select wlan
+ json_select "${phy%.*}" || return 0
+ json_get_vars path
+
+ prev_phy="$(iwinfo nl80211 phyname "path=$path${suffix:++$suffix}")"
+ [ -n "$prev_phy" ] || return 0
+
+ [ "$prev_phy" = "$phy" ] && return 0
+
+ iw "$prev_phy" set name "$phy"
+)
+
+find_phy() {
+ [ -n "$phy" ] && {
+ rename_board_phy_by_name "$phy"
+ [ -d /sys/class/ieee80211/$phy ] && return 0
+ }
+ [ -n "$path" ] && {
+ phy="$(iwinfo nl80211 phyname "path=$path")"
+ [ -n "$phy" ] && {
+ rename_board_phy_by_path "$path"
+ return 0
+ }
+ }
+ [ -n "$macaddr" ] && {
+ for phy in $(ls /sys/class/ieee80211 2>/dev/null); do
+ grep -i -q "$macaddr" "/sys/class/ieee80211/${phy}/macaddress" && {
+ path="$(iwinfo nl80211 path "$phy")"
+ rename_board_phy_by_path "$path"
+ return 0
+ }
+ done
+ }
+ return 1
+}
+
+mac80211_check_ap() {
+ has_ap=1
+}
+
+mac80211_set_ifname() {
+ local phy="$1"
+ local prefix="$2"
+ eval "ifname=\"$phy-$prefix\${idx_$prefix:-0}\"; idx_$prefix=\$((\${idx_$prefix:-0 } + 1))"
+}
+
+mac80211_prepare_vif() {
+ json_select config
+
+ json_get_vars ifname mode ssid wds powersave macaddr enable wpa_psk_file vlan_file
+
+ [ -n "$ifname" ] || {
+ local prefix;
+
+ case "$mode" in
+ ap|sta|mesh) prefix=$mode;;
+ adhoc) prefix=ibss;;
+ monitor) prefix=mon;;
+ esac
+
+ mac80211_set_ifname "$phy" "$prefix"
+ }
+
+ append active_ifnames "$ifname"
+ set_default wds 0
+ set_default powersave 0
+ json_add_string _ifname "$ifname"
+
+ default_macaddr=
+ if [ -z "$macaddr" ]; then
+ macaddr="$(mac80211_generate_mac $phy)"
+ macidx="$(($macidx + 1))"
+ default_macaddr=1
+ elif [ "$macaddr" = 'random' ]; then
+ macaddr="$(macaddr_random)"
+ fi
+ json_add_string _macaddr "$macaddr"
+ json_add_string _default_macaddr "$default_macaddr"
+ json_select ..
+
+
+ [ "$mode" == "ap" ] && {
+ [ -z "$wpa_psk_file" ] && hostapd_set_psk "$ifname"
+ [ -z "$vlan_file" ] && hostapd_set_vlan "$ifname"
+ }
+
+ json_select config
+
+ # It is far easier to delete and create the desired interface
+ case "$mode" in
+ ap)
+ # Hostapd will handle recreating the interface and
+ # subsequent virtual APs belonging to the same PHY
+ if [ -n "$hostapd_ctrl" ]; then
+ type=bss
+ else
+ type=interface
+ fi
+
+ mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
+
+ [ -n "$hostapd_ctrl" ] || {
+ ap_ifname="${ifname}"
+ hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
+ }
+ ;;
+ esac
+
+ json_select ..
+}
+
+mac80211_prepare_iw_htmode() {
+ case "$htmode" in
+ VHT20|HT20|HE20) iw_htmode=HT20;;
+ HT40*|VHT40|VHT160|HE40)
+ case "$band" in
+ 2g)
+ case "$htmode" in
+ HT40+) iw_htmode="HT40+";;
+ HT40-) iw_htmode="HT40-";;
+ *)
+ if [ "$channel" -lt 7 ]; then
+ iw_htmode="HT40+"
+ else
+ iw_htmode="HT40-"
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ case "$(( ($channel / 4) % 2 ))" in
+ 1) iw_htmode="HT40+" ;;
+ 0) iw_htmode="HT40-";;
+ esac
+ ;;
+ esac
+ [ "$auto_channel" -gt 0 ] && iw_htmode="HT40+"
+ ;;
+ VHT80|HE80)
+ iw_htmode="80MHZ"
+ ;;
+ NONE|NOHT)
+ iw_htmode="NOHT"
+ ;;
+ *) iw_htmode="" ;;
+ esac
+}
+
+mac80211_add_mesh_params() {
+ for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do
+ eval "mp_val=\"\$$var\""
+ [ -n "$mp_val" ] && json_add_string "$var" "$mp_val"
+ done
+}
+
+mac80211_setup_adhoc() {
+ local enable=$1
+ json_get_vars bssid ssid key mcast_rate
+
+ NEWUMLIST="${NEWUMLIST}$ifname "
+
+ [ "$enable" = 0 ] && {
+ ip link set dev "$ifname" down
+ return 0
+ }
+
+ keyspec=
+ [ "$auth_type" = "wep" ] && {
+ set_default key 1
+ case "$key" in
+ [1234])
+ local idx
+ for idx in 1 2 3 4; do
+ json_get_var ikey "key$idx"
+
+ [ -n "$ikey" ] && {
+ ikey="$(($idx - 1)):$(prepare_key_wep "$ikey")"
+ [ $idx -eq $key ] && ikey="d:$ikey"
+ append keyspec "$ikey"
+ }
+ done
+ ;;
+ *)
+ append keyspec "d:0:$(prepare_key_wep "$key")"
+ ;;
+ esac
+ }
+
+ brstr=
+ for br in $basic_rate_list; do
+ wpa_supplicant_add_rate brstr "$br"
+ done
+
+ mcval=
+ [ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
+
+ local prev
+ json_set_namespace wdev_uc prev
+
+ json_add_object "$ifname"
+ json_add_string mode adhoc
+ [ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
+ json_add_string ssid "$ssid"
+ json_add_string freq "$freq"
+ json_add_string htmode "$iw_htmode"
+ [ -n "$bssid" ] && json_add_string bssid "$bssid"
+ json_add_int beacon-interval "$beacon_int"
+ [ -n "$brstr" ] && json_add_string basic-rates "$brstr"
+ [ -n "$mcval" ] && json_add_string mcast-rate "$mcval"
+ [ -n "$keyspec" ] && json_add_string keys "$keyspec"
+ json_close_object
+
+ json_set_namespace "$prev"
+}
+
+mac80211_setup_mesh() {
+ json_get_vars ssid mesh_id mcast_rate
+
+ mcval=
+ [ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
+ [ -n "$mesh_id" ] && ssid="$mesh_id"
+
+ local prev
+ json_set_namespace wdev_uc prev
+
+ json_add_object "$ifname"
+ json_add_string mode mesh
+ [ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
+ json_add_string ssid "$ssid"
+ json_add_string freq "$freq"
+ json_add_string htmode "$iw_htmode"
+ [ -n "$mcval" ] && json_add_string mcast-rate "$mcval"
+ json_add_int beacon-interval "$beacon_int"
+ mac80211_add_mesh_params
+
+ json_close_object
+
+ json_set_namespace "$prev"
+}
+
+mac80211_setup_monitor() {
+ local prev
+ json_set_namespace wdev_uc prev
+
+ json_add_object "$ifname"
+ json_add_string mode monitor
+ [ -n "$freq" ] && json_add_string freq "$freq"
+ json_add_string htmode "$iw_htmode"
+ json_close_object
+
+ json_set_namespace "$prev"
+}
+
+mac80211_set_vif_txpower() {
+ local name="$1"
+
+ json_select config
+ json_get_var ifname _ifname
+ json_get_vars vif_txpower
+ json_select ..
+
+ [ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00"
+}
+
+wpa_supplicant_init_config() {
+ json_set_namespace wpa_supp prev
+
+ json_init
+ json_add_array config
+
+ json_set_namespace "$prev"
+}
+
+wpa_supplicant_add_interface() {
+ local ifname="$1"
+ local mode="$2"
+ local prev
+
+ _wpa_supplicant_common "$ifname"
+
+ json_set_namespace wpa_supp prev
+
+ json_add_object
+ json_add_string ctrl "$_rpath"
+ json_add_string iface "$ifname"
+ json_add_string mode "$mode"
+ json_add_string config "$_config"
+ [ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
+ [ -n "$network_bridge" ] && json_add_string bridge "$network_bridge"
+ [ -n "$wds" ] && json_add_boolean 4addr "$wds"
+ json_add_boolean powersave "$powersave"
+ [ "$mode" = "mesh" ] && mac80211_add_mesh_params
+ json_close_object
+
+ json_set_namespace "$prev"
+
+ wpa_supp_init=1
+}
+
+wpa_supplicant_set_config() {
+ local phy="$1"
+ local prev
+
+ json_set_namespace wpa_supp prev
+ json_close_array
+ json_add_string phy "$phy"
+ json_add_boolean defer 1
+ local data="$(json_dump)"
+
+ json_cleanup
+ json_set_namespace "$prev"
+
+ ubus -S -t 0 wait_for wpa_supplicant || {
+ [ -n "$wpa_supp_init" ] || return 0
+
+ ubus wait_for wpa_supplicant
+ }
+
+ local supplicant_res="$(ubus_call wpa_supplicant config_set "$data")"
+ ret="$?"
+ [ "$ret" != 0 -o -z "$supplicant_res" ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED
+
+ wireless_add_process "$(jsonfilter -s "$supplicant_res" -l 1 -e @.pid)" "/usr/sbin/wpa_supplicant" 1 1
+
+}
+
+hostapd_set_config() {
+ [ -n "$hostapd_ctrl" ] || {
+ ubus_call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"${hostapd_conf_file}.prev"'" }' > /dev/null
+ return 0;
+ }
+
+ ubus wait_for hostapd
+ local hostapd_res="$(ubus_call hostapd config_set "{ \"phy\": \"$phy\", \"config\":\"${hostapd_conf_file}\", \"prev_config\": \"${hostapd_conf_file}.prev\"}")"
+ ret="$?"
+ [ "$ret" != 0 -o -z "$hostapd_res" ] && {
+ wireless_setup_failed HOSTAPD_START_FAILED
+ return
+ }
+ wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1
+}
+
+
+wpa_supplicant_start() {
+ local phy="$1"
+
+ [ -n "$wpa_supp_init" ] || return 0
+
+ ubus_call wpa_supplicant config_set '{ "phy": "'"$phy"'" }' > /dev/null
+}
+
+mac80211_setup_supplicant() {
+ local enable=$1
+ local add_sp=0
+
+ wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1
+
+ if [ "$mode" = "sta" ]; then
+ wpa_supplicant_add_network "$ifname"
+ else
+ wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$hostapd_noscan"
+ fi
+
+ wpa_supplicant_add_interface "$ifname" "$mode"
+
+ return 0
+}
+
+mac80211_setup_vif() {
+ local name="$1"
+ local failed
+
+ json_select config
+ json_get_var ifname _ifname
+ json_get_var macaddr _macaddr
+ json_get_var default_macaddr _default_macaddr
+ json_get_vars mode wds powersave
+
+ set_default powersave 0
+ set_default wds 0
+
+ case "$mode" in
+ mesh)
+ json_get_vars $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING
+ wireless_vif_parse_encryption
+ [ -z "$htmode" ] && htmode="NOHT";
+ if wpa_supplicant -vmesh; then
+ mac80211_setup_supplicant || failed=1
+ else
+ mac80211_setup_mesh
+ fi
+ ;;
+ adhoc)
+ wireless_vif_parse_encryption
+ if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then
+ mac80211_setup_supplicant || failed=1
+ else
+ mac80211_setup_adhoc
+ fi
+ ;;
+ sta)
+ mac80211_setup_supplicant || failed=1
+ ;;
+ monitor)
+ mac80211_setup_monitor
+ ;;
+ esac
+
+ json_select ..
+ [ -n "$failed" ] || wireless_add_vif "$name" "$ifname"
+}
+
+get_freq() {
+ local phy="$1"
+ local channel="$2"
+ local band="$3"
+
+ case "$band" in
+ 2g) band="1:";;
+ 5g) band="2:";;
+ 60g) band="3:";;
+ 6g) band="4:";;
+ esac
+
+ iw "$phy" info | awk -v band="$band" -v channel="[$channel]" '
+
+$1 ~ /Band/ {
+ band_match = band == $2
+}
+
+band_match && $3 == "MHz" && $4 == channel {
+ print $2
+ exit
+}
+'
+}
+
+chan_is_dfs() {
+ local phy="$1"
+ local chan="$2"
+ iw "$phy" info | grep -E -m1 "(\* ${chan:-....} MHz${chan:+|\\[$chan\\]})" | grep -q "MHz.*radar detection"
+ return $!
+}
+
+mac80211_set_noscan() {
+ hostapd_noscan=1
+}
+
+drv_mac80211_cleanup() {
+ :
+}
+
+mac80211_reset_config() {
+ local phy="$1"
+
+ hostapd_conf_file="/var/run/hostapd-$phy.conf"
+ ubus_call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null
+ ubus_call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null
+ wdev_tool "$phy" set_config '{}'
+}
+
+drv_mac80211_setup() {
+ json_select config
+ json_get_vars \
+ phy macaddr path \
+ country chanbw distance \
+ txpower \
+ rxantenna txantenna \
+ frag rts beacon_int:100 htmode \
+ num_global_macaddr:1 multiple_bssid
+ json_get_values basic_rate_list basic_rate
+ json_get_values scan_list scan_list
+ json_select ..
+
+ json_select data && {
+ json_get_var prev_rxantenna rxantenna
+ json_get_var prev_txantenna txantenna
+ json_select ..
+ }
+
+ find_phy || {
+ echo "Could not find PHY for device '$1'"
+ wireless_set_retry 0
+ return 1
+ }
+
+ local wdev
+ local cwdev
+ local found
+
+ # convert channel to frequency
+ [ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel" "$band")"
+
+ [ -n "$country" ] && {
+ iw reg get | grep -q "^country $country:" || {
+ iw reg set "$country"
+ sleep 1
+ }
+ }
+
+ hostapd_conf_file="/var/run/hostapd-$phy.conf"
+
+ macidx=0
+ staidx=0
+
+ [ -n "$chanbw" ] && {
+ for file in /sys/kernel/debug/ieee80211/$phy/ath9k*/chanbw /sys/kernel/debug/ieee80211/$phy/ath5k/bwmode; do
+ [ -f "$file" ] && echo "$chanbw" > "$file"
+ done
+ }
+
+ set_default rxantenna 0xffffffff
+ set_default txantenna 0xffffffff
+ set_default distance 0
+
+ [ "$txantenna" = "all" ] && txantenna=0xffffffff
+ [ "$rxantenna" = "all" ] && rxantenna=0xffffffff
+
+ [ "$rxantenna" = "$prev_rxantenna" -a "$txantenna" = "$prev_txantenna" ] || mac80211_reset_config "$phy"
+ wireless_set_data phy="$phy" txantenna="$txantenna" rxantenna="$rxantenna"
+
+ iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1
+ iw phy "$phy" set distance "$distance" >/dev/null 2>&1
+
+ if [ -n "$txpower" ]; then
+ iw phy "$phy" set txpower fixed "${txpower%%.*}00"
+ else
+ iw phy "$phy" set txpower auto
+ fi
+
+ [ -n "$frag" ] && iw phy "$phy" set frag "${frag%%.*}"
+ [ -n "$rts" ] && iw phy "$phy" set rts "${rts%%.*}"
+
+ has_ap=
+ hostapd_ctrl=
+ ap_ifname=
+ hostapd_noscan=
+ wpa_supp_init=
+ for_each_interface "ap" mac80211_check_ap
+
+ [ -f "$hostapd_conf_file" ] && mv "$hostapd_conf_file" "$hostapd_conf_file.prev"
+
+ for_each_interface "sta adhoc mesh" mac80211_set_noscan
+ [ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy"
+
+ local prev
+ json_set_namespace wdev_uc prev
+ json_init
+ json_set_namespace "$prev"
+
+ wpa_supplicant_init_config
+
+ mac80211_prepare_iw_htmode
+ active_ifnames=
+ for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif
+ for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif
+
+ [ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy"
+ [ -x /usr/sbin/hostapd ] && hostapd_set_config "$phy"
+
+ [ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy"
+
+ json_set_namespace wdev_uc prev
+ wdev_tool "$phy" set_config "$(json_dump)" $active_ifnames
+ json_set_namespace "$prev"
+
+ for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower
+ wireless_set_up
+}
+
+_list_phy_interfaces() {
+ local phy="$1"
+ if [ -d "/sys/class/ieee80211/${phy}/device/net" ]; then
+ ls "/sys/class/ieee80211/${phy}/device/net" 2>/dev/null;
+ else
+ ls "/sys/class/ieee80211/${phy}/device" 2>/dev/null | grep net: | sed -e 's,net:,,g'
+ fi
+}
+
+list_phy_interfaces() {
+ local phy="$1"
+
+ for dev in $(_list_phy_interfaces "$phy"); do
+ readlink "/sys/class/net/${dev}/phy80211" | grep -q "/${phy}\$" || continue
+ echo "$dev"
+ done
+}
+
+drv_mac80211_teardown() {
+ json_select data
+ json_get_vars phy
+ json_select ..
+ [ -n "$phy" ] || {
+ echo "Bug: PHY is undefined for device '$1'"
+ return 1
+ }
+
+ mac80211_reset_config "$phy"
+
+ for wdev in $(list_phy_interfaces "$phy"); do
+ ip link set dev "$wdev" down
+ iw dev "$wdev" del
+ done
+}
+
+add_driver mac80211
diff --git a/package/network/config/wifi-scripts/files/lib/wifi/mac80211.sh b/package/network/config/wifi-scripts/files/lib/wifi/mac80211.sh
new file mode 100644
index 00000000000..e24a2a634ea
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/lib/wifi/mac80211.sh
@@ -0,0 +1,217 @@
+#!/bin/sh
+
+append DRIVERS "mac80211"
+
+check_mac80211_device() {
+ local device="$1"
+ local path="$2"
+ local macaddr="$3"
+
+ [ -n "$found" ] && return 0
+
+ phy_path=
+ config_get phy "$device" phy
+ json_select wlan
+ [ -n "$phy" ] && case "$phy" in
+ phy*)
+ [ -d /sys/class/ieee80211/$phy ] && \
+ phy_path="$(iwinfo nl80211 path "$dev")"
+ ;;
+ *)
+ if json_is_a "$phy" object; then
+ json_select "$phy"
+ json_get_var phy_path path
+ json_select ..
+ elif json_is_a "${phy%.*}" object; then
+ json_select "${phy%.*}"
+ json_get_var phy_path path
+ json_select ..
+ phy_path="$phy_path+${phy##*.}"
+ fi
+ ;;
+ esac
+ json_select ..
+ [ -n "$phy_path" ] || config_get phy_path "$device" path
+ [ -n "$path" -a "$phy_path" = "$path" ] && {
+ found=1
+ return 0
+ }
+
+ config_get dev_macaddr "$device" macaddr
+
+ [ -n "$macaddr" -a "$dev_macaddr" = "$macaddr" ] && found=1
+
+ return 0
+}
+
+
+__get_band_defaults() {
+ local phy="$1"
+
+ ( iw phy "$phy" info; echo ) | awk '
+BEGIN {
+ bands = ""
+}
+
+($1 == "Band" || $1 == "") && band {
+ if (channel) {
+ mode="NOHT"
+ if (ht) mode="HT20"
+ if (vht && band != "1:") mode="VHT80"
+ if (he) mode="HE80"
+ if (he && band == "1:") mode="HE20"
+ sub("\\[", "", channel)
+ sub("\\]", "", channel)
+ bands = bands band channel ":" mode " "
+ }
+ band=""
+}
+
+$1 == "Band" {
+ band = $2
+ channel = ""
+ vht = ""
+ ht = ""
+ he = ""
+}
+
+$0 ~ "Capabilities:" {
+ ht=1
+}
+
+$0 ~ "VHT Capabilities" {
+ vht=1
+}
+
+$0 ~ "HE Iftypes" {
+ he=1
+}
+
+$1 == "*" && $3 == "MHz" && $0 !~ /disabled/ && band && !channel {
+ channel = $4
+}
+
+END {
+ print bands
+}'
+}
+
+get_band_defaults() {
+ local phy="$1"
+
+ for c in $(__get_band_defaults "$phy"); do
+ local band="${c%%:*}"
+ c="${c#*:}"
+ local chan="${c%%:*}"
+ c="${c#*:}"
+ local mode="${c%%:*}"
+
+ case "$band" in
+ 1) band=2g;;
+ 2) band=5g;;
+ 3) band=60g;;
+ 4) band=6g;;
+ *) band="";;
+ esac
+
+ [ -n "$band" ] || continue
+ [ -n "$mode_band" -a "$band" = "6g" ] && return
+
+ mode_band="$band"
+ channel="$chan"
+ htmode="$mode"
+ done
+}
+
+check_devidx() {
+ case "$1" in
+ radio[0-9]*)
+ local idx="${1#radio}"
+ [ "$devidx" -ge "${1#radio}" ] && devidx=$((idx + 1))
+ ;;
+ esac
+}
+
+check_board_phy() {
+ local name="$2"
+
+ json_select "$name"
+ json_get_var phy_path path
+ json_select ..
+
+ if [ "$path" = "$phy_path" ]; then
+ board_dev="$name"
+ elif [ "${path%+*}" = "$phy_path" ]; then
+ fallback_board_dev="$name.${path#*+}"
+ fi
+}
+
+detect_mac80211() {
+ devidx=0
+ config_load wireless
+ config_foreach check_devidx wifi-device
+
+ json_load_file /etc/board.json
+
+ for _dev in /sys/class/ieee80211/*; do
+ [ -e "$_dev" ] || continue
+
+ dev="${_dev##*/}"
+
+ mode_band=""
+ channel=""
+ htmode=""
+ ht_capab=""
+
+ get_band_defaults "$dev"
+
+ path="$(iwinfo nl80211 path "$dev")"
+ macaddr="$(cat /sys/class/ieee80211/${dev}/macaddress)"
+
+ # work around phy rename related race condition
+ [ -n "$path" -o -n "$macaddr" ] || continue
+
+ board_dev=
+ fallback_board_dev=
+ json_for_each_item check_board_phy wlan
+ [ -n "$board_dev" ] || board_dev="$fallback_board_dev"
+ [ -n "$board_dev" ] && dev="$board_dev"
+
+ found=
+ config_foreach check_mac80211_device wifi-device "$path" "$macaddr"
+ [ -n "$found" ] && continue
+
+ name="radio${devidx}"
+ devidx=$(($devidx + 1))
+ case "$dev" in
+ phy*)
+ if [ -n "$path" ]; then
+ dev_id="set wireless.${name}.path='$path'"
+ else
+ dev_id="set wireless.${name}.macaddr='$macaddr'"
+ fi
+ ;;
+ *)
+ dev_id="set wireless.${name}.phy='$dev'"
+ ;;
+ esac
+
+ uci -q batch <<-EOF
+ set wireless.${name}=wifi-device
+ set wireless.${name}.type=mac80211
+ ${dev_id}
+ set wireless.${name}.channel=${channel}
+ set wireless.${name}.band=${mode_band}
+ set wireless.${name}.htmode=$htmode
+ set wireless.${name}.disabled=1
+
+ set wireless.default_${name}=wifi-iface
+ set wireless.default_${name}.device=${name}
+ set wireless.default_${name}.network=lan
+ set wireless.default_${name}.mode=ap
+ set wireless.default_${name}.ssid=OpenWrt
+ set wireless.default_${name}.encryption=none
+EOF
+ uci -q commit wireless
+ done
+}
diff --git a/package/network/config/wifi-scripts/files/sbin/wifi b/package/network/config/wifi-scripts/files/sbin/wifi
new file mode 100755
index 00000000000..27cbad37811
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/sbin/wifi
@@ -0,0 +1,273 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+usage() {
+ cat <<EOF
+Usage: $0 [config|up|down|reconf|reload|status|isup]
+enables (default), disables or configures devices not yet configured.
+EOF
+ exit 1
+}
+
+ubus_wifi_cmd() {
+ local cmd="$1"
+ local dev="$2"
+
+ json_init
+ [ -n "$dev" ] && json_add_string device "$dev"
+ ubus call network.wireless "$cmd" "$(json_dump)"
+}
+
+wifi_isup() {
+ local dev="$1"
+
+ json_load "$(ubus_wifi_cmd "status" "$dev")"
+ json_get_keys devices
+
+ for device in $devices; do
+ json_select "$device"
+ json_get_var up up
+ [ $up -eq 0 ] && return 1
+ json_select ..
+ done
+
+ return 0
+}
+
+find_net_config() {(
+ local vif="$1"
+ local cfg
+ local ifname
+
+ config_get cfg "$vif" network
+
+ [ -z "$cfg" ] && {
+ include /lib/network
+ scan_interfaces
+
+ config_get ifname "$vif" ifname
+
+ cfg="$(find_config "$ifname")"
+ }
+ [ -z "$cfg" ] && return 0
+ echo "$cfg"
+)}
+
+
+bridge_interface() {(
+ local cfg="$1"
+ [ -z "$cfg" ] && return 0
+
+ include /lib/network
+ scan_interfaces
+
+ for cfg in $cfg; do
+ config_get iftype "$cfg" type
+ [ "$iftype" = bridge ] && config_get "$cfg" ifname
+ prepare_interface_bridge "$cfg"
+ return $?
+ done
+)}
+
+prepare_key_wep() {
+ local key="$1"
+ local hex=1
+
+ echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
+ [ "${#key}" -eq 10 -a $hex -eq 1 ] || \
+ [ "${#key}" -eq 26 -a $hex -eq 1 ] || {
+ [ "${key:0:2}" = "s:" ] && key="${key#s:}"
+ key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
+ }
+ echo "$key"
+}
+
+wifi_fixup_hwmode() {
+ local device="$1"
+ local default="$2"
+ local hwmode hwmode_11n
+
+ config_get channel "$device" channel
+ config_get hwmode "$device" hwmode
+ case "$hwmode" in
+ 11bg) hwmode=bg;;
+ 11a) hwmode=a;;
+ 11ad) hwmode=ad;;
+ 11b) hwmode=b;;
+ 11g) hwmode=g;;
+ 11n*)
+ hwmode_11n="${hwmode##11n}"
+ case "$hwmode_11n" in
+ a|g) ;;
+ default) hwmode_11n="$default"
+ esac
+ config_set "$device" hwmode_11n "$hwmode_11n"
+ ;;
+ *)
+ hwmode=
+ if [ "${channel:-0}" -gt 0 ]; then
+ if [ "${channel:-0}" -gt 14 ]; then
+ hwmode=a
+ else
+ hwmode=g
+ fi
+ else
+ hwmode="$default"
+ fi
+ ;;
+ esac
+ config_set "$device" hwmode "$hwmode"
+}
+
+_wifi_updown() {
+ for device in ${2:-$DEVICES}; do (
+ config_get disabled "$device" disabled
+ [ "$disabled" = "1" ] && {
+ echo "'$device' is disabled"
+ set disable
+ }
+ config_get iftype "$device" type
+ if eval "type ${1}_$iftype" 2>/dev/null >/dev/null; then
+ eval "scan_$iftype '$device'"
+ eval "${1}_$iftype '$device'" || echo "$device($iftype): ${1} failed"
+ elif [ ! -f /lib/netifd/wireless/$iftype.sh ]; then
+ echo "$device($iftype): Interface type not supported"
+ fi
+ ); done
+}
+
+wifi_updown() {
+ cmd=down
+ [ enable = "$1" ] && {
+ _wifi_updown disable "$2"
+ ubus_wifi_cmd "$cmd" "$2"
+ ubus call network reload
+ scan_wifi
+ cmd=up
+ }
+ [ reconf = "$1" ] && {
+ ubus call network reload
+ scan_wifi
+ cmd=reconf
+ }
+ ubus_wifi_cmd "$cmd" "$2"
+ _wifi_updown "$@"
+}
+
+wifi_reload_legacy() {
+ _wifi_updown "disable" "$1"
+ scan_wifi
+ _wifi_updown "enable" "$1"
+}
+
+wifi_reload() {
+ ubus call network reload
+ wifi_reload_legacy
+}
+
+wifi_detect_notice() {
+ >&2 echo "WARNING: Wifi detect is deprecated. Use wifi config instead"
+ >&2 echo "For more information, see commit 5f8f8a366136a07df661e31decce2458357c167a"
+ exit 1
+}
+
+wifi_config() {
+ [ -e /tmp/.config_pending ] && return
+ ucode /usr/share/hostap/wifi-detect.uc
+ [ ! -f /etc/config/wireless ] && touch /etc/config/wireless
+
+ for driver in $DRIVERS; do (
+ if eval "type detect_$driver" 2>/dev/null >/dev/null; then
+ eval "detect_$driver" || echo "$driver: Detect failed" >&2
+ else
+ echo "$driver: Hardware detection not supported" >&2
+ fi
+ ); done
+}
+
+start_net() {(
+ local iface="$1"
+ local config="$2"
+ local vifmac="$3"
+
+ [ -f "/var/run/$iface.pid" ] && kill "$(cat /var/run/${iface}.pid)" 2>/dev/null
+ [ -z "$config" ] || {
+ include /lib/network
+ scan_interfaces
+ for config in $config; do
+ setup_interface "$iface" "$config" "" "$vifmac"
+ done
+ }
+)}
+
+set_wifi_up() {
+ local cfg="$1"
+ local ifname="$2"
+ uci_set_state wireless "$cfg" up 1
+ uci_set_state wireless "$cfg" ifname "$ifname"
+}
+
+set_wifi_down() {
+ local cfg="$1"
+ local vifs vif vifstr
+
+ [ -f "/var/run/wifi-${cfg}.pid" ] &&
+ kill "$(cat "/var/run/wifi-${cfg}.pid")" 2>/dev/null
+ uci_revert_state wireless "$cfg"
+ config_get vifs "$cfg" vifs
+ for vif in $vifs; do
+ uci_revert_state wireless "$vif"
+ done
+}
+
+scan_wifi() {
+ local cfgfile="$1"
+ DEVICES=
+ config_cb() {
+ local type="$1"
+ local section="$2"
+
+ # section start
+ case "$type" in
+ wifi-device)
+ append DEVICES "$section"
+ config_set "$section" vifs ""
+ config_set "$section" ht_capab ""
+ ;;
+ esac
+
+ # section end
+ config_get TYPE "$CONFIG_SECTION" TYPE
+ case "$TYPE" in
+ wifi-iface)
+ config_get device "$CONFIG_SECTION" device
+ config_get vifs "$device" vifs
+ append vifs "$CONFIG_SECTION"
+ config_set "$device" vifs "$vifs"
+ ;;
+ esac
+ }
+ config_load "${cfgfile:-wireless}"
+}
+
+DEVICES=
+DRIVERS=
+include /lib/wifi
+scan_wifi
+
+case "$1" in
+ down) wifi_updown "disable" "$2";;
+ detect) wifi_detect_notice ;;
+ config) wifi_config ;;
+ status) ubus_wifi_cmd "status" "$2";;
+ isup) wifi_isup "$2"; exit $?;;
+ reload) wifi_reload "$2";;
+ reload_legacy) wifi_reload_legacy "$2";;
+ --help|help) usage;;
+ reconf) wifi_updown "reconf" "$2";;
+ ''|up) wifi_updown "enable" "$2";;
+ *) usage; exit 1;;
+esac
diff --git a/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc b/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc
new file mode 100644
index 00000000000..750e3ae71c2
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc
@@ -0,0 +1,373 @@
+import * as nl80211 from "nl80211";
+import * as rtnl from "rtnl";
+import { readfile, glob, basename, readlink } from "fs";
+
+const iftypes = {
+ ap: nl80211.const.NL80211_IFTYPE_AP,
+ mesh: nl80211.const.NL80211_IFTYPE_MESH_POINT,
+ sta: nl80211.const.NL80211_IFTYPE_STATION,
+ adhoc: nl80211.const.NL80211_IFTYPE_ADHOC,
+ monitor: nl80211.const.NL80211_IFTYPE_MONITOR,
+};
+
+const mesh_params = {
+ mesh_retry_timeout: "retry_timeout",
+ mesh_confirm_timeout: "confirm_timeout",
+ mesh_holding_timeout: "holding_timeout",
+ mesh_max_peer_links: "max_peer_links",
+ mesh_max_retries: "max_retries",
+ mesh_ttl: "ttl",
+ mesh_element_ttl: "element_ttl",
+ mesh_auto_open_plinks: "auto_open_plinks",
+ mesh_hwmp_max_preq_retries: "hwmp_max_preq_retries",
+ mesh_path_refresh_time: "path_refresh_time",
+ mesh_min_discovery_timeout: "min_discovery_timeout",
+ mesh_hwmp_active_path_timeout: "hwmp_active_path_timeout",
+ mesh_hwmp_preq_min_interval: "hwmp_preq_min_interval",
+ mesh_hwmp_net_diameter_traversal_time: "hwmp_net_diam_trvs_time",
+ mesh_hwmp_rootmode: "hwmp_rootmode",
+ mesh_hwmp_rann_interval: "hwmp_rann_interval",
+ mesh_gate_announcements: "gate_announcements",
+ mesh_sync_offset_max_neighor: "sync_offset_max_neighbor",
+ mesh_rssi_threshold: "rssi_threshold",
+ mesh_hwmp_active_path_to_root_timeout: "hwmp_path_to_root_timeout",
+ mesh_hwmp_root_interval: "hwmp_root_interval",
+ mesh_hwmp_confirmation_interval: "hwmp_confirmation_interval",
+ mesh_awake_window: "awake_window",
+ mesh_plink_timeout: "plink_timeout",
+ mesh_fwding: "forwarding",
+ mesh_power_mode: "power_mode",
+ mesh_nolearn: "nolearn"
+};
+
+function wdev_remove(name)
+{
+ nl80211.request(nl80211.const.NL80211_CMD_DEL_INTERFACE, 0, { dev: name });
+}
+
+function __phy_is_fullmac(phyidx)
+{
+ let data = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, 0, { wiphy: phyidx });
+
+ return !data.software_iftypes.monitor;
+}
+
+function phy_is_fullmac(phy)
+{
+ let phyidx = int(trim(readfile(`/sys/class/ieee80211/${phy}/index`)));
+
+ return __phy_is_fullmac(phyidx);
+}
+
+function find_reusable_wdev(phyidx)
+{
+ if (!__phy_is_fullmac(phyidx))
+ return null;
+
+ let data = nl80211.request(
+ nl80211.const.NL80211_CMD_GET_INTERFACE,
+ nl80211.const.NLM_F_DUMP,
+ { wiphy: phyidx });
+ for (let res in data)
+ if (trim(readfile(`/sys/class/net/${res.ifname}/operstate`)) == "down")
+ return res.ifname;
+ return null;
+}
+
+function wdev_create(phy, name, data)
+{
+ let phyidx = int(readfile(`/sys/class/ieee80211/${phy}/index`));
+
+ wdev_remove(name);
+
+ if (!iftypes[data.mode])
+ return `Invalid mode: ${data.mode}`;
+
+ let req = {
+ wiphy: phyidx,
+ ifname: name,
+ iftype: iftypes[data.mode],
+ };
+
+ if (data["4addr"])
+ req["4addr"] = data["4addr"];
+ if (data.macaddr)
+ req.mac = data.macaddr;
+
+ nl80211.error();
+
+ let reuse_ifname = find_reusable_wdev(phyidx);
+ if (reuse_ifname &&
+ (reuse_ifname == name ||
+ rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: reuse_ifname, ifname: name}) != false))
+ nl80211.request(
+ nl80211.const.NL80211_CMD_SET_INTERFACE, 0, {
+ wiphy: phyidx,
+ dev: name,
+ iftype: iftypes[data.mode],
+ });
+ else
+ nl80211.request(
+ nl80211.const.NL80211_CMD_NEW_INTERFACE,
+ nl80211.const.NLM_F_CREATE,
+ req);
+
+ let error = nl80211.error();
+ if (error)
+ return error;
+
+ if (data.powersave != null) {
+ nl80211.request(nl80211.const.NL80211_CMD_SET_POWER_SAVE, 0,
+ { dev: name, ps_state: data.powersave ? 1 : 0});
+ }
+
+ return null;
+}
+
+function wdev_set_mesh_params(name, data)
+{
+ let mesh_cfg = {};
+
+ for (let key in mesh_params) {
+ let val = data[key];
+ if (val == null)
+ continue;
+ mesh_cfg[mesh_params[key]] = int(val);
+ }
+
+ if (!length(mesh_cfg))
+ return null;
+
+ nl80211.request(nl80211.const.NL80211_CMD_SET_MESH_CONFIG, 0,
+ { dev: name, mesh_params: mesh_cfg });
+
+ return nl80211.error();
+}
+
+function wdev_set_up(name, up)
+{
+ rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: name, change: 1, flags: up ? 1 : 0 });
+}
+
+function phy_sysfs_file(phy, name)
+{
+ return trim(readfile(`/sys/class/ieee80211/${phy}/${name}`));
+}
+
+function macaddr_split(str)
+{
+ return map(split(str, ":"), (val) => hex(val));
+}
+
+function macaddr_join(addr)
+{
+ return join(":", map(addr, (val) => sprintf("%02x", val)));
+}
+
+function wdev_macaddr(wdev)
+{
+ return trim(readfile(`/sys/class/net/${wdev}/address`));
+}
+
+const phy_proto = {
+ macaddr_init: function(used, options) {
+ this.macaddr_options = options ?? {};
+ this.macaddr_list = {};
+
+ if (type(used) == "object")
+ for (let addr in used)
+ this.macaddr_list[addr] = used[addr];
+ else
+ for (let addr in used)
+ this.macaddr_list[addr] = -1;
+
+ this.for_each_wdev((wdev) => {
+ let macaddr = wdev_macaddr(wdev);
+ this.macaddr_list[macaddr] ??= -1;
+ });
+
+ return this.macaddr_list;
+ },
+
+ macaddr_generate: function(data) {
+ let phy = this.name;
+ let idx = int(data.id ?? 0);
+ let mbssid = int(data.mbssid ?? 0) > 0;
+ let num_global = int(data.num_global ?? 1);
+ let use_global = !mbssid && idx < num_global;
+
+ let base_addr = phy_sysfs_file(phy, "macaddress");
+ if (!base_addr)
+ return null;
+
+ if (!idx && !mbssid)
+ return base_addr;
+
+ let base_mask = phy_sysfs_file(phy, "address_mask");
+ if (!base_mask)
+ return null;
+
+ if (base_mask == "00:00:00:00:00:00" && idx >= num_global) {
+ let addrs = split(phy_sysfs_file(phy, "addresses"), "\n");
+
+ if (idx < length(addrs))
+ return addrs[idx];
+
+ base_mask = "ff:ff:ff:ff:ff:ff";
+ }
+
+ let addr = macaddr_split(base_addr);
+ let mask = macaddr_split(base_mask);
+ let type;
+
+ if (mbssid)
+ type = "b5";
+ else if (use_global)
+ type = "add";
+ else if (mask[0] > 0)
+ type = "b1";
+ else if (mask[5] < 0xff)
+ type = "b5";
+ else
+ type = "add";
+
+ switch (type) {
+ case "b1":
+ if (!(addr[0] & 2))
+ idx--;
+ addr[0] |= 2;
+ addr[0] ^= idx << 2;
+ break;
+ case "b5":
+ if (mbssid)
+ addr[0] |= 2;
+ addr[5] ^= idx;
+ break;
+ default:
+ for (let i = 5; i > 0; i--) {
+ addr[i] += idx;
+ if (addr[i] < 256)
+ break;
+ addr[i] %= 256;
+ }
+ break;
+ }
+
+ return macaddr_join(addr);
+ },
+
+ macaddr_next: function(val) {
+ let data = this.macaddr_options ?? {};
+ let list = this.macaddr_list;
+
+ for (let i = 0; i < 32; i++) {
+ data.id = i;
+
+ let mac = this.macaddr_generate(data);
+ if (!mac)
+ return null;
+
+ if (list[mac] != null)
+ continue;
+
+ list[mac] = val != null ? val : -1;
+ return mac;
+ }
+ },
+
+ for_each_wdev: function(cb) {
+ let wdevs = glob(`/sys/class/ieee80211/${this.name}/device/net/*`);
+ wdevs = map(wdevs, (arg) => basename(arg));
+ for (let wdev in wdevs) {
+ if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != this.name)
+ continue;
+
+ cb(wdev);
+ }
+ }
+};
+
+function phy_open(phy)
+{
+ let phyidx = readfile(`/sys/class/ieee80211/${phy}/index`);
+ if (!phyidx)
+ return null;
+
+ return proto({
+ name: phy,
+ idx: int(phyidx)
+ }, phy_proto);
+}
+
+const vlist_proto = {
+ update: function(values, arg) {
+ let data = this.data;
+ let cb = this.cb;
+ let seq = { };
+ let new_data = {};
+ let old_data = {};
+
+ this.data = new_data;
+
+ if (type(values) == "object") {
+ for (let key in values) {
+ old_data[key] = data[key];
+ new_data[key] = values[key];
+ delete data[key];
+ }
+ } else {
+ for (let val in values) {
+ let cur_key = val[0];
+ let cur_obj = val[1];
+
+ old_data[cur_key] = data[cur_key];
+ new_data[cur_key] = val[1];
+ delete data[cur_key];
+ }
+ }
+
+ for (let key in data) {
+ cb(null, data[key], arg);
+ delete data[key];
+ }
+ for (let key in new_data)
+ cb(new_data[key], old_data[key], arg);
+ }
+};
+
+function is_equal(val1, val2) {
+ let t1 = type(val1);
+
+ if (t1 != type(val2))
+ return false;
+
+ if (t1 == "array") {
+ if (length(val1) != length(val2))
+ return false;
+
+ for (let i = 0; i < length(val1); i++)
+ if (!is_equal(val1[i], val2[i]))
+ return false;
+
+ return true;
+ } else if (t1 == "object") {
+ for (let key in val1)
+ if (!is_equal(val1[key], val2[key]))
+ return false;
+ for (let key in val2)
+ if (val1[key] == null)
+ return false;
+ return true;
+ } else {
+ return val1 == val2;
+ }
+}
+
+function vlist_new(cb) {
+ return proto({
+ cb: cb,
+ data: {}
+ }, vlist_proto);
+}
+
+export { wdev_remove, wdev_create, wdev_set_mesh_params, wdev_set_up, is_equal, vlist_new, phy_is_fullmac, phy_open };
diff --git a/package/network/config/wifi-scripts/files/usr/share/hostap/wdev.uc b/package/network/config/wifi-scripts/files/usr/share/hostap/wdev.uc
new file mode 100644
index 00000000000..ff4d629fd64
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/usr/share/hostap/wdev.uc
@@ -0,0 +1,185 @@
+#!/usr/bin/env ucode
+'use strict';
+import { vlist_new, is_equal, wdev_create, wdev_set_mesh_params, wdev_remove, wdev_set_up, phy_open } from "/usr/share/hostap/common.uc";
+import { readfile, writefile, basename, readlink, glob } from "fs";
+let libubus = require("ubus");
+
+let keep_devices = {};
+let phy = shift(ARGV);
+let command = shift(ARGV);
+let phydev;
+
+function iface_stop(wdev)
+{
+ if (keep_devices[wdev.ifname])
+ return;
+
+ wdev_remove(wdev.ifname);
+}
+
+function iface_start(wdev)
+{
+ let ifname = wdev.ifname;
+
+ if (readfile(`/sys/class/net/${ifname}/ifindex`)) {
+ wdev_set_up(ifname, false);
+ wdev_remove(ifname);
+ }
+ let wdev_config = {};
+ for (let key in wdev)
+ wdev_config[key] = wdev[key];
+ if (!wdev_config.macaddr && wdev.mode != "monitor")
+ wdev_config.macaddr = phydev.macaddr_next();
+ wdev_create(phy, ifname, wdev_config);
+ wdev_set_up(ifname, true);
+ if (wdev.freq)
+ system(`iw dev ${ifname} set freq ${wdev.freq} ${wdev.htmode}`);
+ if (wdev.mode == "adhoc") {
+ let cmd = ["iw", "dev", ifname, "ibss", "join", wdev.ssid, wdev.freq, wdev.htmode, "fixed-freq" ];
+ if (wdev.bssid)
+ push(cmd, wdev.bssid);
+ for (let key in [ "beacon-interval", "basic-rates", "mcast-rate", "keys" ])
+ if (wdev[key])
+ push(cmd, key, wdev[key]);
+ system(cmd);
+ } else if (wdev.mode == "mesh") {
+ let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ];
+ for (let key in [ "mcast-rate", "beacon-interval" ])
+ if (wdev[key])
+ push(cmd, key, wdev[key]);
+ system(cmd);
+
+ wdev_set_mesh_params(ifname, wdev);
+ }
+}
+
+function iface_cb(new_if, old_if)
+{
+ if (old_if && new_if && is_equal(old_if, new_if))
+ return;
+
+ if (old_if)
+ iface_stop(old_if);
+ if (new_if)
+ iface_start(new_if);
+}
+
+function drop_inactive(config)
+{
+ for (let key in config) {
+ if (!readfile(`/sys/class/net/${key}/ifindex`))
+ delete config[key];
+ }
+}
+
+function add_ifname(config)
+{
+ for (let key in config)
+ config[key].ifname = key;
+}
+
+function delete_ifname(config)
+{
+ for (let key in config)
+ delete config[key].ifname;
+}
+
+function add_existing(phy, config)
+{
+ let wdevs = glob(`/sys/class/ieee80211/${phy}/device/net/*`);
+ wdevs = map(wdevs, (arg) => basename(arg));
+ for (let wdev in wdevs) {
+ if (config[wdev])
+ continue;
+
+ if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != phy)
+ continue;
+
+ if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
+ config[wdev] = {};
+ }
+}
+
+function usage()
+{
+ warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
+
+Commands:
+ set_config <config> [<device]...] - set phy configuration
+ get_macaddr <id> - get phy MAC address for vif index <id>
+`);
+ exit(1);
+}
+
+const commands = {
+ set_config: function(args) {
+ let statefile = `/var/run/wdev-${phy}.json`;
+
+ let new_config = shift(args);
+ for (let dev in ARGV)
+ keep_devices[dev] = true;
+
+ if (!new_config)
+ usage();
+
+ new_config = json(new_config);
+ if (!new_config) {
+ warn("Invalid configuration\n");
+ exit(1);
+ }
+
+ let old_config = readfile(statefile);
+ if (old_config)
+ old_config = json(old_config);
+
+ let config = vlist_new(iface_cb);
+ if (type(old_config) == "object")
+ config.data = old_config;
+
+ add_existing(phy, config.data);
+ add_ifname(config.data);
+ drop_inactive(config.data);
+
+ let ubus = libubus.connect();
+ let data = ubus.call("hostapd", "config_get_macaddr_list", { phy: phy });
+ let macaddr_list = [];
+ if (type(data) == "object" && data.macaddr)
+ macaddr_list = data.macaddr;
+ ubus.disconnect();
+ phydev.macaddr_init(macaddr_list);
+
+ add_ifname(new_config);
+ config.update(new_config);
+
+ drop_inactive(config.data);
+ delete_ifname(config.data);
+ writefile(statefile, sprintf("%J", config.data));
+ },
+ get_macaddr: function(args) {
+ let data = {};
+
+ for (let arg in args) {
+ arg = split(arg, "=", 2);
+ data[arg[0]] = arg[1];
+ }
+
+ let macaddr = phydev.macaddr_generate(data);
+ if (!macaddr) {
+ warn(`Could not get MAC address for phy ${phy}\n`);
+ exit(1);
+ }
+
+ print(macaddr + "\n");
+ },
+};
+
+if (!phy || !command | !commands[command])
+ usage();
+
+phydev = phy_open(phy);
+if (!phydev) {
+ warn(`PHY ${phy} does not exist\n`);
+ exit(1);
+}
+
+commands[command](ARGV);
diff --git a/package/network/config/wifi-scripts/files/usr/share/hostap/wifi-detect.uc b/package/network/config/wifi-scripts/files/usr/share/hostap/wifi-detect.uc
new file mode 100644
index 00000000000..5f375880d2b
--- /dev/null
+++ b/package/network/config/wifi-scripts/files/usr/share/hostap/wifi-detect.uc
@@ -0,0 +1,155 @@
+#!/usr/bin/env ucode
+'use strict';
+import { readfile, writefile, realpath, glob, basename, unlink, open, rename } from "fs";
+import { is_equal } from "/usr/share/hostap/common.uc";
+let nl = require("nl80211");
+
+let board_file = "/etc/board.json";
+let prev_board_data = json(readfile(board_file));
+let board_data = json(readfile(board_file));
+
+function phy_idx(name) {
+ return +rtrim(readfile(`/sys/class/ieee80211/${name}/index`));
+}
+
+function phy_path(name) {
+ let devpath = realpath(`/sys/class/ieee80211/${name}/device`);
+
+ devpath = replace(devpath, /^\/sys\/devices\//, "");
+ if (match(devpath, /^platform\/.*\/pci/))
+ devpath = replace(devpath, /^platform\//, "");
+ let dev_phys = map(glob(`/sys/class/ieee80211/${name}/device/ieee80211/*`), basename);
+ sort(dev_phys, (a, b) => phy_idx(a) - phy_idx(b));
+
+ let ofs = index(dev_phys, name);
+ if (ofs > 0)
+ devpath += `+${ofs}`;
+
+ return devpath;
+}
+
+function cleanup() {
+ let wlan = board_data.wlan;
+
+ for (let name in wlan)
+ if (substr(name, 0, 3) == "phy")
+ delete wlan[name];
+ else
+ delete wlan[name].info;
+}
+
+function wiphy_get_entry(phy, path) {
+ board_data.wlan ??= {};
+
+ let wlan = board_data.wlan;
+ for (let name in wlan)
+ if (wlan[name].path == path)
+ return wlan[name];
+
+ wlan[phy] = {
+ path: path
+ };
+
+ return wlan[phy];
+}
+
+function wiphy_detect() {
+ let phys = nl.request(nl.const.NL80211_CMD_GET_WIPHY, nl.const.NLM_F_DUMP, { split_wiphy_dump: true });
+ if (!phys)
+ return;
+
+ for (let phy in phys) {
+ let name = phy.wiphy_name;
+ let path = phy_path(name);
+ let info = {
+ antenna_rx: phy.wiphy_antenna_avail_rx,
+ antenna_tx: phy.wiphy_antenna_avail_tx,
+ bands: {},
+ };
+
+ let bands = info.bands;
+ for (let band in phy.wiphy_bands) {
+ if (!band || !band.freqs)
+ continue;
+ let freq = band.freqs[0].freq;
+ let band_info = {};
+ let band_name;
+ if (freq > 50000)
+ band_name = "60G";
+ else if (freq > 5900)
+ band_name = "6G";
+ else if (freq > 4000)
+ band_name = "5G";
+ else
+ band_name = "2G";
+ bands[band_name] = band_info;
+ if (band.ht_capa > 0)
+ band_info.ht = true;
+ if (band.vht_capa > 0)
+ band_info.vht = true;
+ let he_phy_cap = 0;
+
+ for (let ift in band.iftype_data) {
+ if (!ift.he_cap_phy)
+ continue;
+
+ band_info.he = true;
+ he_phy_cap |= ift.he_cap_phy[0];
+ /* TODO: EHT */
+ }
+
+ if (band_name != "2G" &&
+ (he_phy_cap & 0x18) || ((band.vht_capa >> 2) & 0x3))
+ band_info.max_width = 160;
+ else if (band_name != "2G" &&
+ (he_phy_cap & 4) || band.vht_capa > 0)
+ band_info.max_width = 80;
+ else if ((band.ht_capa & 0x2) || (he_phy_cap & 0x2))
+ band_info.max_width = 40;
+ else
+ band_info.max_width = 20;
+
+ let modes = band_info.modes = [ "NOHT" ];
+ if (band_info.ht)
+ push(modes, "HT20");
+ if (band_info.vht)
+ push(modes, "VHT20");
+ if (band_info.he)
+ push(modes, "HE20");
+ if (band.ht_capa & 0x2) {
+ push(modes, "HT40");
+ if (band_info.vht)
+ push(modes, "VHT40")
+ }
+ if (he_phy_cap & 0x2)
+ push(modes, "HE40");
+
+ if (band_name == "2G")
+ continue;
+ if (band_info.vht)
+ push(modes, "VHT80");
+ if (he_phy_cap & 4)
+ push(modes, "HE80");
+ if ((band.vht_capa >> 2) & 0x3)
+ push(modes, "VHT160");
+ if (he_phy_cap & 0x18)
+ push(modes, "HE160");
+ }
+
+ let entry = wiphy_get_entry(name, path);
+ entry.info = info;
+ }
+}
+
+cleanup();
+wiphy_detect();
+if (!is_equal(prev_board_data, board_data)) {
+ let new_file = board_file + ".new";
+ unlink(new_file);
+ let f = open(new_file, "wx");
+ if (!f)
+ exit(1);
+ f.write(sprintf("%.J\n", board_data));
+ f.close();
+ rename(new_file, board_file);
+}
diff --git a/package/network/ipv6/464xlat/Makefile b/package/network/ipv6/464xlat/Makefile
index c792323235f..ab09b1e6ddb 100644
--- a/package/network/ipv6/464xlat/Makefile
+++ b/package/network/ipv6/464xlat/Makefile
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=464xlat
-PKG_RELEASE:=12
+PKG_RELEASE:=13
PKG_SOURCE_DATE:=2018-01-16
PKG_MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
diff --git a/package/network/ipv6/464xlat/files/464xlat.sh b/package/network/ipv6/464xlat/files/464xlat.sh
index c90ac1af59a..dbe38b3cacf 100755
--- a/package/network/ipv6/464xlat/files/464xlat.sh
+++ b/package/network/ipv6/464xlat/files/464xlat.sh
@@ -98,6 +98,9 @@ proto_464xlat_teardown() {
ip -6 rule del from all lookup local
ip -6 rule add from all lookup local pref 0
fi
+
+ # Kill conntracks SNATed to 192.0.0.1
+ echo 192.0.0.1 > /proc/net/nf_conntrack
}
proto_464xlat_init_config() {
diff --git a/package/network/ipv6/6in4/Makefile b/package/network/ipv6/6in4/Makefile
index 08696ef7a89..edbb7d71a01 100644
--- a/package/network/ipv6/6in4/Makefile
+++ b/package/network/ipv6/6in4/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=6in4
-PKG_RELEASE:=26
+PKG_RELEASE:=28
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
diff --git a/package/network/ipv6/6rd/Makefile b/package/network/ipv6/6rd/Makefile
index 9836ae9361c..3ab8198ef31 100644
--- a/package/network/ipv6/6rd/Makefile
+++ b/package/network/ipv6/6rd/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=6rd
-PKG_RELEASE:=10
+PKG_RELEASE:=13
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
diff --git a/package/network/ipv6/6rd/files/6rd.sh b/package/network/ipv6/6rd/files/6rd.sh
index 62a20314d93..dad61118fe6 100644
--- a/package/network/ipv6/6rd/files/6rd.sh
+++ b/package/network/ipv6/6rd/files/6rd.sh
@@ -40,8 +40,8 @@ proto_6rd_setup() {
# Determine the relay prefix.
local ip4prefixlen="${ip4prefixlen:-0}"
- local ip4prefix
- eval "$(ipcalc.sh "$ipaddr/$ip4prefixlen")";ip4prefix=$NETWORK
+ local ip4prefix IP PREFIX NETWORK NETMASK BROADCAST
+ ipcalc "$ipaddr/$ip4prefixlen" && ip4prefix="$NETWORK"
# Determine our IPv6 address.
local ip6subnet=$(6rdcalc "$ip6prefix/$ip6prefixlen" "$ipaddr/$ip4prefixlen")
diff --git a/package/network/ipv6/odhcp6c/Makefile b/package/network/ipv6/odhcp6c/Makefile
index a4e62d04f23..ac507e1f17a 100644
--- a/package/network/ipv6/odhcp6c/Makefile
+++ b/package/network/ipv6/odhcp6c/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=odhcp6c
-PKG_RELEASE:=18
+PKG_RELEASE:=20
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcp6c.git
-PKG_SOURCE_DATE:=2021-01-09
-PKG_SOURCE_VERSION:=53f07e90b7f1da6977143a488dd5cb73a33b233b
-PKG_MIRROR_HASH:=ad3665b611d19177996771b11df28d92f066b0125484ea3bdfc0b3185c14f90e
+PKG_SOURCE_DATE:=2023-05-12
+PKG_SOURCE_VERSION:=bcd283632ac13391aac3ebdd074d1fd832d76fa3
+PKG_MIRROR_HASH:=0f3508a5a148ca831ae30b49b21919535f9dfbbd003a942baa6cb5388d207878
PKG_MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
PKG_LICENSE:=GPL-2.0
diff --git a/package/network/ipv6/odhcp6c/files/dhcpv6.sh b/package/network/ipv6/odhcp6c/files/dhcpv6.sh
index cf6847f29e2..18c24febd61 100755
--- a/package/network/ipv6/odhcp6c/files/dhcpv6.sh
+++ b/package/network/ipv6/odhcp6c/files/dhcpv6.sh
@@ -34,11 +34,13 @@ proto_dhcpv6_init_config() {
proto_config_add_string "vendorclass"
proto_config_add_array "sendopts:list(string)"
proto_config_add_boolean delegate
+ proto_config_add_int skpriority
proto_config_add_int "soltimeout"
proto_config_add_boolean fakeroutes
proto_config_add_boolean sourcefilter
proto_config_add_boolean keep_ra_dnslifetime
proto_config_add_int "ra_holdoff"
+ proto_config_add_boolean verbose
}
proto_dhcpv6_add_prefix() {
@@ -53,8 +55,8 @@ proto_dhcpv6_setup() {
local config="$1"
local iface="$2"
- local reqaddress reqprefix clientid reqopts defaultreqopts noslaaconly forceprefix extendprefix norelease noserverunicast noclientfqdn noacceptreconfig ip6prefix ip6prefixes iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass sendopts delegate zone_dslite zone_map zone_464xlat zone encaplimit_dslite encaplimit_map soltimeout fakeroutes sourcefilter keep_ra_dnslifetime ra_holdoff
- json_get_vars reqaddress reqprefix clientid reqopts defaultreqopts noslaaconly forceprefix extendprefix norelease noserverunicast noclientfqdn noacceptreconfig iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass delegate zone_dslite zone_map zone_464xlat zone encaplimit_dslite encaplimit_map soltimeout fakeroutes sourcefilter keep_ra_dnslifetime ra_holdoff
+ local reqaddress reqprefix clientid reqopts defaultreqopts noslaaconly forceprefix extendprefix norelease noserverunicast noclientfqdn noacceptreconfig ip6prefix ip6prefixes iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass sendopts delegate zone_dslite zone_map zone_464xlat zone encaplimit_dslite encaplimit_map skpriority soltimeout fakeroutes sourcefilter keep_ra_dnslifetime ra_holdoff verbose
+ json_get_vars reqaddress reqprefix clientid reqopts defaultreqopts noslaaconly forceprefix extendprefix norelease noserverunicast noclientfqdn noacceptreconfig iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass delegate zone_dslite zone_map zone_464xlat zone encaplimit_dslite encaplimit_map skpriority soltimeout fakeroutes sourcefilter keep_ra_dnslifetime ra_holdoff verbose
json_for_each_item proto_dhcpv6_add_prefix ip6prefix ip6prefixes
# Configure
@@ -88,8 +90,12 @@ proto_dhcpv6_setup() {
[ "$keep_ra_dnslifetime" = "1" ] && append opts "-L"
+ [ -n "$skpriority" ] && append opts "-K$skpriority"
+
[ -n "$ra_holdoff" ] && append opts "-m$ra_holdoff"
+ [ "$verbose" = "1" ] && append opts "-v"
+
local opt
for opt in $reqopts; do
append opts "-r$opt"
@@ -105,6 +111,7 @@ proto_dhcpv6_setup() {
[ -n "$iface_464xlat" ] && proto_export "IFACE_464XLAT=$iface_464xlat"
[ "$delegate" = "0" ] && proto_export "IFACE_DSLITE_DELEGATE=0"
[ "$delegate" = "0" ] && proto_export "IFACE_MAP_DELEGATE=0"
+ [ "$delegate" = "0" ] && proto_export "IFACE_464XLAT_DELEGATE=0"
[ -n "$zone_dslite" ] && proto_export "ZONE_DSLITE=$zone_dslite"
[ -n "$zone_map" ] && proto_export "ZONE_MAP=$zone_map"
[ -n "$zone_464xlat" ] && proto_export "ZONE_464XLAT=$zone_464xlat"
diff --git a/package/network/ipv6/thc-ipv6/Makefile b/package/network/ipv6/thc-ipv6/Makefile
index 91bacf625e3..b26b0507fb7 100644
--- a/package/network/ipv6/thc-ipv6/Makefile
+++ b/package/network/ipv6/thc-ipv6/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=thc-ipv6
-PKG_VERSION:=2.7
+PKG_VERSION:=3.8
PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GITHUB/vanhauser-thc/THC-Archive/master/Tools
-PKG_HASH:=440a3ae98b57100c397ec4f8634468dbbb0c3b48788c6b74af2a597a90544a96
+PKG_HASH:=b60be61a8b0a944a66e3b719704b4c03c1bc2c22f32d5d21e99e434c82a9d769
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
@@ -31,7 +31,7 @@ THC_APPLETS := \
fuzz_dhcps6 implementation6 implementation6d inverse_lookup6 \
kill_router6 ndpexhaust6 node_query6 parasite6 passive_discovery6 \
randicmp6 redir6 rsmurf6 sendpees6 sendpeesmp6 smurf6 thcping6 \
- toobig6 trace6
+ toobig6 trace6 toobigsniff6 flood_unreach6 connect6
THC_DEPENDS_dnsdict6 := +libpthread
THC_DEPENDS_thcping6 := +librt
diff --git a/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch b/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch
index 1ef1f66be88..118c2a705bc 100644
--- a/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch
+++ b/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch
@@ -1,9 +1,10 @@
--- a/Makefile
+++ b/Makefile
-@@ -1,5 +1,5 @@
+@@ -1,6 +1,6 @@
# Comment out if openssl-dev is not present
+ # of if you want to compile statc
-HAVE_SSL=yes
+#HAVE_SSL=yes
- CC=gcc
- #CFLAGS=-g
+ # comment in if you want to compile static tools
+ #STATIC=-static
diff --git a/package/network/ipv6/thc-ipv6/patches/000-cflags_override.patch b/package/network/ipv6/thc-ipv6/patches/101-remove-march-native.patch
index e1c36b6c6cd..da6c7caa7cb 100644
--- a/package/network/ipv6/thc-ipv6/patches/000-cflags_override.patch
+++ b/package/network/ipv6/thc-ipv6/patches/101-remove-march-native.patch
@@ -1,12 +1,11 @@
-diff -urN thc-ipv6-2.7/Makefile thc-ipv6-2.7.new/Makefile
---- thc-ipv6-2.7/Makefile 2014-12-27 05:05:30.000000000 -0800
-+++ thc-ipv6-2.7.new/Makefile 2017-02-04 20:55:51.679898101 -0800
-@@ -3,7 +3,7 @@
+--- a/Makefile
++++ b/Makefile
+@@ -7,7 +7,7 @@ HAVE_SSL=yes
- CC=gcc
+ #CC=gcc
#CFLAGS=-g
--CFLAGS=-O2
-+CFLAGS?=-O2
+-CFLAGS+=-g -O3 -march=native -flto -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks
++CFLAGS+=-g -O3 -flto -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks
CFLAGS+=$(if $(HAVE_SSL),-D_HAVE_SSL,)
LDFLAGS+=-lpcap $(if $(HAVE_SSL),-lssl -lcrypto,)
- PROGRAMS=parasite6 dos-new-ip6 detect-new-ip6 fake_router6 fake_advertise6 fake_solicitate6 fake_mld6 fake_mld26 fake_mldrouter6 flood_mldrouter6 fake_mipv6 redir6 smurf6 alive6 toobig6 rsmurf6 implementation6 implementation6d sendpees6 sendpeesmp6 randicmp6 fuzz_ip6 flood_mld6 flood_mld26 flood_router6 flood_advertise6 flood_solicitate6 trace6 exploit6 denial6 fake_dhcps6 flood_dhcpc6 fake_dns6d fragmentation6 kill_router6 fake_dnsupdate6 ndpexhaust6 detect_sniffer6 dump_router6 fake_router26 flood_router26 passive_discovery6 dnsrevenum6 inverse_lookup6 node_query6 address6 covert_send6 covert_send6d inject_alive6 firewall6 ndpexhaust26 fake_pim6 thcsyn6 redirsniff6 flood_redir6 four2six dump_dhcp6 fuzz_dhcps6 flood_rs6 fuzz_dhcpc6
+ PROGRAMS=parasite6 dos-new-ip6 detect-new-ip6 fake_router6 fake_advertise6 fake_solicitate6 fake_mld6 fake_mld26 fake_mldrouter6 flood_mldrouter6 fake_mipv6 redir6 smurf6 alive6 toobig6 rsmurf6 implementation6 implementation6d sendpees6 sendpeesmp6 randicmp6 fuzz_ip6 flood_mld6 flood_mld26 flood_router6 flood_advertise6 flood_solicitate6 trace6 exploit6 denial6 fake_dhcps6 flood_dhcpc6 fake_dns6d fragmentation6 kill_router6 fake_dnsupdate6 ndpexhaust6 detect_sniffer6 dump_router6 fake_router26 flood_router26 passive_discovery6 dnsrevenum6 inverse_lookup6 node_query6 address6 covert_send6 covert_send6d inject_alive6 firewall6 ndpexhaust26 fake_pim6 thcsyn6 redirsniff6 flood_redir6 four2six dump_dhcp6 flood_rs6 fuzz_dhcps6 fuzz_dhcpc6 toobigsniff6 flood_unreach6 connect6
diff --git a/package/network/services/bridger/Makefile b/package/network/services/bridger/Makefile
new file mode 100644
index 00000000000..e228de517dc
--- /dev/null
+++ b/package/network/services/bridger/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2022 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bridger
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=https://github.com/nbd168/bridger
+PKG_SOURCE_DATE:=2023-05-12
+PKG_SOURCE_VERSION:=d0f79a16c749ad310d79e1c31f593860619f99eb
+PKG_MIRROR_HASH:=bee35594767cbcd13764f5c95e4837a4fc73171a91fcdae73aaefe00f4e8f8fa
+
+PKG_LICENSE:=GPL-2.0
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_DEPENDS:=bpf-headers
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+include $(INCLUDE_DIR)/bpf.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/bridger
+ SECTION:=utils
+ CATEGORY:=Base system
+ TITLE:=Bridge forwarding accelerator
+ DEPENDS:=+libbpf +libubox +libubus +libnl-tiny +kmod-sched-core +kmod-sched-flower +kmod-sched-bpf +kmod-sched-act-vlan $(BPF_DEPENDS)
+endef
+
+TARGET_CFLAGS += \
+ -I$(STAGING_DIR)/usr/include/libnl-tiny \
+ -I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS += \
+ -DLIBNL_LIBS=-lnl-tiny
+
+define Build/Compile
+ $(call CompileBPF,$(PKG_BUILD_DIR)/bridger-bpf.c)
+ $(Build/Compile/Default)
+endef
+
+define Package/bridger/install
+ $(INSTALL_DIR) \
+ $(1)/etc/config \
+ $(1)/etc/init.d \
+ $(1)/lib/bpf \
+ $(1)/usr/sbin
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/bridger-bpf.o $(1)/lib/bpf
+ $(INSTALL_BIN) \
+ $(PKG_INSTALL_DIR)/usr/bin/bridger \
+ $(1)/usr/sbin/
+ $(INSTALL_DATA) ./files/bridger.conf $(1)/etc/config/bridger
+ $(INSTALL_BIN) ./files/bridger.init $(1)/etc/init.d/bridger
+endef
+
+$(eval $(call BuildPackage,bridger))
diff --git a/package/network/services/bridger/files/bridger.conf b/package/network/services/bridger/files/bridger.conf
new file mode 100644
index 00000000000..cb43deff795
--- /dev/null
+++ b/package/network/services/bridger/files/bridger.conf
@@ -0,0 +1,3 @@
+config defaults
+ # example for blacklisting individual devices or bridges
+ # list blacklist eth0
diff --git a/package/network/services/bridger/files/bridger.init b/package/network/services/bridger/files/bridger.init
new file mode 100644
index 00000000000..2ba9f06b65e
--- /dev/null
+++ b/package/network/services/bridger/files/bridger.init
@@ -0,0 +1,44 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2021 OpenWrt.org
+
+START=19
+
+USE_PROCD=1
+PROG=/usr/sbin/bridger
+
+add_blacklist() {
+ cfg="$1"
+
+ config_get blacklist "$cfg" blacklist
+ for i in $blacklist; do
+ json_add_string "" "$i"
+ done
+}
+
+reload_service() {
+ config_load bridger
+
+ json_init
+ json_add_string name "config"
+ json_add_array devices
+ config_foreach add_blacklist defaults
+ json_close_array
+
+ ubus call bridger set_blacklist "$(json_dump)"
+}
+
+service_triggers() {
+ procd_add_reload_trigger bridger
+}
+
+start_service() {
+ procd_open_instance
+ procd_set_param command "$PROG"
+ procd_set_param respawn
+ procd_close_instance
+}
+
+service_started() {
+ ubus -t 10 wait_for bridger
+ [ $? = 0 ] && reload_service
+}
diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
index 90a81b5f656..241f3463e2f 100644
--- a/package/network/services/dnsmasq/Makefile
+++ b/package/network/services/dnsmasq/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq
-PKG_UPSTREAM_VERSION:=2.85
+PKG_UPSTREAM_VERSION:=2.89
PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION)))
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=7
PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz
-PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
-PKG_HASH:=ad98d3803df687e5b938080f3d25c628fe41c878752d03fbc6199787fee312fa
+PKG_SOURCE_URL:=https://thekelleys.org.uk/dnsmasq/
+PKG_HASH:=02bd230346cf0b9d5909f5e151df168b2707103785eb616b56685855adebb609
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
@@ -24,12 +24,14 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_UPSTR
PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
+PKG_BUILD_FLAGS:=lto
PKG_ASLR_PIE_REGULAR:=1
PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6 \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset \
+ CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_nftset \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc \
@@ -61,10 +63,11 @@ endef
define Package/dnsmasq-full
$(call Package/dnsmasq/Default)
- TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Conntrack, NO_ID enabled by default)
+ TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Nftset, Conntrack, NO_ID enabled by default)
DEPENDS+=+PACKAGE_dnsmasq_full_dnssec:libnettle \
+PACKAGE_dnsmasq_full_ipset:kmod-ipt-ipset \
- +PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack
+ +PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack \
+ +PACKAGE_dnsmasq_full_nftset:nftables-json
VARIANT:=full
PROVIDES:=dnsmasq
endef
@@ -83,7 +86,7 @@ define Package/dnsmasq-full/description
$(call Package/dnsmasq/description)
This is a fully configurable variant with DHCPv4, DHCPv6, DNSSEC, Authoritative DNS
-and IPset, Conntrack support & NO_ID enabled by default.
+and nftset, Conntrack support & NO_ID enabled by default.
endef
define Package/dnsmasq/conffiles
@@ -109,6 +112,9 @@ define Package/dnsmasq-full/config
default y
config PACKAGE_dnsmasq_full_ipset
bool "Build with IPset support."
+ default n
+ config PACKAGE_dnsmasq_full_nftset
+ bool "Build with Nftset support."
default y
config PACKAGE_dnsmasq_full_conntrack
bool "Build with Conntrack support."
@@ -128,9 +134,6 @@ endef
Package/dnsmasq-dhcpv6/conffiles = $(Package/dnsmasq/conffiles)
Package/dnsmasq-full/conffiles = $(Package/dnsmasq/conffiles)
-TARGET_CFLAGS += -flto
-TARGET_LDFLAGS += -flto=jobserver
-
COPTS = -DHAVE_UBUS -DHAVE_POLL_H \
$(if $(CONFIG_IPV6),,-DNO_IPV6)
@@ -144,6 +147,7 @@ ifeq ($(BUILD_VARIANT),full)
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec),-DHAVE_DNSSEC) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth),,-DNO_AUTH) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset),,-DNO_IPSET) \
+ $(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_nftset),-DHAVE_NFTSET,) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack),-DHAVE_CONNTRACK,) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid),-DNO_ID,) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc),-DHAVE_BROKEN_RTC) \
@@ -182,6 +186,7 @@ define Package/dnsmasq/install
$(INSTALL_DATA) ./files/dnsmasq_acl.json $(1)/usr/share/acl.d/
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/50-dnsmasq-migrate-resolv-conf-auto.sh $(1)/etc/uci-defaults
+ $(INSTALL_BIN) ./files/50-dnsmasq-migrate-ipset.sh $(1)/etc/uci-defaults
endef
Package/dnsmasq-dhcpv6/install = $(Package/dnsmasq/install)
diff --git a/package/network/services/dnsmasq/files/50-dnsmasq-migrate-ipset.sh b/package/network/services/dnsmasq/files/50-dnsmasq-migrate-ipset.sh
new file mode 100755
index 00000000000..aba73e7dd48
--- /dev/null
+++ b/package/network/services/dnsmasq/files/50-dnsmasq-migrate-ipset.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+ipsets=$(uci -q get dhcp.@dnsmasq[0].ipset)
+[ -z "$ipsets" ] && exit 0
+
+for ipset in $ipsets; do
+ names=${ipset##*/}
+ domains=${ipset%/*}
+
+ [ -z "$names" ] || [ -z "$domains" ] && continue
+
+ uci add dhcp ipset
+
+ OLDIFS="$IFS"
+
+ IFS=","
+ for name in $names; do
+ uci add_list dhcp.@ipset[-1].name="$name"
+ done
+
+ IFS="/"
+ for domain in ${domains:1}; do
+ uci add_list dhcp.@ipset[-1].domain="$domain"
+ done
+
+ IFS="$OLDIFS"
+
+ uci del_list dhcp.@dnsmasq[0].ipset="$ipset"
+done
+
+uci commit dhcp
+exit 0
diff --git a/package/network/services/dnsmasq/files/dhcp.conf b/package/network/services/dnsmasq/files/dhcp.conf
index 8c42ef782e3..d5b9dfa018c 100644
--- a/package/network/services/dnsmasq/files/dhcp.conf
+++ b/package/network/services/dnsmasq/files/dhcp.conf
@@ -10,6 +10,7 @@ config dnsmasq
option domain 'lan'
option expandhosts 1
option nonegcache 0
+ option cachesize 1000
option authoritative 1
option readethers 1
option leasefile '/tmp/dhcp.leases'
@@ -21,6 +22,9 @@ config dnsmasq
#list bogusnxdomain '64.94.110.11'
option localservice 1 # disable to allow DNS requests from non-local subnets
option ednspacket_max 1232
+ option filter_aaaa 0
+ option filter_a 0
+ #list addnmount /some/path # read-only mount path to expose it to dnsmasq
config dhcp lan
option interface lan
diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init
index d5f70a0ee51..510d328cd23 100644..100755
--- a/package/network/services/dnsmasq/files/dnsmasq.init
+++ b/package/network/services/dnsmasq/files/dnsmasq.init
@@ -19,6 +19,7 @@ BASEDHCPSTAMPFILE="/var/run/dnsmasq"
DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf"
RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf"
DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh"
+DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus"
DNSMASQ_DHCP_VER=4
@@ -32,6 +33,7 @@ dnsmasq_ignore_opt() {
[ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1
[ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1
[ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1
+ [ "${dnsmasq_features#* nftset }" = "$dnsmasq_features" ] || dnsmasq_has_nftset=1
fi
case "$opt" in
@@ -54,6 +56,8 @@ dnsmasq_ignore_opt() {
[ -z "$dnsmasq_has_tftp" ] ;;
ipset)
[ -z "$dnsmasq_has_ipset" ] ;;
+ nftset)
+ [ -z "$dnsmasq_has_nftset" ] ;;
*)
return 1
esac
@@ -168,8 +172,8 @@ append_address() {
xappend "--address=$1"
}
-append_ipset() {
- xappend "--ipset=$1"
+append_connmark_allowlist() {
+ xappend "--connmark-allowlist=$1"
}
append_interface() {
@@ -186,7 +190,26 @@ append_notinterface() {
xappend "--except-interface=$ifname"
}
+ismounted() {
+ local filename="$1"
+ local dirname
+ for dirname in $EXTRA_MOUNT ; do
+ case "$filename" in
+ "${dirname}/"* | "${dirname}" )
+ return 0
+ ;;
+ esac
+ done
+
+ return 1
+}
+
+append_extramount() {
+ ismounted "$1" || append EXTRA_MOUNT "$1"
+}
+
append_addnhosts() {
+ append_extramount "$1"
xappend "--addn-hosts=$1"
}
@@ -221,7 +244,7 @@ dhcp_subscrid_add() {
config_get subscriberid "$cfg" subscriberid
[ -n "$subscriberid" ] || return 0
- xappend "--dhcp-subscrid=$networkid,$subscriberid"
+ xappend "--dhcp-subscrid=set:$networkid,$subscriberid"
config_get_bool force "$cfg" force 0
@@ -237,7 +260,7 @@ dhcp_remoteid_add() {
config_get remoteid "$cfg" remoteid
[ -n "$remoteid" ] || return 0
- xappend "--dhcp-remoteid=$networkid,$remoteid"
+ xappend "--dhcp-remoteid=set:$networkid,$remoteid"
config_get_bool force "$cfg" force 0
@@ -254,7 +277,7 @@ dhcp_circuitid_add() {
config_get circuitid "$cfg" circuitid
[ -n "$circuitid" ] || return 0
- xappend "--dhcp-circuitid=$networkid,$circuitid"
+ xappend "--dhcp-circuitid=set:$networkid,$circuitid"
config_get_bool force "$cfg" force 0
@@ -270,7 +293,7 @@ dhcp_userclass_add() {
config_get userclass "$cfg" userclass
[ -n "$userclass" ] || return 0
- xappend "--dhcp-userclass=$networkid,$userclass"
+ xappend "--dhcp-userclass=set:$networkid,$userclass"
config_get_bool force "$cfg" force 0
@@ -287,7 +310,7 @@ dhcp_vendorclass_add() {
config_get vendorclass "$cfg" vendorclass
[ -n "$vendorclass" ] || return 0
- xappend "--dhcp-vendorclass=$networkid,$vendorclass"
+ xappend "--dhcp-vendorclass=set:$networkid,$vendorclass"
config_get_bool force "$cfg" force 0
@@ -303,7 +326,7 @@ dhcp_match_add() {
config_get match "$cfg" match
[ -n "$match" ] || return 0
- xappend "--dhcp-match=$networkid,$match"
+ xappend "--dhcp-match=set:$networkid,$match"
config_get_bool force "$cfg" force 0
@@ -312,7 +335,7 @@ dhcp_match_add() {
dhcp_host_add() {
local cfg="$1"
- local hosttag nametime addrs duids macs tags
+ local hosttag nametime addrs duids macs tags mtags
config_get_bool force "$cfg" force 0
@@ -337,6 +360,11 @@ dhcp_host_add() {
config_get duid "$cfg" duid
config_get tag "$cfg" tag
+ add_tag() {
+ mtags="${mtags}tag:$1,"
+ }
+ config_list_foreach "$cfg" match_tag add_tag
+
if [ -n "$mac" ]; then
# --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap
# many MAC are possible to track a laptop ON/OFF dock
@@ -374,9 +402,9 @@ dhcp_host_add() {
if [ $DNSMASQ_DHCP_VER -eq 6 ]; then
addrs="${ip:+,$ip}${hostid:+,[::$hostid]}"
- xappend "--dhcp-host=$macs${duids:+,$duids}$hosttag$addrs$nametime"
+ xappend "--dhcp-host=$mtags$macs${duids:+,$duids}$hosttag$addrs$nametime"
else
- xappend "--dhcp-host=$macs$hosttag${ip:+,$ip}$nametime"
+ xappend "--dhcp-host=$mtags$macs$hosttag${ip:+,$ip}$nametime"
fi
}
@@ -481,7 +509,6 @@ dhcp_boot_add() {
dhcp_option_add "$cfg" "$networkid" "$force"
}
-
dhcp_add() {
local cfg="$1"
local dhcp6range="::"
@@ -512,8 +539,13 @@ dhcp_add() {
# Do not support non-static interfaces for now
[ static = "$proto" ] || return 0
+ ipaddr="${subnet%%/*}"
+ prefix_or_netmask="${subnet##*/}"
+
# Override interface netmask with dhcp config if applicable
- config_get netmask "$cfg" netmask "${subnet##*/}"
+ config_get netmask "$cfg" netmask
+
+ [ -n "$netmask" ] && prefix_or_netmask="$netmask"
#check for an already active dhcp server on the interface, unless 'force' is set
config_get_bool force "$cfg" force 0
@@ -529,6 +561,8 @@ dhcp_add() {
config_get leasetime "$cfg" leasetime 12h
config_get options "$cfg" options
config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1
+ config_get_bool dynamicdhcpv4 "$cfg" dynamicdhcpv4 $dynamicdhcp
+ config_get_bool dynamicdhcpv6 "$cfg" dynamicdhcpv6 $dynamicdhcp
config_get dhcpv4 "$cfg" dhcpv4
config_get dhcpv6 "$cfg" dhcpv6
@@ -537,6 +571,7 @@ dhcp_add() {
config_get ra_management "$cfg" ra_management
config_get ra_preference "$cfg" ra_preference
config_get dns "$cfg" dns
+ config_get dns_sl "$cfg" domain
config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname"
@@ -552,25 +587,20 @@ dhcp_add() {
nettag="${networkid:+set:${networkid},}"
- if [ "$limit" -gt 0 ] ; then
- limit=$((limit-1))
- fi
+ # make sure the DHCP range is not empty
+ if [ "$dhcpv4" != "disabled" ] && ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" ; then
+ [ "$dynamicdhcpv4" = "0" ] && END="static"
- eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)"
+ xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
+ fi
- if [ "$dynamicdhcp" = "0" ] ; then
- END="static"
+ if [ "$dynamicdhcpv6" = "0" ] ; then
dhcp6range="::,static"
else
dhcp6range="::1000,::ffff"
fi
- if [ "$dhcpv4" != "disabled" ] ; then
- xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
- fi
-
-
if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ "$ra" = "server" ] ; then
# Note: dnsmasq cannot just be a DHCPv6 server (all-in-1)
# and let some other machine(s) send RA pointing to it.
@@ -621,6 +651,13 @@ dhcp_add() {
fi
dhcp_option_append "option6:dns-server,$dnss" "$networkid"
+
+ if [ -n "$dns_sl" ]; then
+ ddssl=""
+ for dd in $dns_sl; do append ddssl "$dd" ","; done
+ fi
+
+ dhcp_option_append "option6:domain-search,$ddssl" "$networkid"
fi
dhcp_option_add "$cfg" "$networkid" 0
@@ -771,49 +808,81 @@ dhcp_relay_add() {
dnsmasq_ipset_add() {
local cfg="$1"
- local ipsets domains
+ local ipsets nftsets domains
add_ipset() {
ipsets="${ipsets:+$ipsets,}$1"
}
+ add_nftset() {
+ local IFS=,
+ for set in $1; do
+ local fam="$family"
+ [ -n "$fam" ] || fam=$(echo "$set" | sed -nre \
+ 's#^.*[^0-9]([46])$|^.*[-_]([46])[-_].*$|^([46])[^0-9].*$#\1\2\3#p')
+ [ -n "$fam" ] || \
+ fam=$(nft -t list set "$table_family" "$table" "$set" 2>&1 | sed -nre \
+ 's#^\t\ttype .*\bipv([46])_addr\b.*$#\1#p')
+
+ [ -n "$fam" ] || \
+ logger -t dnsmasq "Cannot infer address family from non-existent nftables set '$set'"
+
+ nftsets="${nftsets:+$nftsets,}${fam:+$fam#}$table_family#$table#$set"
+ done
+ }
+
add_domain() {
# leading '/' is expected
domains="$domains/$1"
}
+ config_get table "$cfg" table 'fw4'
+ config_get table_family "$cfg" table_family 'inet'
+ if [ "$table_family" = "ip" ] ; then
+ family="4"
+ elif [ "$table_family" = "ip6" ] ; then
+ family="6"
+ else
+ config_get family "$cfg" family
+ fi
+
config_list_foreach "$cfg" "name" add_ipset
+ config_list_foreach "$cfg" "name" add_nftset
config_list_foreach "$cfg" "domain" add_domain
- if [ -z "$ipsets" ] || [ -z "$domains" ]; then
+ if [ -z "$ipsets" ] || [ -z "$nftsets" ] || [ -z "$domains" ]; then
return 0
fi
xappend "--ipset=$domains/$ipsets"
+ xappend "--nftset=$domains/$nftsets"
}
dnsmasq_start()
{
local cfg="$1"
- local disabled user_dhcpscript
- local resolvfile resolvdir localuse=0
+ local disabled user_dhcpscript logfacility
+ local resolvfile resolvdir localuse=1
config_get_bool disabled "$cfg" disabled 0
[ "$disabled" -gt 0 ] && return 0
- # reset list of DOMAINS and DNS servers (for each dnsmasq instance)
+ # reset list of DOMAINS, DNS servers and EXTRA mounts (for each dnsmasq instance)
DNS_SERVERS=""
DOMAIN=""
+ EXTRA_MOUNT=""
CONFIGFILE="${BASECONFIGFILE}.${cfg}"
CONFIGFILE_TMP="${CONFIGFILE}.$$"
HOSTFILE="${BASEHOSTFILE}.${cfg}"
HOSTFILE_TMP="${HOSTFILE}.$$"
+ HOSTFILE_DIR="$(dirname "$HOSTFILE")"
BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}"
# before we can call xappend
+ umask u=rwx,g=rx,o=rx
mkdir -p /var/run/dnsmasq/
mkdir -p $(dirname $CONFIGFILE)
- mkdir -p $(dirname $HOSTFILE)
+ mkdir -p "$HOSTFILE_DIR"
mkdir -p /var/lib/misc
chown dnsmasq:dnsmasq /var/run/dnsmasq
@@ -904,8 +973,11 @@ dnsmasq_start()
append_bool "$cfg" rapidcommit "--dhcp-rapid-commit"
append_bool "$cfg" scriptarp "--script-arp"
- append_parm "$cfg" logfacility "--log-facility"
+ append_bool "$cfg" filter_aaaa "--filter-AAAA"
+ append_bool "$cfg" filter_a "--filter-A"
+ append_parm "$cfg" logfacility "--log-facility"
+ config_get logfacility "$cfg" "logfacility"
append_parm "$cfg" cachesize "--cache-size"
append_parm "$cfg" dnsforwardmax "--dns-forward-max"
append_parm "$cfg" port "--port"
@@ -920,15 +992,37 @@ dnsmasq_start()
config_list_foreach "$cfg" "server" append_server
config_list_foreach "$cfg" "rev_server" append_rev_server
config_list_foreach "$cfg" "address" append_address
- config_list_foreach "$cfg" "ipset" append_ipset
+
+ local connmark_allowlist_enable
+ config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0
+ [ "$connmark_allowlist_enable" -gt 0 ] && {
+ append_parm "$cfg" "connmark_allowlist_enable" "--connmark-allowlist-enable"
+ config_list_foreach "$cfg" "connmark_allowlist" append_connmark_allowlist
+ }
+
[ -n "$BOOT" ] || {
config_list_foreach "$cfg" "interface" append_interface
config_list_foreach "$cfg" "notinterface" append_notinterface
}
+ config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0
+ if [ "$ignore_hosts_dir" = "1" ]; then
+ xappend "--addn-hosts=$HOSTFILE"
+ append EXTRA_MOUNT "$HOSTFILE"
+ else
+ xappend "--addn-hosts=$HOSTFILE_DIR"
+ append EXTRA_MOUNT "$HOSTFILE_DIR"
+ fi
config_list_foreach "$cfg" "addnhosts" append_addnhosts
config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain
append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases"
- append_parm "$cfg" "serversfile" "--servers-file"
+
+ local serversfile
+ config_get serversfile "$cfg" "serversfile"
+ [ -n "$serversfile" ] && {
+ xappend "--servers-file=$serversfile"
+ append EXTRA_MOUNT "$serversfile"
+ }
+
append_parm "$cfg" "tftp_root" "--tftp-root"
append_parm "$cfg" "dhcp_boot" "--dhcp-boot"
append_parm "$cfg" "local_ttl" "--local-ttl"
@@ -965,7 +1059,7 @@ dnsmasq_start()
config_get resolvfile "$cfg" resolvfile /tmp/resolv.conf.d/resolv.conf.auto
[ -n "$resolvfile" ] && [ ! -e "$resolvfile" ] && touch "$resolvfile"
xappend "--resolv-file=$resolvfile"
- [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1
+ [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0
resolvdir="$(dirname "$resolvfile")"
fi
config_get_bool localuse "$cfg" localuse "$localuse"
@@ -1020,12 +1114,6 @@ dnsmasq_start()
xappend "--dhcp-broadcast=tag:needs-broadcast"
- config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0
- if [ "$ignore_hosts_dir" = "1" ]; then
- xappend "--addn-hosts=$HOSTFILE"
- else
- xappend "--addn-hosts=$(dirname $HOSTFILE)"
- fi
config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d"
xappend "--conf-dir=$dnsmasqconfdir"
@@ -1096,7 +1184,6 @@ dnsmasq_start()
config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg"
echo >> $CONFIGFILE_TMP
- echo >> $CONFIGFILE_TMP
mv -f $CONFIGFILE_TMP $CONFIGFILE
mv -f $HOSTFILE_TMP $HOSTFILE
@@ -1112,15 +1199,30 @@ dnsmasq_start()
done
}
+ config_list_foreach "$cfg" addnmount append_extramount
+
procd_open_instance $cfg
procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid
procd_set_param file $CONFIGFILE
[ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript"
procd_set_param respawn
+ local instance_ifc instance_netdev
+ config_get instance_ifc "$cfg" interface
+ [ -n "$instance_ifc" ] && network_get_device instance_netdev "$instance_ifc" &&
+ [ -n "$instance_netdev" ] && procd_set_param netdev $instance_netdev
+
procd_add_jail dnsmasq ubus log
- procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE $RFC6761FILE $DHCPBOGUSHOSTNAMEFILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript /etc/hosts /etc/ethers /sbin/hotplug-call $EXTRA_MOUNT $DHCPSCRIPT /tmp/hosts/
+ procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS
+ procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE
+ procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript
+ procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers
procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
+ case "$logfacility" in */*)
+ [ ! -e "$logfacility" ] && touch "$logfacility"
+ procd_add_jail_mount_rw "$logfacility"
+ esac
+ [ -e "$hostsfile" ] && procd_add_jail_mount $hostsfile
procd_close_instance
}
@@ -1128,12 +1230,12 @@ dnsmasq_start()
dnsmasq_stop()
{
local cfg="$1"
- local noresolv resolvfile localuse=0
+ local noresolv resolvfile localuse=1
config_get_bool noresolv "$cfg" noresolv 0
config_get resolvfile "$cfg" "resolvfile"
- [ "$noresolv" = 0 ] && [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1
+ [ "$noresolv" = 0 ] && [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0
config_get_bool localuse "$cfg" localuse "$localuse"
[ "$localuse" -gt 0 ] && ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf
diff --git a/package/network/services/dnsmasq/files/dnsmasq_acl.json b/package/network/services/dnsmasq/files/dnsmasq_acl.json
index 47d7c293029..67c6c20483c 100644
--- a/package/network/services/dnsmasq/files/dnsmasq_acl.json
+++ b/package/network/services/dnsmasq/files/dnsmasq_acl.json
@@ -7,6 +7,9 @@
},
"hotplug.neigh": {
"methods": [ "call" ]
+ },
+ "hotplug.tftp": {
+ "methods": [ "call" ]
}
}
}
diff --git a/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch b/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch
index b601bce1a95..59b8d02c0e1 100644
--- a/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch
+++ b/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch
@@ -13,7 +13,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
-@@ -95,10 +95,6 @@ int main (int argc, char **argv)
+@@ -103,10 +103,6 @@ int main (int argc, char **argv)
read_opts(argc, argv, compile_opts);
@@ -26,7 +26,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
-@@ -1144,7 +1144,7 @@ extern struct daemon {
+@@ -1248,7 +1248,7 @@ extern struct daemon {
int inotifyfd;
#endif
#if defined(HAVE_LINUX_NETWORK)
@@ -35,7 +35,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
#elif defined(HAVE_BSD_NETWORK)
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
#endif
-@@ -1326,9 +1326,6 @@ int read_write(int fd, unsigned char *pa
+@@ -1453,9 +1453,6 @@ int read_write(int fd, unsigned char *pa
void close_fds(long max_fd, int spare1, int spare2, int spare3);
int wildcard_match(const char* wildcard, const char* match);
int wildcard_matchn(const char* wildcard, const char* match, int num);
@@ -140,7 +140,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno));
--- a/src/util.c
+++ b/src/util.c
-@@ -786,22 +786,3 @@ int wildcard_matchn(const char* wildcard
+@@ -855,22 +855,3 @@ int wildcard_matchn(const char* wildcard
return (!num) || (*wildcard == *match);
}
diff --git a/package/network/services/dnsmasq/patches/200-ubus_dns.patch b/package/network/services/dnsmasq/patches/200-ubus_dns.patch
new file mode 100644
index 00000000000..ccbe70ab9c3
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/200-ubus_dns.patch
@@ -0,0 +1,282 @@
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -1631,14 +1631,26 @@ void emit_dbus_signal(int action, struct
+
+ /* ubus.c */
+ #ifdef HAVE_UBUS
++struct blob_attr;
++typedef void (*ubus_dns_notify_cb)(struct blob_attr *msg, void *priv);
++
+ char *ubus_init(void);
+ void set_ubus_listeners(void);
+ void check_ubus_listeners(void);
++void drop_ubus_listeners(void);
++struct blob_buf *ubus_dns_notify_prepare(void);
++int ubus_dns_notify(const char *type, ubus_dns_notify_cb cb, void *priv);
+ void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
+ # ifdef HAVE_CONNTRACK
+ void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name);
+ void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *pattern, const char *ip, u32 ttl);
+ # endif
++#else
++struct blob_buf;
++static inline struct blob_buf *ubus_dns_notify_prepare(void)
++{
++ return NULL;
++}
+ #endif
+
+ /* ipset.c */
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -13,8 +13,10 @@
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+-
+ #include "dnsmasq.h"
++#ifdef HAVE_UBUS
++#include <libubox/blobmsg.h>
++#endif
+
+ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
+ char *name, int isExtract, int extrabytes)
+@@ -394,9 +396,64 @@ static int private_net6(struct in6_addr
+ ((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
+ }
+
++#ifdef HAVE_UBUS
++static void ubus_dns_doctor_cb(struct blob_attr *msg, void *priv)
++{
++ static const struct blobmsg_policy policy = {
++ .name = "address",
++ .type = BLOBMSG_TYPE_STRING,
++ };
++ struct blob_attr *val;
++ char **dest = priv;
++
++ blobmsg_parse(&policy, 1, &val, blobmsg_data(msg), blobmsg_data_len(msg));
++ if (val)
++ *dest = blobmsg_get_string(val);
++}
++
++static int ubus_dns_doctor(const char *name, int ttl, void *p, int af)
++{
++ struct blob_buf *b;
++ char *addr;
++
++ if (!name)
++ return 0;
++
++ b = ubus_dns_notify_prepare();
++ if (!b)
++ return 0;
++
++ blobmsg_add_string(b, "name", name);
++
++ blobmsg_add_u32(b, "ttl", ttl);
++
++ blobmsg_add_string(b, "type", af == AF_INET6 ? "AAAA" : "A");
++
++ addr = blobmsg_alloc_string_buffer(b, "address", INET6_ADDRSTRLEN);
++ if (!addr)
++ return 0;
++
++ inet_ntop(af, p, addr, INET6_ADDRSTRLEN);
++ blobmsg_add_string_buffer(b);
++
++ addr = NULL;
++ ubus_dns_notify("dns_result", ubus_dns_doctor_cb, &addr);
++
++ if (!addr)
++ return 0;
++
++ return inet_pton(af, addr, p) == 1;
++}
++#else
++static int ubus_dns_doctor(const char *name, int ttl, void *p, int af)
++{
++ return 0;
++}
++#endif
++
+ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, int *doctored)
+ {
+- int i, qtype, qclass, rdlen;
++ int i, qtype, qclass, rdlen, ttl;
+
+ for (i = count; i != 0; i--)
+ {
+@@ -405,7 +462,7 @@ static unsigned char *do_doctor(unsigned
+
+ GETSHORT(qtype, p);
+ GETSHORT(qclass, p);
+- p += 4; /* ttl */
++ GETLONG(ttl, p); /* ttl */
+ GETSHORT(rdlen, p);
+
+ if (qclass == C_IN && qtype == T_A)
+@@ -416,6 +473,9 @@ static unsigned char *do_doctor(unsigned
+ if (!CHECK_LEN(header, p, qlen, INADDRSZ))
+ return 0;
+
++ if (ubus_dns_doctor(daemon->namebuff, ttl, p, AF_INET))
++ *doctored = 1;
++
+ /* alignment */
+ memcpy(&addr, p, INADDRSZ);
+
+@@ -433,13 +493,22 @@ static unsigned char *do_doctor(unsigned
+ addr.s_addr &= ~doctor->mask.s_addr;
+ addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
+ /* Since we munged the data, the server it came from is no longer authoritative */
+- header->hb3 &= ~HB3_AA;
+ *doctored = 1;
+ memcpy(p, &addr, INADDRSZ);
+ break;
+ }
+ }
+-
++ else if (qclass == C_IN && qtype == T_AAAA)
++ {
++ if (!CHECK_LEN(header, p, qlen, IN6ADDRSZ))
++ return 0;
++
++ if (ubus_dns_doctor(daemon->namebuff, ttl, p, AF_INET6))
++ *doctored = 1;
++ }
++
++ if (*doctored)
++ header->hb3 &= ~HB3_AA;
+ if (!ADD_RDLEN(header, p, qlen, rdlen))
+ return 0; /* bad packet */
+ }
+@@ -570,7 +639,7 @@ int extract_addresses(struct dns_header
+ cache_start_insert();
+
+ /* find_soa is needed for dns_doctor side effects, so don't call it lazily if there are any. */
+- if (daemon->doctors || option_bool(OPT_DNSSEC_VALID))
++ if (daemon->doctors || option_bool(OPT_DNSSEC_VALID) || ubus_dns_notify_prepare())
+ {
+ searched_soa = 1;
+ ttl = find_soa(header, qlen, doctored);
+--- a/src/ubus.c
++++ b/src/ubus.c
+@@ -72,6 +72,13 @@ static struct ubus_object ubus_object =
+ .subscribe_cb = ubus_subscribe_cb,
+ };
+
++static struct ubus_object_type ubus_dns_object_type =
++ { .name = "dnsmasq.dns" };
++
++static struct ubus_object ubus_dns_object = {
++ .type = &ubus_dns_object_type,
++};
++
+ static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
+ {
+ (void)ctx;
+@@ -105,13 +112,21 @@ static void ubus_disconnect_cb(struct ub
+ char *ubus_init()
+ {
+ struct ubus_context *ubus = NULL;
++ char *dns_name;
+ int ret = 0;
+
+ if (!(ubus = ubus_connect(NULL)))
+ return NULL;
+
++ dns_name = whine_malloc(strlen(daemon->ubus_name) + 5);
++ sprintf(dns_name, "%s.dns", daemon->ubus_name);
++
+ ubus_object.name = daemon->ubus_name;
++ ubus_dns_object.name = dns_name;
++
+ ret = ubus_add_object(ubus, &ubus_object);
++ if (!ret)
++ ret = ubus_add_object(ubus, &ubus_dns_object);
+ if (ret)
+ {
+ ubus_destroy(ubus);
+@@ -181,6 +196,17 @@ void check_ubus_listeners()
+ } \
+ } while (0)
+
++void drop_ubus_listeners()
++{
++ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
++
++ if (!ubus)
++ return;
++
++ ubus_free(ubus);
++ daemon->ubus = NULL;
++}
++
+ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+@@ -328,6 +354,50 @@ fail:
+ } \
+ } while (0)
+
++struct blob_buf *ubus_dns_notify_prepare(void)
++{
++ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
++
++ if (!ubus || !ubus_dns_object.has_subscribers)
++ return NULL;
++
++ blob_buf_init(&b, 0);
++ return &b;
++}
++
++struct ubus_dns_notify_req {
++ struct ubus_notify_request req;
++ ubus_dns_notify_cb cb;
++ void *priv;
++};
++
++static void dns_notify_cb(struct ubus_notify_request *req, int type, struct blob_attr *msg)
++{
++ struct ubus_dns_notify_req *dreq = container_of(req, struct ubus_dns_notify_req, req);
++
++ dreq->cb(msg, dreq->priv);
++}
++
++int ubus_dns_notify(const char *type, ubus_dns_notify_cb cb, void *priv)
++{
++ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
++ struct ubus_dns_notify_req dreq;
++ int ret;
++
++ if (!ubus || !ubus_dns_object.has_subscribers)
++ return 0;
++
++ ret = ubus_notify_async(ubus, &ubus_dns_object, type, b.head, &dreq.req);
++ if (ret)
++ return ret;
++
++ dreq.req.data_cb = dns_notify_cb;
++ dreq.cb = cb;
++ dreq.priv = priv;
++
++ return ubus_complete_request(ubus, &dreq.req.req, 100);
++}
++
+ void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
+ {
+ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -2003,6 +2003,10 @@ static void check_dns_listeners(time_t n
+ daemon->pipe_to_parent = pipefd[1];
+ }
+
++#ifdef HAVE_UBUS
++ drop_ubus_listeners();
++#endif
++
+ /* start with no upstream connections. */
+ for (s = daemon->servers; s; s = s->next)
+ s->tcpfd = -1;
diff --git a/package/network/services/dropbear/Config.in b/package/network/services/dropbear/Config.in
index 15000eff53e..7ffe7684d4a 100644
--- a/package/network/services/dropbear/Config.in
+++ b/package/network/services/dropbear/Config.in
@@ -12,7 +12,6 @@ config DROPBEAR_CURVE25519
config DROPBEAR_ECC
bool "Elliptic curve cryptography (ECC)"
- default n
help
Enables basic support for elliptic curve cryptography (ECC)
in key exchange and public key authentication.
@@ -25,11 +24,10 @@ config DROPBEAR_ECC
Increases binary size by about 24 kB (MIPS).
- If full ECC support is required, also select DROPBEAR_ECC_FULL.
+ Note: select DROPBEAR_ECC_FULL if full ECC support is required.
config DROPBEAR_ECC_FULL
bool "Elliptic curve cryptography (ECC), full support"
- default n
depends on DROPBEAR_ECC
help
Enables full support for elliptic curve cryptography (ECC)
@@ -67,41 +65,62 @@ config DROPBEAR_CHACHA20POLY1305
Increases binary size by about 4 kB (MIPS).
+config DROPBEAR_U2F
+ bool "U2F/FIDO support"
+ default y
+ help
+ This option itself doesn't enable any support for U2F/FIDO
+ but subordinate options do:
+
+ - DROPBEAR_ECDSA_SK - ecdsa-sk keys support
+ depends on DROPBEAR_ECC ("Elliptic curve cryptography (ECC)")
+ - DROPBEAR_ED25519_SK - ed25519-sk keys support
+ depends on DROPBEAR_ED25519 ("Ed25519 support")
+
+config DROPBEAR_ECDSA_SK
+ bool "ECDSA-SK support"
+ default y
+ depends on DROPBEAR_U2F && DROPBEAR_ECC
+ help
+ This enables the following public key algorithm:
+ sk-ecdsa-sha2-nistp256@openssh.com
+
+config DROPBEAR_ED25519_SK
+ bool "Ed25519-SK support"
+ default y
+ depends on DROPBEAR_U2F && DROPBEAR_ED25519
+ help
+ This enables the following public key algorithm:
+ sk-ssh-ed25519@openssh.com
+
config DROPBEAR_ZLIB
bool "Enable compression"
- default n
help
Enables compression using shared zlib library.
- Increases binary size by about 0.1 kB (MIPS) and requires additional 62 kB (MIPS)
- for a shared zlib library.
+ Increases binary size by about 0.1 kB (MIPS) and requires
+ additional 62 kB (MIPS) for a shared zlib library.
config DROPBEAR_UTMP
bool "Utmp support"
- default n
depends on BUSYBOX_CONFIG_FEATURE_UTMP
help
- This enables dropbear utmp support, the file /var/run/utmp is used to
- track who is currently logged in.
+ This enables dropbear utmp support, the file /var/run/utmp is
+ used to track who is currently logged in.
config DROPBEAR_PUTUTLINE
bool "Pututline support"
- default n
depends on DROPBEAR_UTMP
help
- Dropbear will use pututline() to write the utmp structure into the utmp file.
+ Dropbear will use pututline() to write the utmp structure into
+ the utmp file.
config DROPBEAR_DBCLIENT
bool "Build dropbear with dbclient"
default y
-config DROPBEAR_SCP
- bool "Build dropbear with scp"
- default y
-
config DROPBEAR_ASKPASS
bool "Enable askpass helper support"
- default n
depends on DROPBEAR_DBCLIENT
help
This enables support for ssh-askpass helper in dropbear client
@@ -109,4 +128,70 @@ config DROPBEAR_ASKPASS
Increases binary size by about 0.1 kB (MIPS).
+config DROPBEAR_DBCLIENT_AGENTFORWARD
+ bool "Enable agent forwarding in dbclient [LEGACY/SECURITY]"
+ default y
+ depends on DROPBEAR_DBCLIENT
+ help
+ Increases binary size by about 0.1 kB (MIPS).
+
+ Security notes:
+
+ SSH agent forwarding might cause security issues (locally and
+ on the jump machine).
+
+ Hovewer, it's enabled by default for compatibility with
+ previous OpenWrt/dropbear releases.
+
+ Consider DISABLING this option if you're building own OpenWrt
+ image.
+
+ Also see DROPBEAR_AGENTFORWARD (agent forwarding in dropbear
+ server itself).
+
+config DROPBEAR_SCP
+ bool "Build dropbear with scp"
+ default y
+
+config DROPBEAR_AGENTFORWARD
+ bool "Enable agent forwarding [LEGACY/SECURITY]"
+ default y
+ help
+ Increases binary size by about 0.1 kB (MIPS).
+
+ Security notes:
+
+ SSH agent forwarding might cause security issues (locally and
+ on the jump machine).
+
+ Hovewer, it's enabled by default for compatibility with
+ previous OpenWrt/dropbear releases.
+
+ Consider DISABLING this option if you're building own OpenWrt
+ image.
+
+ Also see DROPBEAR_DBCLIENT_AGENTFORWARD (agent forwarding in
+ dropbear client) if DROPBEAR_DBCLIENT is selected.
+
+config DROPBEAR_MODERN_ONLY
+ bool "Use modern crypto only [BREAKS COMPATIBILITY]"
+ select DROPBEAR_ED25519
+ select DROPBEAR_CURVE25519
+ select DROPBEAR_CHACHA20POLY1305
+ help
+ This option enables:
+ - Chacha20-Poly1305
+ - Curve25519
+ - Ed25519
+ and disables:
+ - AES
+ - RSA
+ - SHA1
+
+ Reduces binary size by about 64 kB (MIPS) from default
+ configuration.
+
+ Consider enabling this option if you're building own OpenWrt
+ image and using modern SSH software everywhere.
+
endmenu
diff --git a/package/network/services/dropbear/Makefile b/package/network/services/dropbear/Makefile
index 77887f39db1..2d7ce75b8d0 100644
--- a/package/network/services/dropbear/Makefile
+++ b/package/network/services/dropbear/Makefile
@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dropbear
-PKG_VERSION:=2020.81
-PKG_RELEASE:=2
+PKG_VERSION:=2022.83
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
- http://matt.ucc.asn.au/dropbear/releases/ \
+ https://matt.ucc.asn.au/dropbear/releases/ \
https://dropbear.nl/mirror/releases/
-PKG_HASH:=48235d10b37775dbda59341ac0c4b239b82ad6318c31568b985730c788aac53b
+PKG_HASH:=bc5a121ffbc94b5171ad5ebe01be42746d50aa797c9549a4639894a16749443b
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
@@ -23,7 +23,7 @@ PKG_CPE_ID:=cpe:/a:matt_johnston:dropbear_ssh_server
PKG_BUILD_PARALLEL:=1
PKG_ASLR_PIE_REGULAR:=1
-PKG_USE_MIPS16:=0
+PKG_BUILD_FLAGS:=no-mips16 gc-sections lto
PKG_FIXUP:=autoreconf
PKG_FLAGS:=nonshared
@@ -31,8 +31,11 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_TARGET_INIT_PATH CONFIG_DROPBEAR_ECC CONFIG_DROPBEAR_ECC_FULL \
CONFIG_DROPBEAR_CURVE25519 CONFIG_DROPBEAR_ZLIB \
CONFIG_DROPBEAR_ED25519 CONFIG_DROPBEAR_CHACHA20POLY1305 \
+ CONFIG_DROPBEAR_U2F CONFIG_DROPBEAR_ECDSA_SK CONFIG_DROPBEAR_ED25519_SK \
CONFIG_DROPBEAR_UTMP CONFIG_DROPBEAR_PUTUTLINE \
- CONFIG_DROPBEAR_DBCLIENT CONFIG_DROPBEAR_SCP CONFIG_DROPBEAR_ASKPASS
+ CONFIG_DROPBEAR_DBCLIENT CONFIG_DROPBEAR_SCP CONFIG_DROPBEAR_ASKPASS \
+ CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD CONFIG_DROPBEAR_AGENTFORWARD \
+ CONFIG_DROPBEAR_MODERN_ONLY
include $(INCLUDE_DIR)/package.mk
@@ -41,7 +44,7 @@ ifneq ($(DUMP),1)
endif
define Package/dropbear/Default
- URL:=http://matt.ucc.asn.au/dropbear/
+ URL:=https://matt.ucc.asn.au/dropbear/
endef
define Package/dropbear/config
@@ -67,10 +70,11 @@ define Package/dropbear/description
endef
define Package/dropbear/conffiles
-$(if $(CONFIG_DROPBEAR_ED25519),/etc/dropbear/dropbear_ed25519_host_key)
-$(if $(CONFIG_DROPBEAR_ECC),/etc/dropbear/dropbear_ecdsa_host_key)
-/etc/dropbear/dropbear_rsa_host_key
/etc/config/dropbear
+/etc/dropbear/authorized_keys
+/etc/dropbear/dropbear_ecdsa_host_key
+/etc/dropbear/dropbear_ed25519_host_key
+/etc/dropbear/dropbear_rsa_host_key
endef
define Package/dropbearconvert
@@ -98,78 +102,100 @@ CONFIGURE_ARGS += \
##############################################################################
#
-# option|value - add option to localoptions.h
-# !!option|value - replace option in sysoptions.h
+# option,value - add option to localoptions.h
+# !!option,value - replace option in sysoptions.h
#
##############################################################################
+# adjust allowed shell list (if getusershell(3) is missing):
+# - COMPAT_USER_SHELLS
# remove protocol idented software version number:
# - LOCAL_IDENT
# disable legacy/unsafe methods and unused functionality:
-# - INETD_MODE
# - DROPBEAR_CLI_NETCAT
# - DROPBEAR_DSS
# - DO_MOTD
+# - DROPBEAR_DH_GROUP14_SHA1
+# - DROPBEAR_SHA1_HMAC
DB_OPT_COMMON = \
- DEFAULT_PATH|"$(TARGET_INIT_PATH)" \
- !!LOCAL_IDENT|"SSH-2.0-dropbear" \
- INETD_MODE|0 \
- DROPBEAR_CLI_NETCAT|0 \
- DROPBEAR_DSS|0 \
- DO_MOTD|0 \
+ !!LOCAL_IDENT,"SSH-2.0-dropbear" \
+ COMPAT_USER_SHELLS,"/bin/ash","/bin/sh" \
+ DEFAULT_PATH,"$(TARGET_INIT_PATH)" \
+ DEFAULT_ROOT_PATH,"$(TARGET_INIT_PATH)" \
+ DROPBEAR_DSS,0 \
+ DROPBEAR_CLI_NETCAT,0 \
+ DO_MOTD,0 \
+ DROPBEAR_DH_GROUP14_SHA1,0 \
+ DROPBEAR_SHA1_HMAC,0 \
##############################################################################
#
-# option|config|enabled|disabled = add option to localoptions.h
-# !!option|config|enabled|disabled = replace option in sysoptions.h
+# option,config,enabled,disabled = add option to localoptions.h
+# !!option,config,enabled,disabled = replace option in sysoptions.h
#
# option := (config) ? enabled : disabled
#
##############################################################################
DB_OPT_CONFIG = \
- DROPBEAR_CURVE25519|CONFIG_DROPBEAR_CURVE25519|1|0 \
- DROPBEAR_ED25519|CONFIG_DROPBEAR_ED25519|1|0 \
- DROPBEAR_CHACHA20POLY1305|CONFIG_DROPBEAR_CHACHA20POLY1305|1|0 \
- DROPBEAR_ECDSA|CONFIG_DROPBEAR_ECC|1|0 \
- DROPBEAR_ECDH|CONFIG_DROPBEAR_ECC|1|0 \
- !!DROPBEAR_ECC_384|CONFIG_DROPBEAR_ECC_FULL|1|0 \
- !!DROPBEAR_ECC_521|CONFIG_DROPBEAR_ECC_FULL|1|0 \
- DROPBEAR_CLI_ASKPASS_HELPER|CONFIG_DROPBEAR_ASKPASS|1|0 \
-
-
-TARGET_CFLAGS += -DARGTYPE=3 -ffunction-sections -fdata-sections -flto
-TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver
+ !!DROPBEAR_ECC_384,CONFIG_DROPBEAR_ECC_FULL,1,0 \
+ !!DROPBEAR_ECC_521,CONFIG_DROPBEAR_ECC_FULL,1,0 \
+ DROPBEAR_CURVE25519,CONFIG_DROPBEAR_CURVE25519,1,0 \
+ DROPBEAR_CHACHA20POLY1305,CONFIG_DROPBEAR_CHACHA20POLY1305,1,0 \
+ DROPBEAR_ED25519,CONFIG_DROPBEAR_ED25519,1,0 \
+ DROPBEAR_ECDSA,CONFIG_DROPBEAR_ECC,1,0 \
+ DROPBEAR_ECDH,CONFIG_DROPBEAR_ECC,1,0 \
+ DROPBEAR_SK_KEYS,CONFIG_DROPBEAR_U2F,1,0 \
+ DROPBEAR_SK_ECDSA,CONFIG_DROPBEAR_ECDSA_SK,1,0 \
+ DROPBEAR_SK_ED25519,CONFIG_DROPBEAR_ED25519_SK,1,0 \
+ DROPBEAR_CLI_ASKPASS_HELPER,CONFIG_DROPBEAR_ASKPASS,1,0 \
+ DROPBEAR_CLI_AGENTFWD,CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD,1,0 \
+ DROPBEAR_SVR_AGENTFWD,CONFIG_DROPBEAR_AGENTFORWARD,1,0 \
+ DROPBEAR_AES128,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_AES256,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_ENABLE_CTR_MODE,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_RSA,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_RSA_SHA1,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+
+
+TARGET_CFLAGS += -DARGTYPE=3
+
+xsedx:=$(shell printf '\027')
db_opt_add =echo '\#define $(1) $(2)' >> $(PKG_BUILD_DIR)/localoptions.h
-db_opt_replace =$(ESED) 's,^(\#define $(1)) .*$$$$,\1 $(2),g' $(PKG_BUILD_DIR)/sysoptions.h
+db_opt_replace =$(ESED) '/^\#define $(1) .*$$$$/{h;:a;$$$$!n;/^\#.+$$$$/bb;/^$$$$/bb;H;ba;:b;x;s$(xsedx)^.+$$$$$(xsedx)\#define $(1) $(2)$(xsedx)p;x};p' -n $(PKG_BUILD_DIR)/sysoptions.h
define Build/Configure/dropbear_headers
$(strip $(foreach s,$(DB_OPT_COMMON), \
- $(if $(filter !!%,$(word 1,$(subst |, ,$(s)))), \
- $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst |, ,$(s)))),$(word 2,$(subst |, ,$(s)))), \
- $(call db_opt_add,$(word 1,$(subst |, ,$(s))),$(word 2,$(subst |, ,$(s)))) \
+ $(if $(filter !!%,$(word 1,$(subst $(comma),$(space),$(s)))), \
+ $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst $(comma),$(space),$(s)))),$(subst $(space),$(comma),$(wordlist 2,$(words $(subst $(comma),$(space),$(s))),$(subst $(comma),$(space),$(s))))), \
+ $(call db_opt_add,$(word 1,$(subst $(comma),$(space),$(s))),$(subst $(space),$(comma),$(wordlist 2,$(words $(subst $(comma),$(space),$(s))),$(subst $(comma),$(space),$(s))))) \
) ; \
))
$(strip $(foreach s,$(DB_OPT_CONFIG), \
- $(if $(filter !!%,$(word 1,$(subst |, ,$(s)))), \
- $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst |, ,$(s)))),$(if $($(word 2,$(subst |, ,$(s)))),$(word 3,$(subst |, ,$(s))),$(word 4,$(subst |, ,$(s))))), \
- $(call db_opt_add,$(word 1,$(subst |, ,$(s))),$(if $($(word 2,$(subst |, ,$(s)))),$(word 3,$(subst |, ,$(s))),$(word 4,$(subst |, ,$(s))))) \
+ $(if $(filter !!%,$(word 1,$(subst $(comma),$(space),$(s)))), \
+ $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst $(comma),$(space),$(s)))),$(if $($(word 2,$(subst $(comma),$(space),$(s)))),$(word 3,$(subst $(comma),$(space),$(s))),$(word 4,$(subst $(comma),$(space),$(s))))), \
+ $(call db_opt_add,$(word 1,$(subst $(comma),$(space),$(s))),$(if $($(word 2,$(subst $(comma),$(space),$(s)))),$(word 3,$(subst $(comma),$(space),$(s))),$(word 4,$(subst $(comma),$(space),$(s))))) \
) ; \
))
endef
-define Build/Configure
- : > $(PKG_BUILD_DIR)/localoptions.h
+define Build/Configure/dropbear_objects
+ grep -ERZl -e '($(subst $(space),|,$(strip $(sort $(patsubst !!%,%,$(foreach s,$(DB_OPT_COMMON) $(DB_OPT_CONFIG),$(word 1,$(subst $(comma),$(space),$(s)))))))))' \
+ $(PKG_BUILD_DIR)/ | sed -zE 's/^(.+)\.[^.]+$$$$/\1.o/' | sort -uV | xargs -0 -r rm -fv || :
+endef
+define Build/Configure
+ rm -f $(PKG_BUILD_DIR)/localoptions.h
$(Build/Configure/Default)
+ : > $(PKG_BUILD_DIR)/localoptions.h
$(Build/Configure/dropbear_headers)
- # Enforce rebuild of svr-chansession.c
- rm -f $(PKG_BUILD_DIR)/svr-chansession.o
+ # Enforce rebuild of files depending on configured options
+ $(Build/Configure/dropbear_objects)
# Rebuild them on config change
+$(MAKE) -C $(PKG_BUILD_DIR)/libtomcrypt clean
@@ -179,10 +205,12 @@ endef
define Build/Compile
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
+ IGNORE_SPEED=1 \
PROGRAMS="dropbear $(if $(CONFIG_DROPBEAR_DBCLIENT),dbclient,) dropbearkey $(if $(CONFIG_DROPBEAR_SCP),scp,)" \
MULTI=1 SCPPROGRESS=1
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
+ IGNORE_SPEED=1 \
PROGRAMS="dropbearconvert"
endef
@@ -200,9 +228,7 @@ define Package/dropbear/install
$(INSTALL_DIR) $(1)/etc/dropbear
$(INSTALL_DIR) $(1)/lib/preinit
$(INSTALL_DATA) ./files/dropbear.failsafe $(1)/lib/preinit/99_10_failsafe_dropbear
- $(if $(CONFIG_DROPBEAR_ED25519),touch $(1)/etc/dropbear/dropbear_ed25519_host_key)
- $(if $(CONFIG_DROPBEAR_ECC),touch $(1)/etc/dropbear/dropbear_ecdsa_host_key)
- touch $(1)/etc/dropbear/dropbear_rsa_host_key
+ $(foreach f,$(filter /etc/dropbear/%,$(Package/dropbear/conffiles)),$(if $(wildcard $(TOPDIR)/files/$(f)),chmod 0600 $(TOPDIR)/files/$(f) || :; ))
endef
define Package/dropbearconvert/install
diff --git a/package/network/services/dropbear/files/dropbear.failsafe b/package/network/services/dropbear/files/dropbear.failsafe
index a98ede459ad..417265babed 100755
--- a/package/network/services/dropbear/files/dropbear.failsafe
+++ b/package/network/services/dropbear/files/dropbear.failsafe
@@ -1,8 +1,61 @@
#!/bin/sh
+_dropbear()
+{
+ /usr/sbin/dropbear "$@" </dev/null >/dev/null 2>&1
+}
+
+_dropbearkey()
+{
+ /usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
+}
+
+_ensurekey()
+{
+ _dropbearkey -y -f "$1" && return
+ rm -f "$1"
+ _dropbearkey -f "$@" || {
+ rm -f "$1"
+ return 1
+ }
+}
+
+ktype_all='ed25519 ecdsa rsa'
+
failsafe_dropbear () {
- dropbearkey -t rsa -s 1024 -f /tmp/dropbear_failsafe_host_key
- dropbear -r /tmp/dropbear_failsafe_host_key <> /dev/null 2>&1
+ local kargs kcount ktype tkey
+
+ kargs=
+ kcount=0
+ for ktype in ${ktype_all} ; do
+ tkey="/tmp/dropbear_failsafe_${ktype}_host_key"
+
+ case "${ktype}" in
+ ed25519) _ensurekey "${tkey}" -t ed25519 ;;
+ ecdsa) _ensurekey "${tkey}" -t ecdsa -s 256 ;;
+ rsa) _ensurekey "${tkey}" -t rsa -s 1024 ;;
+ *)
+ echo "unknown key type: ${ktype}" >&2
+ continue
+ ;;
+ esac
+
+ [ -s "${tkey}" ] || {
+ rm -f "${tkey}"
+ continue
+ }
+
+ chmod 0400 "${tkey}"
+ kargs="${kargs}${kargs:+ }-r ${tkey}"
+ kcount=$((kcount+1))
+ done
+
+ [ "${kcount}" != 0 ] || {
+ echo 'DROPBEAR IS BROKEN' >&2
+ return 1
+ }
+
+ _dropbear ${kargs}
}
boot_hook_add failsafe failsafe_dropbear
diff --git a/package/network/services/dropbear/files/dropbear.init b/package/network/services/dropbear/files/dropbear.init
index ea4cad2a8d5..21570987c43 100755
--- a/package/network/services/dropbear/files/dropbear.init
+++ b/package/network/services/dropbear/files/dropbear.init
@@ -12,28 +12,52 @@ PIDCOUNT=0
extra_command "killclients" "Kill ${NAME} processes except servers and yourself"
+# most of time real_stat() will be failing
+# due to missing "stat" binary (by default)
+real_stat() { env stat -L "$@" 2>/dev/null ; }
+dumb_stat() { ls -Ldln "$1" | tr -s '\t ' ' ' ; }
+stat_perm() { real_stat -c '%A' "$1" || dumb_stat "$1" | cut -d ' ' -f 1 ; }
+stat_owner() { real_stat -c '%u' "$1" || dumb_stat "$1" | cut -d ' ' -f 3 ; }
+
_dropbearkey()
{
- /usr/bin/dropbearkey "$@" 0<&- 1>&- 2>&-
+ /usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
}
-# $1 - host key file name
-hk_verify()
+# $1 - file name (host key or config)
+file_verify()
{
[ -f "$1" ] || return 1
- [ -s "$1" ] || return 2
- _dropbearkey -y -f "$1" || return 3
+ # checking file ownership
+ [ "$(stat_owner "$1")" = "0" ] || {
+ chown 0 "$1"
+ [ "$(stat_owner "$1")" = "0" ] || return 2
+ }
+ # checking file permissions
+ [ "$(stat_perm "$1")" = "-rw-------" ] || {
+ chmod 0600 "$1"
+ [ "$(stat_perm "$1")" = "-rw-------" ] || return 3
+ }
+ # file is host key or not?
+ # if $2 is empty string - file is "host key"
+ # if $2 is non-empty string - file is "config"
+ [ -z "$2" ] || return 0
+ # checking file contents (finally)
+ [ -s "$1" ] || return 4
+ _dropbearkey -y -f "$1" || return 5
return 0
}
-# $1 - hk_verify() return code
-hk_errmsg()
+# $1 - file_verify() return code
+file_errmsg()
{
case "$1" in
0) ;;
1) echo "file does not exist" ;;
- 2) echo "file has zero length" ;;
- 3) echo "file is not valid host key or not supported" ;;
+ 2) echo "file has wrong owner (must be owned by root)" ;;
+ 3) echo "file has wrong permissions (must not have group/other write bit)" ;;
+ 4) echo "file has zero length" ;;
+ 5) echo "file is not valid host key or not supported" ;;
*) echo "unknown error" ;;
esac
}
@@ -43,73 +67,97 @@ hk_errmsg()
hk_config()
{
local x m
- hk_verify "$2"; x=$?
- case "$x" in
- 0) procd_append_param command -r "$2"
- ;;
- *) m=$(hk_errmsg "$x")
- logger -t "${NAME}" -p daemon.warn \
- "option '$1', value '$2': $m, skipping"
- ;;
- esac
+ file_verify "$2" ; x=$?
+ if [ "$x" = 0 ] ; then
+ procd_append_param command -r "$2"
+ return
+ fi
+ m=$(file_errmsg "$x")
+ logger -s -t "${NAME}" -p daemon.warn \
+ "Option '$1', skipping '$2': $m"
}
# $1 - host key file name
-hk_config__keyfile()
-{
- hk_config 'keyfile' "$1"
-}
+hk_config__keyfile() { hk_config keyfile "$1" ; }
+
+ktype_all='ed25519 ecdsa rsa'
hk_generate_as_needed()
{
- local kdir kgen ktype tdir kcount tfile
- kdir='/etc/dropbear'
+ local hk_cfg_dir kgen ktype kfile hk_tmp_dir
+ hk_cfg_dir='/etc/dropbear'
+
+ [ -d "${hk_cfg_dir}" ] || mkdir -p "${hk_cfg_dir}"
+
+ kgen=
+ for ktype in ${ktype_all} ; do
+ kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
- kgen=''
- for ktype in ed25519 ecdsa rsa; do
- hk_verify "${kdir}/dropbear_${ktype}_host_key" && continue
+ if file_verify "${kfile}" ; then continue ; fi
- kgen="${kgen} ${ktype}"
+ kgen="${kgen}${kgen:+ }${ktype}"
done
- [ -z "${kgen}" ] && return
+ # all keys are sane?
+ [ -n "${kgen}" ] || return 0
- tdir=$(mktemp -d); chmod 0700 "${tdir}"
+ hk_tmp_dir=$(mktemp -d)
+ # system in bad state?
+ [ -n "${hk_tmp_dir}" ] || return 1
- kcount=0
- for ktype in ${kgen}; do
- tfile="${tdir}/dropbear_${ktype}_host_key"
+ chmod 0700 "${hk_tmp_dir}"
- if ! _dropbearkey -t ${ktype} -f "${tfile}"; then
+ for ktype in ${kgen} ; do
+ kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
+
+ if ! _dropbearkey -t ${ktype} -f "${kfile}" ; then
# unsupported key type
- rm -f "${tfile}"
+ rm -f "${kfile}"
continue
fi
- kcount=$((kcount+1))
+ chmod 0600 "${kfile}"
done
- if [ ${kcount} -ne 0 ]; then
- mkdir -p "${kdir}"; chmod 0700 "${kdir}"; chown root "${kdir}"
- mv -f "${tdir}/"* "${kdir}/"
+ kgen=
+ for ktype in ${ktype_all} ; do
+ kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
+
+ [ -s "${kfile}" ] || continue
+
+ kgen="${kgen}${kgen:+ }${ktype}"
+ done
+
+ if [ -n "${kgen}" ] ; then
+ for ktype in ${kgen} ; do
+ kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
+ [ -s "${kfile}" ] || continue
+ mv -f "${kfile}" "${hk_cfg_dir}/"
+ done
fi
- rm -rf "${tdir}"
+ rm -rf "${hk_tmp_dir}"
+
+ # cleanup empty files
+ for ktype in ${ktype_all} ; do
+ kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
+
+ [ -s "${kfile}" ] || rm -f "${kfile}"
+ done
}
-append_ports()
+# $1 - list with whitespace-separated elements
+normalize_list()
{
- local ipaddrs="$1"
- local port="$2"
-
- [ -z "$ipaddrs" ] && {
- procd_append_param command -p "$port"
- return
- }
+ printf '%s' "$1" | tr -s ' \r\n\t' ' ' | sed -E 's/^ //;s/ $//'
+}
- for addr in $ipaddrs; do
- procd_append_param command -p "$addr:$port"
- done
+warn_multiple_interfaces()
+{
+ logger -t "${NAME}" -p daemon.warn \
+ "Option '$1' should specify SINGLE interface but instead it lists interfaces: $2"
+ logger -t "${NAME}" -p daemon.warn \
+ "Consider creating per-interface instances instead!"
}
validate_section_dropbear()
@@ -117,8 +165,10 @@ validate_section_dropbear()
uci_load_validate dropbear dropbear "$1" "$2" \
'PasswordAuth:bool:1' \
'enable:bool:1' \
+ 'DirectInterface:string' \
'Interface:string' \
'GatewayPorts:bool:0' \
+ 'ForceCommand:string' \
'RootPasswordAuth:bool:1' \
'RootLogin:bool:1' \
'rsakeyfile:file' \
@@ -128,52 +178,181 @@ validate_section_dropbear()
'SSHKeepAlive:uinteger:300' \
'IdleTimeout:uinteger:0' \
'MaxAuthTries:uinteger:3' \
- 'RecvWindowSize:uinteger:0' \
+ 'RecvWindowSize:uinteger:262144' \
'mdns:bool:1'
}
dropbear_instance()
{
- local ipaddrs
-
[ "$2" = 0 ] || {
echo "validation failed"
return 1
}
- [ -n "${Interface}" ] && {
- [ -n "${BOOT}" ] && return 0
+ [ "${enable}" = "1" ] || return 1
- network_get_ipaddrs_all ipaddrs "${Interface}" || {
- echo "interface ${Interface} has no physdev or physdev has no suitable ip"
- return 1
- }
- }
+ local iface ndev ipaddrs
+
+ # 'DirectInterface' should specify single interface
+ # but end users may misinterpret this setting
+ DirectInterface=$(normalize_list "${DirectInterface}")
+
+ # 'Interface' should specify single interface
+ # but end users are often misinterpret this setting
+ Interface=$(normalize_list "${Interface}")
+
+ if [ -n "${Interface}" ] ; then
+ if [ -n "${DirectInterface}" ] ; then
+ logger -t "${NAME}" -p daemon.warn \
+ "Option 'DirectInterface' takes precedence over 'Interface'"
+ else
+ logger -t "${NAME}" -p daemon.info \
+ "Option 'Interface' binds to address(es) but not to interface"
+ logger -t "${NAME}" -p daemon.info \
+ "Consider using option 'DirectInterface' to bind directly to interface"
+ fi
+ fi
+
+ # handle 'DirectInterface'
+ iface=$(echo "${DirectInterface}" | awk '{print $1}')
+ case "${DirectInterface}" in
+ *\ *)
+ warn_multiple_interfaces DirectInterface "${DirectInterface}"
+ logger -t "${NAME}" -p daemon.warn \
+ "Using network interface '${iface}' for direct binding"
+ ;;
+ esac
+ while [ -n "${iface}" ] ; do
+ # if network is available (even during boot) - proceed
+ if network_is_up "${iface}" ; then break ; fi
+ # skip during boot
+ [ -z "${BOOT}" ] || return 0
+
+ logger -t "${NAME}" -p daemon.crit \
+ "Network interface '${iface}' is not available!"
+ return 1
+ done
+ while [ -n "${iface}" ] ; do
+ # ${iface} is logical (higher level) interface name
+ # ${ndev} is 'real' interface name
+ # e.g.: if ${iface} is 'lan' (default LAN interface) then ${ndev} is 'br-lan'
+ network_get_device ndev "${iface}"
+ [ -z "${ndev}" ] || break
+
+ logger -t "${NAME}" -p daemon.crit \
+ "Missing network device for network interface '${iface}'!"
+ return 1
+ done
+ if [ -n "${iface}" ] ; then
+ logger -t "${NAME}" -p daemon.info \
+ "Using network interface '${iface}' (network device '${ndev}') for direct binding"
+ fi
+ # handle 'Interface'
+ while [ -z "${iface}" ] ; do
+ [ -n "${Interface}" ] || break
+
+ # skip during boot
+ [ -z "${BOOT}" ] || return 0
+
+ case "${Interface}" in
+ *\ *)
+ warn_multiple_interfaces Interface "${Interface}"
+ ;;
+ esac
+
+ local c=0
+ # sysoptions.h
+ local DROPBEAR_MAX_PORTS=10
+
+ local a n if_ipaddrs
+ for n in ${Interface} ; do
+ [ -n "$n" ] || continue
+
+ if_ipaddrs=
+ network_get_ipaddrs_all if_ipaddrs "$n"
+ [ -n "${if_ipaddrs}" ] || {
+ logger -s -t "${NAME}" -p daemon.err \
+ "Network interface '$n' has no suitable IP address(es)!"
+ continue
+ }
+
+ [ $c -le ${DROPBEAR_MAX_PORTS} ] || {
+ logger -s -t "${NAME}" -p daemon.err \
+ "Network interface '$n' is NOT listened due to option limit exceed!"
+ continue
+ }
+
+ for a in ${if_ipaddrs} ; do
+ [ -n "$a" ] || continue
+
+ c=$((c+1))
+ if [ $c -le ${DROPBEAR_MAX_PORTS} ] ; then
+ ipaddrs="${ipaddrs} $a"
+ continue
+ fi
+
+ logger -t "${NAME}" -p daemon.err \
+ "Endpoint '$a:${Port}' on network interface '$n' is NOT listened due to option limit exceed!"
+ done
+ done
+ break
+ done
- [ "${enable}" = "0" ] && return 1
PIDCOUNT="$(( ${PIDCOUNT} + 1))"
local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
procd_open_instance
procd_set_param command "$PROG" -F -P "$pid_file"
+ if [ -n "${iface}" ] ; then
+ # if ${iface} is non-empty then ${ndev} is non-empty too
+ procd_append_param command -l "${ndev}" -p "${Port}"
+ else
+ if [ -z "${ipaddrs}" ] ; then
+ procd_append_param command -p "${Port}"
+ else
+ local a
+ for a in ${ipaddrs} ; do
+ [ -n "$a" ] || continue
+ procd_append_param command -p "$a:${Port}"
+ done
+ fi
+ fi
[ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s
[ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a
+ [ -n "${ForceCommand}" ] && procd_append_param command -c "${ForceCommand}"
[ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g
[ "${RootLogin}" -eq 0 ] && procd_append_param command -w
+ config_list_foreach "$1" 'keyfile' hk_config__keyfile
if [ -n "${rsakeyfile}" ]; then
- logger -t ${NAME} -p daemon.warn \
- "option 'rsakeyfile' is considered to be deprecated and" \
- "will be removed in future releases, use 'keyfile' instead"
+ logger -s -t "${NAME}" -p daemon.crit \
+ "Option 'rsakeyfile' is considered to be DEPRECATED and will be REMOVED in future releases, use 'keyfile' list instead"
+ sed -i.before-upgrade -E -e 's/option(\s+)rsakeyfile/list keyfile/' \
+ "/etc/config/${NAME}"
+ logger -s -t "${NAME}" -p daemon.crit \
+ "Auto-transition 'option rsakeyfile' => 'list keyfile' in /etc/config/${NAME} is done, please verify your configuration"
hk_config 'rsakeyfile' "${rsakeyfile}"
fi
- config_list_foreach "$1" "keyfile" hk_config__keyfile
[ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
- append_ports "${ipaddrs}" "${Port}"
[ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
[ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
[ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}"
- [ "${RecvWindowSize}" -gt 0 -a "${RecvWindowSize}" -le 1048576 ] && \
+ [ "${RecvWindowSize}" -gt 0 ] && {
+ # NB: OpenWrt increases receive window size to increase throughput on high latency links
+ # ref: validate_section_dropbear()
+ # default receive window size is 24576 (DEFAULT_RECV_WINDOW in default_options.h)
+
+ # sysoptions.h
+ local MAX_RECV_WINDOW=10485760
+ if [ "${RecvWindowSize}" -gt ${MAX_RECV_WINDOW} ] ; then
+ # separate logging is required because syslog misses dropbear's message
+ # Bad recv window '${RecvWindowSize}', using ${MAX_RECV_WINDOW}
+ # it's probably dropbear issue but we should handle this and notify user
+ logger -s -t "${NAME}" -p daemon.warn \
+ "Option 'RecvWindowSize' is too high (${RecvWindowSize}), limiting to ${MAX_RECV_WINDOW}"
+ RecvWindowSize=${MAX_RECV_WINDOW}
+ fi
procd_append_param command -W "${RecvWindowSize}"
+ }
[ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear"
procd_set_param respawn
procd_close_instance
@@ -181,10 +360,21 @@ dropbear_instance()
load_interfaces()
{
- config_get interface "$1" Interface
+ local enable
config_get enable "$1" enable 1
-
- [ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
+ [ "${enable}" = "1" ] || return 0
+
+ local direct_iface iface
+ config_get direct_iface "$1" DirectInterface
+ direct_iface=$(normalize_list "${direct_iface}")
+ # 'DirectInterface' takes precedence over 'Interface'
+ if [ -n "${direct_iface}" ] ; then
+ iface=$(echo "${direct_iface}" | awk '{print $1}')
+ else
+ config_get iface "$1" Interface
+ iface=$(normalize_list "${iface}")
+ fi
+ interfaces="${interfaces} ${iface}"
}
boot()
@@ -196,6 +386,7 @@ boot()
start_service()
{
hk_generate_as_needed
+ file_verify /etc/dropbear/authorized_keys config
. /lib/functions.sh
. /lib/functions/network.sh
@@ -208,13 +399,14 @@ service_triggers()
{
local interfaces
- procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload
+ procd_add_config_trigger "config.change" "${NAME}" /etc/init.d/dropbear reload
config_load "${NAME}"
- config_foreach load_interfaces dropbear
+ config_foreach load_interfaces "${NAME}"
[ -n "${interfaces}" ] && {
- for n in $interfaces ; do
+ local n
+ for n in $(printf '%s\n' ${interfaces} | sort -u) ; do
procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload
done
}
diff --git a/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch b/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch
new file mode 100644
index 00000000000..ad1a20c520f
--- /dev/null
+++ b/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch
@@ -0,0 +1,104 @@
+From 36a03132634a17c667c0fac0a8e1519b3d1b71c6 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 28 Nov 2022 21:12:23 +0800
+Subject: Add #if DROPBEAR_RSA guards
+
+Fixes building with DROPBEAR_RSA disabled.
+Closes #197
+---
+ signkey.c | 8 +++++++-
+ signkey.h | 2 ++
+ sysoptions.h | 5 +----
+ 3 files changed, 10 insertions(+), 5 deletions(-)
+
+--- a/signkey.c
++++ b/signkey.c
+@@ -120,6 +120,7 @@ enum signkey_type signkey_type_from_name
+ /* Special case for rsa-sha2-256. This could be generalised if more
+ signature names are added that aren't 1-1 with public key names */
+ const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA256
+ if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
+ if (namelen) {
+@@ -136,11 +137,13 @@ const char* signature_name_from_type(enu
+ return SSH_SIGNKEY_RSA;
+ }
+ #endif
++#endif /* DROPBEAR_RSA */
+ return signkey_name_from_type((enum signkey_type)type, namelen);
+ }
+
+ /* Returns DROPBEAR_SIGNATURE_NONE if none match */
+ enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA256
+ if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256)
+ && memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
+@@ -153,10 +156,11 @@ enum signature_type signature_type_from_
+ return DROPBEAR_SIGNATURE_RSA_SHA1;
+ }
+ #endif
++#endif /* DROPBEAR_RSA */
+ return (enum signature_type)signkey_type_from_name(name, namelen);
+ }
+
+-/* Returns the signature type from a key type. Must not be called
++/* Returns the signature type from a key type. Must not be called
+ with RSA keytype */
+ enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
+ #if DROPBEAR_RSA
+@@ -167,6 +171,7 @@ enum signature_type signature_type_from_
+ }
+
+ enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA256
+ if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
+ return DROPBEAR_SIGNKEY_RSA;
+@@ -177,6 +182,7 @@ enum signkey_type signkey_type_from_sign
+ return DROPBEAR_SIGNKEY_RSA;
+ }
+ #endif
++#endif /* DROPBEAR_RSA */
+ assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
+ return (enum signkey_type)sigtype;
+ }
+--- a/signkey.h
++++ b/signkey.h
+@@ -79,12 +79,14 @@ enum signature_type {
+ DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
+ #endif
+ #endif
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA1
+ DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
+ #endif
+ #if DROPBEAR_RSA_SHA256
+ DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */
+ #endif
++#endif /* DROPBEAR_RSA */
+ DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE,
+ };
+
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -137,7 +137,7 @@
+
+ /* Debian doesn't define this in system headers */
+ #if !defined(LTM_DESC) && (DROPBEAR_ECC)
+-#define LTM_DESC
++#define LTM_DESC
+ #endif
+
+ #define DROPBEAR_ECC_256 (DROPBEAR_ECC)
+@@ -151,9 +151,6 @@
+ * signing operations slightly slower. */
+ #define DROPBEAR_RSA_BLINDING 1
+
+-#ifndef DROPBEAR_RSA_SHA1
+-#define DROPBEAR_RSA_SHA1 DROPBEAR_RSA
+-#endif
+ #ifndef DROPBEAR_RSA_SHA256
+ #define DROPBEAR_RSA_SHA256 DROPBEAR_RSA
+ #endif
diff --git a/package/network/services/dropbear/patches/002-fix-y2038-issues.patch b/package/network/services/dropbear/patches/002-fix-y2038-issues.patch
new file mode 100644
index 00000000000..0654e3b98b5
--- /dev/null
+++ b/package/network/services/dropbear/patches/002-fix-y2038-issues.patch
@@ -0,0 +1,198 @@
+From ec2215726cffb976019d08ebf569edd2229e9dba Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Thu, 1 Dec 2022 11:34:43 +0800
+Subject: Fix y2038 issues with time_t conversion
+
+These changes were identified by building with and without
+-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
+on 32-bit arm, logging warnings to files.
+-Wconversion was added to CFLAGS in both builds.
+
+Then a "diff -I Wconversion log1 log2" shows new warnings that appear
+with the 64-bit time_t. There are a few false positives that have been
+fixed for quietness.
+
+struct logininfo and struct wtmp are still problematic, those will
+need to be handled by libc.
+---
+ common-session.c | 43 +++++++++++++++++++++++++++----------------
+ dbutil.c | 2 +-
+ loginrec.c | 2 ++
+ loginrec.h | 4 ++--
+ runopts.h | 4 ++--
+ svr-auth.c | 2 +-
+ 6 files changed, 35 insertions(+), 22 deletions(-)
+
+--- a/common-session.c
++++ b/common-session.c
+@@ -519,15 +519,24 @@ static void send_msg_keepalive() {
+ ses.last_packet_time_idle = old_time_idle;
+ }
+
++/* Returns the difference in seconds, clamped to LONG_MAX */
++static long elapsed(time_t now, time_t prev) {
++ time_t del = now - prev;
++ if (del > LONG_MAX) {
++ return LONG_MAX;
++ }
++ return (long)del;
++}
++
+ /* Check all timeouts which are required. Currently these are the time for
+ * user authentication, and the automatic rekeying. */
+ static void checktimeouts() {
+
+ time_t now;
+ now = monotonic_now();
+-
++
+ if (IS_DROPBEAR_SERVER && ses.connect_time != 0
+- && now - ses.connect_time >= AUTH_TIMEOUT) {
++ && elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) {
+ dropbear_close("Timeout before auth");
+ }
+
+@@ -537,45 +546,47 @@ static void checktimeouts() {
+ }
+
+ if (!ses.kexstate.sentkexinit
+- && (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
++ && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
+ || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
+ TRACE(("rekeying after timeout or max data reached"))
+ send_msg_kexinit();
+ }
+-
++
+ if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
+ /* Avoid sending keepalives prior to auth - those are
+ not valid pre-auth packet types */
+
+ /* Send keepalives if we've been idle */
+- if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
++ if (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) {
+ send_msg_keepalive();
+ }
+
+ /* Also send an explicit keepalive message to trigger a response
+ if the remote end hasn't sent us anything */
+- if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
+- && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
++ if (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs
++ && elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) {
+ send_msg_keepalive();
+ }
+
+- if (now - ses.last_packet_time_keepalive_recv
++ if (elapsed(now, ses.last_packet_time_keepalive_recv)
+ >= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
+ dropbear_exit("Keepalive timeout");
+ }
+ }
+
+- if (opts.idle_timeout_secs > 0
+- && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
++ if (opts.idle_timeout_secs > 0
++ && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
+ dropbear_close("Idle timeout");
+ }
+ }
+
+-static void update_timeout(long limit, long now, long last_event, long * timeout) {
+- TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
+- limit, now, last_event, *timeout))
++static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
++ TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
++ limit,
++ (unsigned long long)now,
++ (unsigned long long)last_event, *timeout))
+ if (last_event > 0 && limit > 0) {
+- *timeout = MIN(*timeout, last_event+limit-now);
++ *timeout = MIN(*timeout, elapsed(now, last_event) + limit);
+ TRACE2(("new timeout %ld", *timeout))
+ }
+ }
+@@ -584,7 +595,7 @@ static long select_timeout() {
+ /* determine the minimum timeout that might be required, so
+ as to avoid waking when unneccessary */
+ long timeout = KEX_REKEY_TIMEOUT;
+- long now = monotonic_now();
++ time_t now = monotonic_now();
+
+ if (!ses.kexstate.sentkexinit) {
+ update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
+@@ -596,7 +607,7 @@ static long select_timeout() {
+ }
+
+ if (ses.authstate.authdone) {
+- update_timeout(opts.keepalive_secs, now,
++ update_timeout(opts.keepalive_secs, now,
+ MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
+ &timeout);
+ }
+--- a/dbutil.c
++++ b/dbutil.c
+@@ -724,7 +724,7 @@ void gettime_wrapper(struct timespec *no
+ /* Fallback for everything else - this will sometimes go backwards */
+ gettimeofday(&tv, NULL);
+ now->tv_sec = tv.tv_sec;
+- now->tv_nsec = 1000*tv.tv_usec;
++ now->tv_nsec = 1000*(long)tv.tv_usec;
+ }
+
+ /* second-resolution monotonic timestamp */
+--- a/loginrec.c
++++ b/loginrec.c
+@@ -459,6 +459,7 @@ line_abbrevname(char *dst, const char *s
+ void
+ set_utmp_time(struct logininfo *li, struct utmp *ut)
+ {
++ /* struct utmp in glibc isn't y2038 safe yet */
+ # ifdef HAVE_STRUCT_UTMP_UT_TV
+ ut->ut_tv.tv_sec = li->tv_sec;
+ ut->ut_tv.tv_usec = li->tv_usec;
+@@ -1272,6 +1273,7 @@ lastlog_construct(struct logininfo *li,
+ (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
+ strlcpy(last->ll_host, li->hostname,
+ MIN_SIZEOF(last->ll_host, li->hostname));
++ /* struct lastlog in glibc isn't y2038 safe yet */
+ last->ll_time = li->tv_sec;
+ }
+
+--- a/loginrec.h
++++ b/loginrec.h
+@@ -139,8 +139,8 @@ struct logininfo {
+ /* struct timeval (sys/time.h) isn't always available, if it isn't we'll
+ * use time_t's value as tv_sec and set tv_usec to 0
+ */
+- unsigned int tv_sec;
+- unsigned int tv_usec;
++ time_t tv_sec;
++ suseconds_t tv_usec;
+ union login_netinfo hostaddr; /* caller's host address(es) */
+ }; /* struct logininfo */
+
+--- a/runopts.h
++++ b/runopts.h
+@@ -39,8 +39,8 @@ typedef struct runopts {
+ int listen_fwd_all;
+ #endif
+ unsigned int recv_window;
+- time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
+- time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
++ long keepalive_secs; /* Time between sending keepalives. 0 is off */
++ long idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
+ int usingsyslog;
+
+ #ifndef DISABLE_ZLIB
+--- a/svr-auth.c
++++ b/svr-auth.c
+@@ -389,7 +389,7 @@ void send_msg_userauth_failure(int parti
+ Beware of integer overflow if increasing these values */
+ const unsigned int mindelay = 250000000;
+ const unsigned int vardelay = 100000000;
+- unsigned int rand_delay;
++ suseconds_t rand_delay;
+ struct timespec delay;
+
+ gettime_wrapper(&delay);
diff --git a/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch b/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch
new file mode 100644
index 00000000000..6789800e120
--- /dev/null
+++ b/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch
@@ -0,0 +1,25 @@
+From c043efb47c3173072fa636ca0da0d19875d4511f Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Tue, 6 Dec 2022 22:34:11 +0800
+Subject: Fix so DROPBEAR_DSS is only forced for fuzzing
+
+Regression from 787391ea3b5af2acf5e3c83372510f0c79477ad7,
+was missing fuzzing conditional
+---
+ sysoptions.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -380,9 +380,11 @@
+ #endif
+
+ /* Fuzzing expects all key types to be enabled */
++#if DROPBEAR_FUZZ
+ #if defined(DROPBEAR_DSS)
+ #undef DROPBEAR_DSS
+ #endif
+ #define DROPBEAR_DSS 1
++#endif
+
+ /* no include guard for this file */
diff --git a/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch b/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch
new file mode 100644
index 00000000000..bcb43aed2ae
--- /dev/null
+++ b/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch
@@ -0,0 +1,24 @@
+From 860721558837441ab45019858e710a2625ffa46e Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Wed, 7 Dec 2022 13:04:10 +0800
+Subject: Allow users's own gid in pty permission check
+
+This allows non-root Dropbear to work even without devpts gid=5 mount
+option on Linux.
+---
+ sshpty.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/sshpty.c
++++ b/sshpty.c
+@@ -380,7 +380,9 @@ pty_setowner(struct passwd *pw, const ch
+ tty_name, strerror(errno));
+ }
+
+- if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
++ /* Allow either "tty" gid or user's own gid. On Linux with openpty()
++ * this varies depending on the devpts mount options */
++ if (st.st_uid != pw->pw_uid || !(st.st_gid == gid || st.st_gid == pw->pw_gid)) {
+ if (chown(tty_name, pw->pw_uid, gid) < 0) {
+ if (errno == EROFS &&
+ (st.st_uid == pw->pw_uid || st.st_uid == 0)) {
diff --git a/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch b/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch
new file mode 100644
index 00000000000..0d23c9c4161
--- /dev/null
+++ b/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch
@@ -0,0 +1,123 @@
+From 01415ef8269e594a647f67ea0729ca8b590679de Mon Sep 17 00:00:00 2001
+From: Francois Perrad <francois.perrad@gadz.org>
+Date: Thu, 22 Dec 2022 10:19:54 +0100
+Subject: const parameter mp_int
+
+---
+ bignum.c | 2 +-
+ bignum.h | 2 +-
+ buffer.c | 2 +-
+ buffer.h | 2 +-
+ dbrandom.c | 2 +-
+ dbrandom.h | 2 +-
+ dbutil.c | 2 +-
+ dbutil.h | 2 +-
+ genrsa.c | 4 ++--
+ 9 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/bignum.c
++++ b/bignum.c
+@@ -93,7 +93,7 @@ void bytes_to_mp(mp_int *mp, const unsig
+
+ /* hash the ssh representation of the mp_int mp */
+ void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
+- hash_state *hs, mp_int *mp) {
++ hash_state *hs, const mp_int *mp) {
+ buffer * buf;
+
+ buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
+--- a/bignum.h
++++ b/bignum.h
+@@ -33,6 +33,6 @@ void m_mp_alloc_init_multi(mp_int **mp,
+ void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
+ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
+ void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
+- hash_state *hs, mp_int *mp);
++ hash_state *hs, const mp_int *mp);
+
+ #endif /* DROPBEAR_BIGNUM_H_ */
+--- a/buffer.c
++++ b/buffer.c
+@@ -299,7 +299,7 @@ void buf_putbytes(buffer *buf, const uns
+
+ /* for our purposes we only need positive (or 0) numbers, so will
+ * fail if we get negative numbers */
+-void buf_putmpint(buffer* buf, mp_int * mp) {
++void buf_putmpint(buffer* buf, const mp_int * mp) {
+ size_t written;
+ unsigned int len, pad = 0;
+ TRACE2(("enter buf_putmpint"))
+--- a/buffer.h
++++ b/buffer.h
+@@ -65,7 +65,7 @@ void buf_putint(buffer* buf, unsigned in
+ void buf_putstring(buffer* buf, const char* str, unsigned int len);
+ void buf_putbufstring(buffer *buf, const buffer* buf_str);
+ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
+-void buf_putmpint(buffer* buf, mp_int * mp);
++void buf_putmpint(buffer* buf, const mp_int * mp);
+ int buf_getmpint(buffer* buf, mp_int* mp);
+ unsigned int buf_getint(buffer* buf);
+
+--- a/dbrandom.c
++++ b/dbrandom.c
+@@ -347,7 +347,7 @@ void genrandom(unsigned char* buf, unsig
+ * rand must be an initialised *mp_int for the result.
+ * the result rand satisfies: 0 < rand < max
+ * */
+-void gen_random_mpint(mp_int *max, mp_int *rand) {
++void gen_random_mpint(const mp_int *max, mp_int *rand) {
+
+ unsigned char *randbuf = NULL;
+ unsigned int len = 0;
+--- a/dbrandom.h
++++ b/dbrandom.h
+@@ -30,6 +30,6 @@
+ void seedrandom(void);
+ void genrandom(unsigned char* buf, unsigned int len);
+ void addrandom(const unsigned char * buf, unsigned int len);
+-void gen_random_mpint(mp_int *max, mp_int *rand);
++void gen_random_mpint(const mp_int *max, mp_int *rand);
+
+ #endif /* DROPBEAR_RANDOM_H_ */
+--- a/dbutil.c
++++ b/dbutil.c
+@@ -442,7 +442,7 @@ void printhex(const char * label, const
+ }
+ }
+
+-void printmpint(const char *label, mp_int *mp) {
++void printmpint(const char *label, const mp_int *mp) {
+ buffer *buf = buf_new(1000);
+ buf_putmpint(buf, mp);
+ fprintf(stderr, "%d bits ", mp_count_bits(mp));
+--- a/dbutil.h
++++ b/dbutil.h
+@@ -53,7 +53,7 @@ void dropbear_trace3(const char* format,
+ void dropbear_trace4(const char* format, ...) ATTRIB_PRINTF(1,2);
+ void dropbear_trace5(const char* format, ...) ATTRIB_PRINTF(1,2);
+ void printhex(const char * label, const unsigned char * buf, int len);
+-void printmpint(const char *label, mp_int *mp);
++void printmpint(const char *label, const mp_int *mp);
+ void debug_start_net(void);
+ extern int debug_trace;
+ #endif
+--- a/genrsa.c
++++ b/genrsa.c
+@@ -34,7 +34,7 @@
+ #if DROPBEAR_RSA
+
+ static void getrsaprime(mp_int* prime, mp_int *primeminus,
+- mp_int* rsa_e, unsigned int size_bytes);
++ const mp_int* rsa_e, unsigned int size_bytes);
+
+ /* mostly taken from libtomcrypt's rsa key generation routine */
+ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
+@@ -89,7 +89,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsi
+
+ /* return a prime suitable for p or q */
+ static void getrsaprime(mp_int* prime, mp_int *primeminus,
+- mp_int* rsa_e, unsigned int size_bytes) {
++ const mp_int* rsa_e, unsigned int size_bytes) {
+
+ unsigned char *buf;
+ int trials;
diff --git a/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch b/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch
new file mode 100644
index 00000000000..c7011021c17
--- /dev/null
+++ b/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch
@@ -0,0 +1,21 @@
+From 39d955c49f31fc155e885447ee2be61c869d8c2d Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Tue, 3 Jan 2023 22:05:14 +0800
+Subject: Add missing break in switch
+
+Has no effect on execution, the fallthrough does nothing
+Closes #208
+---
+ dropbearkey.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/dropbearkey.c
++++ b/dropbearkey.c
+@@ -139,6 +139,7 @@ static void check_signkey_bits(enum sign
+ dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
+ exit(EXIT_FAILURE);
+ }
++ break;
+ #endif
+ default:
+ (void)0; /* quiet, compiler. ecdsa handles checks itself */
diff --git a/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch b/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch
new file mode 100644
index 00000000000..5fcfaad1809
--- /dev/null
+++ b/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch
@@ -0,0 +1,29 @@
+From 7a53c7f0f4b3eb23e002819553cb45558642c01d Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Wed, 4 Jan 2023 20:32:23 +0800
+Subject: Fix building only client or server
+
+Regressed when -Wundef was added
+
+Fixes #210
+---
+ sysoptions.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -10,6 +10,14 @@
+ #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
+ #define PROGNAME "dropbear"
+
++#ifndef DROPBEAR_CLIENT
++#define DROPBEAR_CLIENT 0
++#endif
++
++#ifndef DROPBEAR_SERVER
++#define DROPBEAR_SERVER 0
++#endif
++
+ /* Spec recommends after one hour or 1 gigabyte of data. One hour
+ * is a bit too verbose, so we try 8 hours */
+ #ifndef KEX_REKEY_TIMEOUT
diff --git a/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch b/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch
new file mode 100644
index 00000000000..4f675234ff9
--- /dev/null
+++ b/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch
@@ -0,0 +1,94 @@
+From a113381c12a2da3c9b7bd594f47a1b2657bdfdf2 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sun, 12 Feb 2023 22:44:32 +0800
+Subject: Disable rsa signatures when no rsa hostkey
+
+Otherwise Dropbear will offer RSA as a hostkey signature option, but the
+session will exit with an assertion or NULL pointer dereference once
+that algorithm is negotiated.
+
+This likely regressed in 2020.79 when signature vs key type enums were
+split, for rsa-sha256.
+
+Fixes #219 on github
+---
+ svr-runopts.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -505,11 +505,11 @@ static void addportandaddress(const char
+ svr_opts.portcount++;
+ }
+
+-static void disablekey(int type) {
++static void disablekey(enum signature_type type) {
+ int i;
+ TRACE(("Disabling key type %d", type))
+ for (i = 0; sigalgs[i].name != NULL; i++) {
+- if (sigalgs[i].val == type) {
++ if ((int)sigalgs[i].val == (int)type) {
+ sigalgs[i].usable = 0;
+ break;
+ }
+@@ -624,7 +624,8 @@ void load_all_hostkeys() {
+
+ #if DROPBEAR_RSA
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
+- disablekey(DROPBEAR_SIGNKEY_RSA);
++ disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
++ disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
+ } else {
+ any_keys = 1;
+ }
+@@ -632,7 +633,7 @@ void load_all_hostkeys() {
+
+ #if DROPBEAR_DSS
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
+- disablekey(DROPBEAR_SIGNKEY_DSS);
++ disablekey(DROPBEAR_SIGNATURE_DSS);
+ } else {
+ any_keys = 1;
+ }
+@@ -666,35 +667,35 @@ void load_all_hostkeys() {
+ #if DROPBEAR_ECC_256
+ if (!svr_opts.hostkey->ecckey256
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
+- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
+ }
+ #endif
+ #if DROPBEAR_ECC_384
+ if (!svr_opts.hostkey->ecckey384
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
+- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
+ }
+ #endif
+ #if DROPBEAR_ECC_521
+ if (!svr_opts.hostkey->ecckey521
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
+- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
+ }
+ #endif
+ #endif /* DROPBEAR_ECDSA */
+
+ #if DROPBEAR_ED25519
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
+- disablekey(DROPBEAR_SIGNKEY_ED25519);
++ disablekey(DROPBEAR_SIGNATURE_ED25519);
+ } else {
+ any_keys = 1;
+ }
+ #endif
+ #if DROPBEAR_SK_ECDSA
+- disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256);
++ disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
+ #endif
+ #if DROPBEAR_SK_ED25519
+- disablekey(DROPBEAR_SIGNKEY_SK_ED25519);
++ disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
+ #endif
+
+ if (!any_keys) {
diff --git a/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch b/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch
new file mode 100644
index 00000000000..e1538a4c1f7
--- /dev/null
+++ b/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch
@@ -0,0 +1,27 @@
+From 3292b8c6f1e5fcc405fa0f7a20e90a60f74037b2 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sun, 12 Feb 2023 23:00:00 +0800
+Subject: Use write() rather than fprintf() in segv handler
+
+fprintf isn't guaranteed safe (though hasn't had any problems reported).
+---
+ svr-main.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/svr-main.c
++++ b/svr-main.c
+@@ -420,8 +420,12 @@ static void sigchld_handler(int UNUSED(u
+
+ /* catch any segvs */
+ static void sigsegv_handler(int UNUSED(unused)) {
+- fprintf(stderr, "Aiee, segfault! You should probably report "
+- "this as a bug to the developer\n");
++ int i;
++ const char *msg = "Aiee, segfault! You should probably report "
++ "this as a bug to the developer\n";
++ i = write(STDERR_FILENO, msg, strlen(msg));
++ /* ignore short writes */
++ (void)i;
+ _exit(EXIT_FAILURE);
+ }
+
diff --git a/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch b/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch
new file mode 100644
index 00000000000..12b1843ee26
--- /dev/null
+++ b/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch
@@ -0,0 +1,39 @@
+From 5040f21cb4ee6ade966e60c6d5a3c270d03de1f1 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 1 May 2023 22:05:43 +0800
+Subject: Remove SO_LINGER
+
+It could cause channels to take up to 5 seconds to close(), which would block
+the entire process. On busy TCP forwarding sessions this would result in
+channels seeming stuck and new connections not being accepted.
+
+We don't need to monitor for flushing failures since we can't report errors, so
+SO_LINGER wasn't useful.
+
+Thanks to GektorUA for reporting and testing
+
+Fixes #230
+---
+ netio.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/netio.c
++++ b/netio.c
+@@ -472,7 +472,6 @@ int dropbear_listen(const char* address,
+ struct addrinfo hints, *res = NULL, *res0 = NULL;
+ int err;
+ unsigned int nsock;
+- struct linger linger;
+ int val;
+ int sock;
+ uint16_t *allocated_lport_p = NULL;
+@@ -551,9 +550,6 @@ int dropbear_listen(const char* address,
+ val = 1;
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+- linger.l_onoff = 1;
+- linger.l_linger = 5;
+- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
+
+ #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ if (res->ai_family == AF_INET6) {
diff --git a/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch b/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch
new file mode 100644
index 00000000000..d1c1fa4cced
--- /dev/null
+++ b/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch
@@ -0,0 +1,147 @@
+From fb64db9eac3fdc6434f2dc7b5ea407fe5df76e6f Mon Sep 17 00:00:00 2001
+From: Diederik De Coninck <diederik.deconinck_ext@softathome.com>
+Date: Tue, 11 Apr 2023 15:38:04 +0200
+Subject: Add option to bind to interface
+
+---
+ netio.c | 13 +++++++++++--
+ netio.h | 2 +-
+ runopts.h | 1 +
+ svr-main.c | 2 +-
+ svr-runopts.c | 9 +++++++++
+ svr-tcpfwd.c | 1 +
+ tcp-accept.c | 2 +-
+ tcpfwd.h | 1 +
+ 8 files changed, 26 insertions(+), 5 deletions(-)
+
+--- a/netio.c
++++ b/netio.c
+@@ -467,7 +467,7 @@ int get_sock_port(int sock) {
+ * failure, if errstring wasn't NULL, it'll be a newly malloced error
+ * string.*/
+ int dropbear_listen(const char* address, const char* port,
+- int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
++ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface) {
+
+ struct addrinfo hints, *res = NULL, *res0 = NULL;
+ int err;
+@@ -497,7 +497,11 @@ int dropbear_listen(const char* address,
+ TRACE(("dropbear_listen: local loopback"))
+ } else {
+ if (address[0] == '\0') {
+- TRACE(("dropbear_listen: all interfaces"))
++ if (interface) {
++ TRACE(("dropbear_listen: %s", interface))
++ } else {
++ TRACE(("dropbear_listen: all interfaces"))
++ }
+ address = NULL;
+ }
+ hints.ai_flags = AI_PASSIVE;
+@@ -551,6 +555,11 @@ int dropbear_listen(const char* address,
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+
++ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
++ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
++ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
++ }
++
+ #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ if (res->ai_family == AF_INET6) {
+ int on = 1;
+--- a/netio.h
++++ b/netio.h
+@@ -19,7 +19,7 @@ void get_socket_address(int fd, char **l
+ void getaddrstring(struct sockaddr_storage* addr,
+ char **ret_host, char **ret_port, int host_lookup);
+ int dropbear_listen(const char* address, const char* port,
+- int *socks, unsigned int sockcount, char **errstring, int *maxfd);
++ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface);
+
+ struct dropbear_progress_connection;
+
+--- a/runopts.h
++++ b/runopts.h
+@@ -128,6 +128,7 @@ typedef struct svr_runopts {
+ char * pidfile;
+
+ char * forced_command;
++ char* interface;
+
+ #if DROPBEAR_PLUGIN
+ /* malloced */
+--- a/svr-main.c
++++ b/svr-main.c
+@@ -488,7 +488,7 @@ static size_t listensockets(int *socks,
+
+ nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos],
+ sockcount - sockpos,
+- &errstring, maxfd);
++ &errstring, maxfd, svr_opts.interface);
+
+ if (nsock < 0) {
+ dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -98,6 +98,8 @@ static void printhelp(const char * progn
+ " (default port is %s if none specified)\n"
+ "-P PidFile Create pid file PidFile\n"
+ " (default %s)\n"
++ "-l <interface>\n"
++ " interface to bind on\n"
+ #if INETD_MODE
+ "-i Start for inetd\n"
+ #endif
+@@ -265,6 +267,9 @@ void svr_getopts(int argc, char ** argv)
+ case 'P':
+ next = &svr_opts.pidfile;
+ break;
++ case 'l':
++ next = &svr_opts.interface;
++ break;
+ #if DO_MOTD
+ /* motd is displayed by default, -m turns it off */
+ case 'm':
+@@ -438,6 +443,10 @@ void svr_getopts(int argc, char ** argv)
+ dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
+ }
+
++ if (svr_opts.interface) {
++ dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
++ }
++
+ if (reexec_fd_arg) {
+ if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
+ || svr_opts.reexec_childpipe < 0) {
+--- a/svr-tcpfwd.c
++++ b/svr-tcpfwd.c
+@@ -205,6 +205,7 @@ static int svr_remotetcpreq(int *allocat
+ tcpinfo->listenport = port;
+ tcpinfo->chantype = &svr_chan_tcpremote;
+ tcpinfo->tcp_type = forwarded;
++ tcpinfo->interface = svr_opts.interface;
+
+ tcpinfo->request_listenaddr = request_addr;
+ if (!opts.listen_fwd_all || (strcmp(request_addr, "localhost") == 0) ) {
+--- a/tcp-accept.c
++++ b/tcp-accept.c
+@@ -117,7 +117,7 @@ int listen_tcpfwd(struct TCPListener* tc
+ snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport);
+
+ nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks,
+- DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
++ DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd, tcpinfo->interface);
+ if (nsocks < 0) {
+ dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
+ m_free(errstring);
+--- a/tcpfwd.h
++++ b/tcpfwd.h
+@@ -42,6 +42,7 @@ struct TCPListener {
+ unsigned int listenport;
+ /* The address that the remote host asked to listen on */
+ char *request_listenaddr;
++ char* interface;
+
+ const struct ChanType *chantype;
+ enum {direct, forwarded} tcp_type;
diff --git a/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch b/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch
new file mode 100644
index 00000000000..11f902bf907
--- /dev/null
+++ b/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch
@@ -0,0 +1,50 @@
+From 031d09b47912b2401f4934667c0b6f857ede61ee Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Tue, 18 Jul 2023 23:20:16 +0800
+Subject: Add ifdef guards for SO_BINDTODEVICE
+
+---
+ netio.c | 2 ++
+ svr-runopts.c | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+--- a/netio.c
++++ b/netio.c
+@@ -555,10 +555,12 @@ int dropbear_listen(const char* address,
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+
++#ifdef SO_BINDTODEVICE
+ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
+ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
+ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
+ }
++#endif
+
+ #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ if (res->ai_family == AF_INET6) {
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -98,8 +98,10 @@ static void printhelp(const char * progn
+ " (default port is %s if none specified)\n"
+ "-P PidFile Create pid file PidFile\n"
+ " (default %s)\n"
++#ifdef SO_BINDTODEVICE
+ "-l <interface>\n"
+ " interface to bind on\n"
++#endif
+ #if INETD_MODE
+ "-i Start for inetd\n"
+ #endif
+@@ -267,9 +269,11 @@ void svr_getopts(int argc, char ** argv)
+ case 'P':
+ next = &svr_opts.pidfile;
+ break;
++#ifdef SO_BINDTODEVICE
+ case 'l':
+ next = &svr_opts.interface;
+ break;
++#endif
+ #if DO_MOTD
+ /* motd is displayed by default, -m turns it off */
+ case 'm':
diff --git a/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch b/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch
new file mode 100644
index 00000000000..531215c7576
--- /dev/null
+++ b/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch
@@ -0,0 +1,74 @@
+From 62a06cd95f58060a59359f8769c3f35cd680d4fd Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sun, 23 Jul 2023 21:01:48 +0800
+Subject: Make banner reading failure non-fatal
+
+---
+ svr-runopts.c | 45 ++++++++++++++++++++++++++++-----------------
+ 1 file changed, 28 insertions(+), 17 deletions(-)
+
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -38,6 +38,7 @@ static void printhelp(const char * progn
+ static void addportandaddress(const char* spec);
+ static void loadhostkey(const char *keyfile, int fatal_duplicate);
+ static void addhostkey(const char *keyfile);
++static void load_banner();
+
+ static void printhelp(const char * progname) {
+
+@@ -382,23 +383,7 @@ void svr_getopts(int argc, char ** argv)
+ }
+
+ if (svr_opts.bannerfile) {
+- struct stat buf;
+- if (stat(svr_opts.bannerfile, &buf) != 0) {
+- dropbear_exit("Error opening banner file '%s'",
+- svr_opts.bannerfile);
+- }
+-
+- if (buf.st_size > MAX_BANNER_SIZE) {
+- dropbear_exit("Banner file too large, max is %d bytes",
+- MAX_BANNER_SIZE);
+- }
+-
+- svr_opts.banner = buf_new(buf.st_size);
+- if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
+- dropbear_exit("Error reading banner file '%s'",
+- svr_opts.bannerfile);
+- }
+- buf_setpos(svr_opts.banner, 0);
++ load_banner();
+ }
+
+ #ifdef HAVE_GETGROUPLIST
+@@ -715,3 +700,29 @@ void load_all_hostkeys() {
+ dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
+ }
+ }
++
++static void load_banner() {
++ struct stat buf;
++ if (stat(svr_opts.bannerfile, &buf) != 0) {
++ dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
++ svr_opts.bannerfile);
++ return;
++ }
++
++ if (buf.st_size > MAX_BANNER_SIZE) {
++ dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
++ MAX_BANNER_SIZE);
++ return;
++ }
++
++ svr_opts.banner = buf_new(buf.st_size);
++ if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
++ dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
++ svr_opts.bannerfile);
++ buf_free(svr_opts.banner);
++ svr_opts.banner = NULL;
++ return;
++ }
++ buf_setpos(svr_opts.banner, 0);
++
++}
diff --git a/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch b/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch
new file mode 100644
index 00000000000..ff130f8be0a
--- /dev/null
+++ b/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch
@@ -0,0 +1,60 @@
+From ec26975d442163b66d1646a48e022bc8c2f1607a Mon Sep 17 00:00:00 2001
+From: Sergey Ponomarev <stokito@gmail.com>
+Date: Sun, 27 Aug 2023 00:07:05 +0300
+Subject: dropbearkey.c Ignore unsupported command line options
+
+To generate non interactively a key with OpenSSH the simplest command is:
+
+ssh-keygen -t ed25519 -q -N '' -f ~/.ssh/id_ed25519
+
+The command has two options -q quiet and -N passphrase which aren't supported by the dropbearkey.
+
+To improve interoperability add explicit ignoring of the -q and -N with empty passphrase.
+Also ignore the -v even if the DEBUG_TRACE is not set.
+
+Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
+---
+ dropbearkey.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/dropbearkey.c
++++ b/dropbearkey.c
+@@ -159,6 +159,7 @@ int main(int argc, char ** argv) {
+ enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
+ char * typetext = NULL;
+ char * sizetext = NULL;
++ char * passphrase = NULL;
+ unsigned int bits = 0, genbits;
+ int printpub = 0;
+
+@@ -194,11 +195,16 @@ int main(int argc, char ** argv) {
+ printhelp(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+-#if DEBUG_TRACE
+ case 'v':
++#if DEBUG_TRACE
+ debug_trace = DROPBEAR_VERBOSE_LEVEL;
+- break;
+ #endif
++ break;
++ case 'q':
++ break; /* quiet is default */
++ case 'N':
++ next = &passphrase;
++ break;
+ default:
+ fprintf(stderr, "Unknown argument %s\n", argv[i]);
+ printhelp(argv[0]);
+@@ -266,6 +272,11 @@ int main(int argc, char ** argv) {
+ check_signkey_bits(keytype, bits);;
+ }
+
++ if (passphrase && *passphrase != '\0') {
++ fprintf(stderr, "Only empty passphrase is supported\n");
++ exit(EXIT_FAILURE);
++ }
++
+ genbits = signkey_generate_get_bits(keytype, bits);
+ fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext);
+ if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
diff --git a/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch b/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch
new file mode 100644
index 00000000000..f39417adb79
--- /dev/null
+++ b/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch
@@ -0,0 +1,121 @@
+From 3b576d95dcf791d7b945e75f639da8f89c1685a2 Mon Sep 17 00:00:00 2001
+From: czurnieden <czurnieden@gmx.de>
+Date: Tue, 9 May 2023 17:17:12 +0200
+Subject: Fix possible integer overflow
+
+---
+ libtommath/bn_mp_2expt.c | 4 ++++
+ libtommath/bn_mp_grow.c | 4 ++++
+ libtommath/bn_mp_init_size.c | 5 +++++
+ libtommath/bn_mp_mul_2d.c | 4 ++++
+ libtommath/bn_s_mp_mul_digs.c | 4 ++++
+ libtommath/bn_s_mp_mul_digs_fast.c | 4 ++++
+ libtommath/bn_s_mp_mul_high_digs.c | 4 ++++
+ libtommath/bn_s_mp_mul_high_digs_fast.c | 4 ++++
+ 8 files changed, 33 insertions(+)
+
+--- a/libtommath/bn_mp_2expt.c
++++ b/libtommath/bn_mp_2expt.c
+@@ -12,6 +12,10 @@ mp_err mp_2expt(mp_int *a, int b)
+ {
+ mp_err err;
+
++ if (b < 0) {
++ return MP_VAL;
++ }
++
+ /* zero a as per default */
+ mp_zero(a);
+
+--- a/libtommath/bn_mp_grow.c
++++ b/libtommath/bn_mp_grow.c
+@@ -9,6 +9,10 @@ mp_err mp_grow(mp_int *a, int size)
+ int i;
+ mp_digit *tmp;
+
++ if (size < 0) {
++ return MP_VAL;
++ }
++
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ /* reallocate the array a->dp
+--- a/libtommath/bn_mp_init_size.c
++++ b/libtommath/bn_mp_init_size.c
+@@ -6,6 +6,11 @@
+ /* init an mp_init for a given size */
+ mp_err mp_init_size(mp_int *a, int size)
+ {
++
++ if (size < 0) {
++ return MP_VAL;
++ }
++
+ size = MP_MAX(MP_MIN_PREC, size);
+
+ /* alloc mem */
+--- a/libtommath/bn_mp_mul_2d.c
++++ b/libtommath/bn_mp_mul_2d.c
+@@ -9,6 +9,10 @@ mp_err mp_mul_2d(const mp_int *a, int b,
+ mp_digit d;
+ mp_err err;
+
++ if (b < 0) {
++ return MP_VAL;
++ }
++
+ /* copy */
+ if (a != c) {
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+--- a/libtommath/bn_s_mp_mul_digs.c
++++ b/libtommath/bn_s_mp_mul_digs.c
+@@ -16,6 +16,10 @@ mp_err s_mp_mul_digs(const mp_int *a, co
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* can we use the fast multiplier? */
+ if ((digs < MP_WARRAY) &&
+ (MP_MIN(a->used, b->used) < MP_MAXFAST)) {
+--- a/libtommath/bn_s_mp_mul_digs_fast.c
++++ b/libtommath/bn_s_mp_mul_digs_fast.c
+@@ -26,6 +26,10 @@ mp_err s_mp_mul_digs_fast(const mp_int *
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* grow the destination as required */
+ if (c->alloc < digs) {
+ if ((err = mp_grow(c, digs)) != MP_OKAY) {
+--- a/libtommath/bn_s_mp_mul_high_digs.c
++++ b/libtommath/bn_s_mp_mul_high_digs.c
+@@ -15,6 +15,10 @@ mp_err s_mp_mul_high_digs(const mp_int *
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* can we use the fast multiplier? */
+ if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)
+ && ((a->used + b->used + 1) < MP_WARRAY)
+--- a/libtommath/bn_s_mp_mul_high_digs_fast.c
++++ b/libtommath/bn_s_mp_mul_high_digs_fast.c
+@@ -19,6 +19,10 @@ mp_err s_mp_mul_high_digs_fast(const mp_
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* grow the destination as required */
+ pa = a->used + b->used;
+ if (c->alloc < pa) {
diff --git a/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch b/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch
new file mode 100644
index 00000000000..b6933120e6f
--- /dev/null
+++ b/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch
@@ -0,0 +1,35 @@
+From 3cf8344769eda55e26eee53c1898b2c66544f188 Mon Sep 17 00:00:00 2001
+From: Justin Chen <justin.chen@broadcom.com>
+Date: Fri, 8 Sep 2023 11:35:18 -0700
+Subject: src: svr-tcpfwd: Fix noremotetcp behavior
+
+If noremotetcp is set, we should still reply with
+send_msg_request_failed. This matches the behavior
+of !DROPBEAR_SVR_REMOTETCPFWD.
+
+We were seeing keepalive packets being ignored when
+the "-k" option was used.
+---
+ svr-tcpfwd.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/svr-tcpfwd.c
++++ b/svr-tcpfwd.c
+@@ -79,14 +79,14 @@ void recv_msg_global_request_remotetcp()
+
+ TRACE(("enter recv_msg_global_request_remotetcp"))
+
++ reqname = buf_getstring(ses.payload, &namelen);
++ wantreply = buf_getbool(ses.payload);
++
+ if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) {
+ TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
+ goto out;
+ }
+
+- reqname = buf_getstring(ses.payload, &namelen);
+- wantreply = buf_getbool(ses.payload);
+-
+ if (namelen > MAX_NAME_LEN) {
+ TRACE(("name len is wrong: %d", namelen))
+ goto out;
diff --git a/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch b/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch
new file mode 100644
index 00000000000..603c61d6fb1
--- /dev/null
+++ b/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch
@@ -0,0 +1,32 @@
+From e28ba1b9975eab48799aa3ed77d3cd91627d7b27 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sat, 9 Dec 2023 23:10:41 +0800
+Subject: Don't try to shutdown() a pty
+
+shutdown() of a pty doesn't work (ENOTSOCK), so we should close
+it instead.
+
+This will ensure that PTY controlling terminals are closed when a
+session exits, including when multiple sessions run over a single SSH
+connection. In the normal case of a single session, the PTY controlling
+terminal would be closed when the Dropbear server process exits anyway.
+
+This possibly fixes #264 on github
+
+It is possible that there could be subtle changes to PTY flushing
+behaviour, though nothing caught by tests at present.
+---
+ svr-chansession.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/svr-chansession.c
++++ b/svr-chansession.c
+@@ -910,7 +910,7 @@ static int ptycommand(struct Channel *ch
+ channel->readfd = chansess->master;
+ /* don't need to set stderr here */
+ ses.maxfd = MAX(ses.maxfd, chansess->master);
+- channel->bidir_fd = 1;
++ channel->bidir_fd = 0;
+
+ setnonblocking(chansess->master);
+
diff --git a/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch b/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch
new file mode 100644
index 00000000000..9c70c3141c8
--- /dev/null
+++ b/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch
@@ -0,0 +1,33 @@
+From 806586b585806cbe32013bcd3af3847278972060 Mon Sep 17 00:00:00 2001
+From: Sergey Ponomarev <stokito@gmail.com>
+Date: Sun, 10 Dec 2023 10:31:56 +0200
+Subject: dropbearkey: add alias to ssh-keygen
+
+The dropbearkey is partially compatible with ssh-keygen and can be used as an alias.
+
+Closes: #263
+---
+ dbmulti.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/dbmulti.c
++++ b/dbmulti.c
+@@ -41,7 +41,8 @@ static int runprog(const char *multipath
+ }
+ #endif
+ #ifdef DBMULTI_dropbearkey
+- if (strcmp(progname, "dropbearkey") == 0) {
++ if (strcmp(progname, "dropbearkey") == 0
++ || strcmp(progname, "ssh-keygen") == 0) {
+ return dropbearkey_main(argc, argv);
+ }
+ #endif
+@@ -88,7 +89,7 @@ int main(int argc, char ** argv) {
+ "'dbclient' or 'ssh' - the Dropbear client\n"
+ #endif
+ #ifdef DBMULTI_dropbearkey
+- "'dropbearkey' - the key generator\n"
++ "'dropbearkey' or 'ssh-keygen' - the key generator\n"
+ #endif
+ #ifdef DBMULTI_dropbearconvert
+ "'dropbearconvert' - the key converter\n"
diff --git a/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch b/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch
new file mode 100644
index 00000000000..3544f2123c6
--- /dev/null
+++ b/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch
@@ -0,0 +1,34 @@
+From 383cc8c97a9420aad9cf93d88e77ec636b183a9d Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 11 Dec 2023 23:18:09 +0800
+Subject: Allow inetd with non-syslog
+
+An inetd-alike should be able to distinguish stdout and stderr, so
+it's a valid configuration.
+
+Fixes #218 on github
+---
+ svr-runopts.c | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -443,18 +443,6 @@ void svr_getopts(int argc, char ** argv)
+ }
+ }
+
+-#if INETD_MODE
+- if (svr_opts.inetdmode && (
+- opts.usingsyslog == 0
+-#if DEBUG_TRACE
+- || debug_trace
+-#endif
+- )) {
+- /* log output goes to stderr which would get sent over the inetd network socket */
+- dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog");
+- }
+-#endif
+-
+ if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
+ dropbear_exit("-t and -s are incompatible");
+ }
diff --git a/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch b/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch
new file mode 100644
index 00000000000..8d016faa9c7
--- /dev/null
+++ b/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch
@@ -0,0 +1,33 @@
+From 9ac650401ffc2fb05c9328d26e76a5e7ae39152a Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 11 Dec 2023 23:31:22 +0800
+Subject: Fix test for multiuser kernels
+
+getuid() succeeds even on non-multiuser kernels. Instead
+getgroups() is a valid test.
+
+Fixes #214 on github
+---
+ common-session.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/common-session.c
++++ b/common-session.c
+@@ -71,10 +71,13 @@ void common_session_init(int sock_in, in
+ #if !DROPBEAR_SVR_MULTIUSER
+ /* A sanity check to prevent an accidental configuration option
+ leaving multiuser systems exposed */
+- errno = 0;
+- getuid();
+- if (errno != ENOSYS) {
+- dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
++ {
++ int ret;
++ errno = 0;
++ ret = getgroups(0, NULL);
++ if (!(ret == -1 && errno == ENOSYS)) {
++ dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
++ }
+ }
+ #endif
+
diff --git a/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch b/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch
new file mode 100644
index 00000000000..d490d9545a2
--- /dev/null
+++ b/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch
@@ -0,0 +1,216 @@
+From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 20 Nov 2023 14:02:47 +0800
+Subject: Implement Strict KEX mode
+
+As specified by OpenSSH with kex-strict-c-v00@openssh.com and
+kex-strict-s-v00@openssh.com.
+---
+ cli-session.c | 11 +++++++++++
+ common-algo.c | 6 ++++++
+ common-kex.c | 26 +++++++++++++++++++++++++-
+ kex.h | 3 +++
+ process-packet.c | 34 +++++++++++++++++++---------------
+ ssh.h | 4 ++++
+ svr-session.c | 3 +++
+ 7 files changed, 71 insertions(+), 16 deletions(-)
+
+--- a/cli-session.c
++++ b/cli-session.c
+@@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
+ static void recv_msg_service_accept(void);
+ static void cli_session_cleanup(void);
+ static void recv_msg_global_request_cli(void);
++static void cli_algos_initialise(void);
+
+ struct clientsession cli_ses; /* GLOBAL */
+
+@@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
+ }
+
+ chaninitialise(cli_chantypes);
++ cli_algos_initialise();
+
+ /* Set up cli_ses vars */
+ cli_session_init(proxy_cmd_pid);
+@@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
+ fflush(stderr);
+ }
+
++static void cli_algos_initialise(void) {
++ algo_type *algo;
++ for (algo = sshkex; algo->name; algo++) {
++ if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
++ algo->usable = 0;
++ }
++ }
++}
++
+--- a/common-algo.c
++++ b/common-algo.c
+@@ -308,6 +308,12 @@ algo_type sshkex[] = {
+ {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
+ #endif
+ #endif
++#if DROPBEAR_CLIENT
++ {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
++#endif
++#if DROPBEAR_SERVER
++ {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
++#endif
+ {NULL, 0, NULL, 0, NULL}
+ };
+
+--- a/common-kex.c
++++ b/common-kex.c
+@@ -183,6 +183,10 @@ void send_msg_newkeys() {
+ gen_new_keys();
+ switch_keys();
+
++ if (ses.kexstate.strict_kex) {
++ ses.transseq = 0;
++ }
++
+ TRACE(("leave send_msg_newkeys"))
+ }
+
+@@ -193,7 +197,11 @@ void recv_msg_newkeys() {
+
+ ses.kexstate.recvnewkeys = 1;
+ switch_keys();
+-
++
++ if (ses.kexstate.strict_kex) {
++ ses.recvseq = 0;
++ }
++
+ TRACE(("leave recv_msg_newkeys"))
+ }
+
+@@ -550,6 +558,10 @@ void recv_msg_kexinit() {
+
+ ses.kexstate.recvkexinit = 1;
+
++ if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
++ dropbear_exit("First packet wasn't kexinit");
++ }
++
+ TRACE(("leave recv_msg_kexinit"))
+ }
+
+@@ -859,6 +871,18 @@ static void read_kex_algos() {
+ }
+ #endif
+
++ if (!ses.kexstate.donefirstkex) {
++ const char* strict_name;
++ if (IS_DROPBEAR_CLIENT) {
++ strict_name = SSH_STRICT_KEX_S;
++ } else {
++ strict_name = SSH_STRICT_KEX_C;
++ }
++ if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
++ ses.kexstate.strict_kex = 1;
++ }
++ }
++
+ algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
+ allgood &= goodguess;
+ if (algo == NULL || algo->data == NULL) {
+--- a/kex.h
++++ b/kex.h
+@@ -83,6 +83,9 @@ struct KEXState {
+
+ unsigned our_first_follows_matches : 1;
+
++ /* Boolean indicating that strict kex mode is in use */
++ unsigned int strict_kex;
++
+ time_t lastkextime; /* time of the last kex */
+ unsigned int datatrans; /* data transmitted since last kex */
+ unsigned int datarecv; /* data received since last kex */
+--- a/process-packet.c
++++ b/process-packet.c
+@@ -44,6 +44,7 @@ void process_packet() {
+
+ unsigned char type;
+ unsigned int i;
++ unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
+ time_t now;
+
+ TRACE2(("enter process_packet"))
+@@ -54,22 +55,24 @@ void process_packet() {
+ now = monotonic_now();
+ ses.last_packet_time_keepalive_recv = now;
+
+- /* These packets we can receive at any time */
+- switch(type) {
+
+- case SSH_MSG_IGNORE:
+- goto out;
+- case SSH_MSG_DEBUG:
+- goto out;
+-
+- case SSH_MSG_UNIMPLEMENTED:
+- /* debugging XXX */
+- TRACE(("SSH_MSG_UNIMPLEMENTED"))
+- goto out;
+-
+- case SSH_MSG_DISCONNECT:
+- /* TODO cleanup? */
+- dropbear_close("Disconnect received");
++ if (type == SSH_MSG_DISCONNECT) {
++ /* Allowed at any time */
++ dropbear_close("Disconnect received");
++ }
++
++ /* These packets may be received at any time,
++ except during first kex with strict kex */
++ if (!first_strict_kex) {
++ switch(type) {
++ case SSH_MSG_IGNORE:
++ goto out;
++ case SSH_MSG_DEBUG:
++ goto out;
++ case SSH_MSG_UNIMPLEMENTED:
++ TRACE(("SSH_MSG_UNIMPLEMENTED"))
++ goto out;
++ }
+ }
+
+ /* Ignore these packet types so that keepalives don't interfere with
+@@ -98,7 +101,8 @@ void process_packet() {
+ if (type >= 1 && type <= 49
+ && type != SSH_MSG_SERVICE_REQUEST
+ && type != SSH_MSG_SERVICE_ACCEPT
+- && type != SSH_MSG_KEXINIT)
++ && type != SSH_MSG_KEXINIT
++ && !first_strict_kex)
+ {
+ TRACE(("unknown allowed packet during kexinit"))
+ recv_unimplemented();
+--- a/ssh.h
++++ b/ssh.h
+@@ -100,6 +100,10 @@
+ #define SSH_EXT_INFO_C "ext-info-c"
+ #define SSH_SERVER_SIG_ALGS "server-sig-algs"
+
++/* OpenSSH strict KEX feature */
++#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com"
++#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com"
++
+ /* service types */
+ #define SSH_SERVICE_USERAUTH "ssh-userauth"
+ #define SSH_SERVICE_USERAUTH_LEN 12
+--- a/svr-session.c
++++ b/svr-session.c
+@@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
+ algo->usable = 0;
+ }
+ #endif
++ if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
++ algo->usable = 0;
++ }
+ }
+ }
+
diff --git a/package/network/services/dropbear/patches/100-pubkey_path.patch b/package/network/services/dropbear/patches/100-pubkey_path.patch
index af3fbb336bf..b1075f84642 100644
--- a/package/network/services/dropbear/patches/100-pubkey_path.patch
+++ b/package/network/services/dropbear/patches/100-pubkey_path.patch
@@ -1,34 +1,50 @@
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
-@@ -386,14 +386,19 @@ static int checkpubkey(const char* keyal
- goto out;
- }
+@@ -78,6 +78,13 @@ static void send_msg_userauth_pk_ok(cons
+ const unsigned char* keyblob, unsigned int keybloblen);
+ static int checkfileperm(char * filename);
-- /* we don't need to check pw and pw_dir for validity, since
-- * its been done in checkpubkeyperms. */
-- len = strlen(ses.authstate.pw_dir);
-- /* allocate max required pathname storage,
-- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
-- filename = m_malloc(len + 22);
-- snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
-- ses.authstate.pw_dir);
-+ if (ses.authstate.pw_uid != 0) {
-+ /* we don't need to check pw and pw_dir for validity, since
-+ * its been done in checkpubkeyperms. */
-+ len = strlen(ses.authstate.pw_dir);
-+ /* allocate max required pathname storage,
-+ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
-+ filename = m_malloc(len + 22);
-+ snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
-+ ses.authstate.pw_dir);
-+ } else {
-+ filename = m_malloc(30);
-+ strncpy(filename, "/etc/dropbear/authorized_keys", 30);
-+ }
++static const char * const global_authkeys_dir = "/etc/dropbear";
++static const int n_global_authkeys_dir = 14; /* + 1 extra byte */
++static const char * const user_authkeys_dir = ".ssh";
++static const int n_user_authkeys_dir = 5; /* + 1 extra byte */
++static const char * const authkeys_file = "authorized_keys";
++static const int n_authkeys_file = 16; /* + 1 extra byte */
++
+ /* process a pubkey auth request, sending success or failure message as
+ * appropriate */
+ void svr_auth_pubkey(int valid_user) {
+@@ -462,14 +469,21 @@ static int checkpubkey(const char* keyal
+ if (checkpubkeyperms() == DROPBEAR_FAILURE) {
+ TRACE(("bad authorized_keys permissions, or file doesn't exist"))
+ } else {
+- /* we don't need to check pw and pw_dir for validity, since
+- * its been done in checkpubkeyperms. */
+- len = strlen(ses.authstate.pw_dir);
+- /* allocate max required pathname storage,
+- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
+- filename = m_malloc(len + 22);
+- snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
+- ses.authstate.pw_dir);
++ if (ses.authstate.pw_uid == 0) {
++ len = n_global_authkeys_dir + n_authkeys_file;
++ filename = m_malloc(len);
++ snprintf(filename, len, "%s/%s", global_authkeys_dir, authkeys_file);
++ } else {
++ /* we don't need to check pw and pw_dir for validity, since
++ * its been done in checkpubkeyperms. */
++ len = strlen(ses.authstate.pw_dir);
++ /* allocate max required pathname storage,
++ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
++ len += n_user_authkeys_dir + n_authkeys_file + 1;
++ filename = m_malloc(len);
++ snprintf(filename, len, "%s/%s/%s", ses.authstate.pw_dir,
++ user_authkeys_dir, authkeys_file);
++ }
- #if DROPBEAR_SVR_MULTIUSER
- /* open the file as the authenticating user. */
-@@ -474,27 +479,36 @@ static int checkpubkeyperms() {
+ authfile = fopen(filename, "r");
+ if (!authfile) {
+@@ -543,27 +557,41 @@ static int checkpubkeyperms() {
goto out;
}
@@ -37,47 +53,51 @@
- len += 22;
- filename = m_malloc(len);
- strlcpy(filename, ses.authstate.pw_dir, len);
--
++ if (ses.authstate.pw_uid == 0) {
++ if (checkfileperm(global_authkeys_dir) != DROPBEAR_SUCCESS) {
++ goto out;
++ }
+
- /* check ~ */
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-+ if (ses.authstate.pw_uid == 0) {
-+ if (checkfileperm("/etc/dropbear") != DROPBEAR_SUCCESS) {
-+ goto out;
-+ }
-+ if (checkfileperm("/etc/dropbear/authorized_keys") != DROPBEAR_SUCCESS) {
-+ goto out;
-+ }
-+ } else {
-+ /* allocate max required pathname storage,
-+ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
-+ len += 22;
++ len = n_global_authkeys_dir + n_authkeys_file;
+ filename = m_malloc(len);
-+ strlcpy(filename, ses.authstate.pw_dir, len);
-+
-+ /* check ~ */
-+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
-+ goto out;
-+ }
- /* check ~/.ssh */
- strlcat(filename, "/.ssh", len);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-+ /* check ~/.ssh */
-+ strlcat(filename, "/.ssh", len);
++ snprintf(filename, len, "%s/%s", global_authkeys_dir, authkeys_file);
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
++ } else {
++ /* check ~ */
++ if (checkfileperm(ses.authstate.pw_dir) != DROPBEAR_SUCCESS) {
++ goto out;
++ }
- /* now check ~/.ssh/authorized_keys */
- strlcat(filename, "/authorized_keys", len);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
++ /* allocate max required pathname storage,
++ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
++ len += n_user_authkeys_dir + n_authkeys_file + 1;
++ filename = m_malloc(len);
++
++ /* check ~/.ssh */
++ snprintf(filename, len, "%s/%s", ses.authstate.pw_dir, user_authkeys_dir);
++ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
++ goto out;
++ }
++
+ /* now check ~/.ssh/authorized_keys */
-+ strlcat(filename, "/authorized_keys", len);
++ snprintf(filename, len, "%s/%s/%s", ses.authstate.pw_dir,
++ user_authkeys_dir, authkeys_file);
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
diff --git a/package/network/services/dropbear/patches/110-change_user.patch b/package/network/services/dropbear/patches/110-change_user.patch
index 1dd67948af6..04d1df3fdeb 100644
--- a/package/network/services/dropbear/patches/110-change_user.patch
+++ b/package/network/services/dropbear/patches/110-change_user.patch
@@ -1,6 +1,6 @@
--- a/svr-chansession.c
+++ b/svr-chansession.c
-@@ -954,12 +954,12 @@ static void execchild(const void *user_d
+@@ -985,12 +985,12 @@ static void execchild(const void *user_d
/* We can only change uid/gid as root ... */
if (getuid() == 0) {
diff --git a/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
index 5e736320cc7..a26f33dfbce 100644
--- a/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
+++ b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
@@ -1,11 +1,13 @@
--- a/cli-runopts.c
+++ b/cli-runopts.c
-@@ -299,6 +299,8 @@ void cli_getopts(int argc, char ** argv)
- debug_trace = 1;
+@@ -329,6 +329,10 @@ void cli_getopts(int argc, char ** argv)
+ case 'z':
+ opts.disable_ip_tos = 1;
break;
- #endif
+ case 'x':
++ /* compatibility with openssh cli
++ * ("-x" disables X11 forwarding) */
+ break;
- case 'F':
- case 'e':
- #if !DROPBEAR_USER_ALGO_LIST
+ default:
+ fprintf(stderr,
+ "WARNING: Ignoring unknown option -%c\n", c);
diff --git a/package/network/services/dropbear/patches/140-disable_assert.patch b/package/network/services/dropbear/patches/140-disable_assert.patch
index 8c3ae7f1192..af01573dee5 100644
--- a/package/network/services/dropbear/patches/140-disable_assert.patch
+++ b/package/network/services/dropbear/patches/140-disable_assert.patch
@@ -1,6 +1,6 @@
--- a/dbutil.h
+++ b/dbutil.h
-@@ -75,7 +75,11 @@ int m_str_to_uint(const char* str, unsig
+@@ -80,7 +80,11 @@ int m_snprintf(char *str, size_t size, c
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
/* Dropbear assertion */
diff --git a/package/network/services/dropbear/patches/160-lto-jobserver.patch b/package/network/services/dropbear/patches/160-lto-jobserver.patch
index 1ba7dd6f442..fd80b986ae2 100644
--- a/package/network/services/dropbear/patches/160-lto-jobserver.patch
+++ b/package/network/services/dropbear/patches/160-lto-jobserver.patch
@@ -1,6 +1,6 @@
--- a/Makefile.in
+++ b/Makefile.in
-@@ -198,17 +198,17 @@ dropbearkey: $(dropbearkeyobjs)
+@@ -200,17 +200,17 @@ dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
@@ -22,7 +22,7 @@
# multi-binary compilation.
-@@ -219,7 +219,7 @@ ifeq ($(MULTI),1)
+@@ -221,7 +221,7 @@ ifeq ($(MULTI),1)
endif
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
diff --git a/package/network/services/dropbear/patches/600-allow-blank-root-password.patch b/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
index b138862ca31..07ae0227631 100644
--- a/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
+++ b/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
@@ -1,6 +1,6 @@
--- a/svr-auth.c
+++ b/svr-auth.c
-@@ -125,7 +125,7 @@ void recv_msg_userauth_request() {
+@@ -124,7 +124,7 @@ void recv_msg_userauth_request() {
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
if (valid_user
diff --git a/package/network/services/dropbear/patches/900-configure-hardening.patch b/package/network/services/dropbear/patches/900-configure-hardening.patch
index ab1361f6ae8..5dc84849bef 100644
--- a/package/network/services/dropbear/patches/900-configure-hardening.patch
+++ b/package/network/services/dropbear/patches/900-configure-hardening.patch
@@ -1,6 +1,6 @@
--- a/configure.ac
+++ b/configure.ac
-@@ -70,53 +70,6 @@ AC_ARG_ENABLE(harden,
+@@ -87,54 +87,6 @@ AC_ARG_ENABLE(harden,
if test "$hardenbuild" -eq 1; then
AC_MSG_NOTICE(Checking for available hardened build flags:)
@@ -11,15 +11,15 @@
-
- OLDLDFLAGS="$LDFLAGS"
- TESTFLAGS="-Wl,-pie"
-- LDFLAGS="$LDFLAGS $TESTFLAGS"
-- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- LDFLAGS="$TESTFLAGS $LDFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [
- LDFLAGS="$OLDLDFLAGS"
- TESTFLAGS="-pie"
-- LDFLAGS="$LDFLAGS $TESTFLAGS"
-- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- LDFLAGS="$TESTFLAGS $LDFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
- )
- ]
@@ -27,30 +27,31 @@
- # readonly elf relocation sections (relro)
- OLDLDFLAGS="$LDFLAGS"
- TESTFLAGS="-Wl,-z,now -Wl,-z,relro"
-- LDFLAGS="$LDFLAGS $TESTFLAGS"
-- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- LDFLAGS="$TESTFLAGS $LDFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
- )
- fi # non-static
- # stack protector. -strong is good but only in gcc 4.9 or later
- OLDCFLAGS="$CFLAGS"
- TESTFLAGS="-fstack-protector-strong"
-- CFLAGS="$CFLAGS $TESTFLAGS"
-- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- CFLAGS="$TESTFLAGS $CFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [
- CFLAGS="$OLDCFLAGS"
- TESTFLAGS="-fstack-protector --param=ssp-buffer-size=4"
-- CFLAGS="$CFLAGS $TESTFLAGS"
-- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- CFLAGS="$TESTFLAGS $CFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDCFLAGS" ]
- )
- ]
- )
- # FORTIFY_SOURCE
- DB_TRYADDCFLAGS([-D_FORTIFY_SOURCE=2])
-
+-
# Spectre v2 mitigations
DB_TRYADDCFLAGS([-mfunction-return=thunk])
+ DB_TRYADDCFLAGS([-mindirect-branch=thunk])
diff --git a/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch b/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch
index 2432b4ef72e..a9a441ce76e 100644
--- a/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch
+++ b/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch
@@ -1,48 +1,29 @@
---- a/libtomcrypt/makefile_include.mk
-+++ b/libtomcrypt/makefile_include.mk
-@@ -94,6 +94,13 @@ endif
+--- a/configure.ac
++++ b/configure.ac
+@@ -45,11 +45,8 @@ fi
+ # LTM_CFLAGS is given to ./configure by the user,
+ # DROPBEAR_LTM_CFLAGS is substituted in the LTM Makefile.in
+ DROPBEAR_LTM_CFLAGS="$LTM_CFLAGS"
+-if test -z "$DROPBEAR_LTM_CFLAGS"; then
+- DROPBEAR_LTM_CFLAGS="-O3 -funroll-loops -fomit-frame-pointer"
+-fi
+-AC_MSG_NOTICE(Setting LTM_CFLAGS to $DROPBEAR_LTM_CFLAGS)
+-AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Default -O3 -funroll-loops -fomit-frame-pointer)
++AC_MSG_NOTICE(Setting LTM_CFLAGS to '$DROPBEAR_LTM_CFLAGS')
++AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Defaults to empty string)
+ AC_SUBST(DROPBEAR_LTM_CFLAGS)
- LTC_CFLAGS += -Wno-type-limits
+ AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wno-pointer-sign])
+--- a/libtomcrypt/src/headers/tomcrypt_dropbear.h
++++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h
+@@ -7,8 +7,10 @@
-+ifdef OPENWRT_BUILD
-+ ifeq (-Os,$(filter -Os,$(CFLAGS)))
-+ LTC_CFLAGS += -DLTC_SMALL_CODE
-+ endif
-+else
-+ ### ! OPENWRT_BUILD
-+
- ifdef LTC_DEBUG
- $(info Debug build)
- # compile for DEBUGGING (required for ccmalloc checking!!!)
-@@ -121,6 +128,9 @@ endif
- endif # COMPILE_SMALL
- endif # COMPILE_DEBUG
+ /* Use small code where possible */
+ #if DROPBEAR_SMALL_CODE
++#ifndef LTC_SMALL_CODE
+ #define LTC_SMALL_CODE
+ #endif
++#endif
-+ ### ! OPENWRT_BUILD
-+endif
-+
-
- ifneq ($(findstring clang,$(CC)),)
- LTC_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header -Wno-missing-field-initializers
---- a/libtommath/makefile_include.mk
-+++ b/libtommath/makefile_include.mk
-@@ -70,6 +70,9 @@ else
- LTM_CFLAGS += -Wsystem-headers
- endif
-
-+ifndef OPENWRT_BUILD
-+ ### ! OPENWRT_BUILD
-+
- ifdef COMPILE_DEBUG
- #debug
- LTM_CFLAGS += -g3
-@@ -90,6 +93,9 @@ endif
-
- endif # COMPILE_SIZE
-
-+ ### ! OPENWRT_BUILD
-+endif
-+
- ifneq ($(findstring clang,$(CC)),)
- LTM_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header
- endif
+ /* Fewer entries needed */
+ #define TAB_SIZE 5
diff --git a/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch b/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch
index b774a38b1aa..059177a1c58 100644
--- a/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch
+++ b/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch
@@ -21,7 +21,7 @@ Signed-off-by: Petr Å tetiar <ynezz@true.cz>
--- a/signkey.c
+++ b/signkey.c
-@@ -657,8 +657,12 @@ int buf_verify(buffer * buf, sign_key *k
+@@ -652,10 +652,18 @@ int buf_verify(buffer * buf, sign_key *k
sigtype = signature_type_from_name(type_name, type_name_len);
m_free(type_name);
@@ -29,10 +29,16 @@ Signed-off-by: Petr Å tetiar <ynezz@true.cz>
- dropbear_exit("Non-matching signing type");
+ if (sigtype == DROPBEAR_SIGNATURE_NONE) {
+ dropbear_exit("No signature type");
-+ }
-+
-+ if ((expect_sigtype != DROPBEAR_SIGNATURE_RSA_SHA256) && (expect_sigtype != sigtype)) {
-+ dropbear_exit("Non-matching signing type");
}
++#if DROPBEAR_RSA
++#if DROPBEAR_RSA_SHA256
++ if ((expect_sigtype != DROPBEAR_SIGNATURE_RSA_SHA256) && (expect_sigtype != sigtype)) {
++ dropbear_exit("Non-matching signing type");
++ }
++#endif
++#endif
++
keytype = signkey_type_from_signature(sigtype);
+ #if DROPBEAR_DSS
+ if (keytype == DROPBEAR_SIGNKEY_DSS) {
diff --git a/package/network/services/hostapd/Config.in b/package/network/services/hostapd/Config.in
index 5c00f3e24ea..87ad7e093e7 100644
--- a/package/network/services/hostapd/Config.in
+++ b/package/network/services/hostapd/Config.in
@@ -4,20 +4,25 @@ config WPA_RFKILL_SUPPORT
depends on PACKAGE_wpa-supplicant || \
PACKAGE_wpa-supplicant-openssl || \
PACKAGE_wpa-supplicant-wolfssl || \
+ PACKAGE_wpa-supplicant-mbedtls || \
PACKAGE_wpa-supplicant-mesh-openssl || \
PACKAGE_wpa-supplicant-mesh-wolfssl || \
+ PACKAGE_wpa-supplicant-mesh-mbedtls || \
PACKAGE_wpa-supplicant-basic || \
PACKAGE_wpa-supplicant-mini || \
PACKAGE_wpa-supplicant-p2p || \
PACKAGE_wpad || \
PACKAGE_wpad-openssl || \
PACKAGE_wpad-wolfssl || \
+ PACKAGE_wpad-mbedtls || \
PACKAGE_wpad-basic || \
PACKAGE_wpad-basic-openssl || \
PACKAGE_wpad-basic-wolfssl || \
+ PACKAGE_wpad-basic-mbedtls || \
PACKAGE_wpad-mini || \
PACKAGE_wpad-mesh-openssl || \
- PACKAGE_wpad-mesh-wolfssl
+ PACKAGE_wpad-mesh-wolfssl || \
+ PACKAGE_wpad-mesh-mbedtls
default n
config WPA_MSG_MIN_PRIORITY
@@ -25,20 +30,25 @@ config WPA_MSG_MIN_PRIORITY
depends on PACKAGE_wpa-supplicant || \
PACKAGE_wpa-supplicant-openssl || \
PACKAGE_wpa-supplicant-wolfssl || \
+ PACKAGE_wpa-supplicant-mbedtls || \
PACKAGE_wpa-supplicant-mesh-openssl || \
PACKAGE_wpa-supplicant-mesh-wolfssl || \
+ PACKAGE_wpa-supplicant-mesh-mbedtls || \
PACKAGE_wpa-supplicant-basic || \
PACKAGE_wpa-supplicant-mini || \
PACKAGE_wpa-supplicant-p2p || \
PACKAGE_wpad || \
PACKAGE_wpad-openssl || \
PACKAGE_wpad-wolfssl || \
+ PACKAGE_wpad-mbedtls || \
PACKAGE_wpad-basic || \
PACKAGE_wpad-basic-openssl || \
PACKAGE_wpad-basic-wolfssl || \
+ PACKAGE_wpad-basic-mbedtls || \
PACKAGE_wpad-mini || \
PACKAGE_wpad-mesh-openssl || \
- PACKAGE_wpad-mesh-wolfssl
+ PACKAGE_wpad-mesh-wolfssl || \
+ PACKAGE_wpad-mesh-mbedtls
default 3
help
Useful values are:
@@ -63,14 +73,6 @@ config WPA_WOLFSSL
select WOLFSSL_HAS_SESSION_TICKET
select WOLFSSL_HAS_WPAS
-config DRIVER_WEXT_SUPPORT
- bool
- default n
-
-config DRIVER_11N_SUPPORT
- bool
- default n
-
config DRIVER_11AC_SUPPORT
bool
default n
@@ -78,6 +80,7 @@ config DRIVER_11AC_SUPPORT
config DRIVER_11AX_SUPPORT
bool
default n
+ select WPA_MBO_SUPPORT
config WPA_ENABLE_WEP
bool "Enable support for unsecure and obsolete WEP"
@@ -87,3 +90,19 @@ config WPA_ENABLE_WEP
for anything anymore. The functionality needed to use WEP is available in the
current hostapd release under this optional build parameter and completely
removed in a future release.
+
+config WPA_MBO_SUPPORT
+ bool "Multi Band Operation (Agile Multiband)"
+ default PACKAGE_wpa-supplicant || \
+ PACKAGE_wpa-supplicant-openssl || \
+ PACKAGE_wpa-supplicant-wolfssl || \
+ PACKAGE_wpa-supplicant-mbedtls || \
+ PACKAGE_wpad || \
+ PACKAGE_wpad-openssl || \
+ PACKAGE_wpad-wolfssl || \
+ PACKAGE_wpad-mbedtls
+ help
+ Multi Band Operation aka (Agile Multiband) enables features
+ that facilitate efficient use of multiple frequency bands.
+ Enabling MBO on an AP using RSN requires 802.11w to be enabled.
+ Hostapd will refuse to start if MBO and RSN are enabled without 11w.
diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile
index fee6889b408..c8f476f7b8c 100644
--- a/package/network/services/hostapd/Makefile
+++ b/package/network/services/hostapd/Makefile
@@ -5,13 +5,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hostapd
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=6
PKG_SOURCE_URL:=http://w1.fi/hostap.git
PKG_SOURCE_PROTO:=git
-PKG_SOURCE_DATE:=2021-05-22
-PKG_SOURCE_VERSION:=b102f19bcc53c7f7db3951424d4d46709b4f1986
-PKG_MIRROR_HASH:=cb3cb968883042fc582752be1607586696c18e6ecf9808c9a8ac50e204584367
+PKG_SOURCE_DATE:=2023-09-08
+PKG_SOURCE_VERSION:=e5ccbfc69ecf297590341ae8b461edba9d8e964c
+PKG_MIRROR_HASH:=fcc6550f46c7f8bbdbf71e63f8f699b9a0878565ad1b90a17855f5ec21283b8f
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=BSD-3-Clause
@@ -21,18 +21,16 @@ PKG_BUILD_PARALLEL:=1
PKG_ASLR_PIE_REGULAR:=1
PKG_CONFIG_DEPENDS:= \
- CONFIG_PACKAGE_kmod-ath9k \
- CONFIG_PACKAGE_kmod-cfg80211 \
CONFIG_PACKAGE_hostapd \
CONFIG_PACKAGE_hostapd-basic \
CONFIG_PACKAGE_hostapd-mini \
CONFIG_WPA_RFKILL_SUPPORT \
- CONFIG_DRIVER_WEXT_SUPPORT \
- CONFIG_DRIVER_11N_SUPPORT \
CONFIG_DRIVER_11AC_SUPPORT \
CONFIG_DRIVER_11AX_SUPPORT \
CONFIG_WPA_ENABLE_WEP
+PKG_BUILD_FLAGS:=gc-sections lto
+
EAPOL_TEST_PROVIDERS:=eapol-test eapol-test-openssl eapol-test-wolfssl
SUPPLICANT_PROVIDERS:=
@@ -53,14 +51,16 @@ LOCAL_AND_LIB_VARIANT=$(patsubst hostapd-%,%,\
LOCAL_VARIANT=$(patsubst %-internal,%,\
$(patsubst %-openssl,%,\
$(patsubst %-wolfssl,%,\
+ $(patsubst %-mbedtls,%,\
$(LOCAL_AND_LIB_VARIANT)\
- )))
+ ))))
SSL_VARIANT=$(strip \
$(if $(findstring openssl,$(LOCAL_AND_LIB_VARIANT)),openssl,\
$(if $(findstring wolfssl,$(LOCAL_AND_LIB_VARIANT)),wolfssl,\
+ $(if $(findstring mbedtls,$(LOCAL_AND_LIB_VARIANT)),mbedtls,\
internal\
- )))
+ ))))
CONFIG_VARIANT:=$(LOCAL_VARIANT)
ifeq ($(LOCAL_VARIANT),mesh)
@@ -71,11 +71,6 @@ include $(INCLUDE_DIR)/package.mk
STAMP_CONFIGURED:=$(STAMP_CONFIGURED)_$(CONFIG_WPA_MSG_MIN_PRIORITY)
-
-ifneq ($(CONFIG_DRIVER_11N_SUPPORT),)
- HOSTAPD_IEEE80211N:=y
-endif
-
ifneq ($(CONFIG_DRIVER_11AC_SUPPORT),)
HOSTAPD_IEEE80211AC:=y
endif
@@ -84,13 +79,15 @@ ifneq ($(CONFIG_DRIVER_11AX_SUPPORT),)
HOSTAPD_IEEE80211AX:=y
endif
+CORE_DEPENDS = +ucode +libubus +libucode +ucode-mod-fs +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uloop +libblobmsg-json +libudebug
+OPENSSL_DEPENDS = +PACKAGE_$(1):libopenssl +PACKAGE_$(1):libopenssl-legacy
+
DRIVER_MAKEOPTS= \
- CONFIG_ACS=$(CONFIG_PACKAGE_kmod-cfg80211) \
- CONFIG_DRIVER_NL80211=$(CONFIG_PACKAGE_kmod-cfg80211) \
- CONFIG_IEEE80211N=$(HOSTAPD_IEEE80211N) \
+ CONFIG_ACS=y CONFIG_DRIVER_NL80211=y \
CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
- CONFIG_DRIVER_WEXT=$(CONFIG_DRIVER_WEXT_SUPPORT) \
+ CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) \
+ CONFIG_UCODE=y
ifeq ($(SSL_VARIANT),openssl)
DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y
@@ -122,18 +119,28 @@ ifeq ($(SSL_VARIANT),wolfssl)
endif
endif
+ifeq ($(SSL_VARIANT),mbedtls)
+ DRIVER_MAKEOPTS += CONFIG_TLS=mbedtls CONFIG_SAE=y
+ TARGET_LDFLAGS += -lmbedcrypto -lmbedx509 -lmbedtls
+
+ ifeq ($(LOCAL_VARIANT),basic)
+ DRIVER_MAKEOPTS += CONFIG_OWE=y
+ endif
+ ifeq ($(LOCAL_VARIANT),mesh)
+ DRIVER_MAKEOPTS += CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
+ endif
+ ifeq ($(LOCAL_VARIANT),full)
+ DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
+ endif
+endif
+
ifneq ($(LOCAL_TYPE),hostapd)
ifdef CONFIG_WPA_RFKILL_SUPPORT
DRIVER_MAKEOPTS += NEED_RFKILL=y
endif
endif
-ifdef CONFIG_USE_GLIBC
- TARGET_LDFLAGS += -lrt
- TARGET_LDFLAGS_C += -lrt
-endif
-
-DRV_DEPENDS:=+PACKAGE_kmod-cfg80211:libnl-tiny
+DRV_DEPENDS:=+libnl-tiny
define Package/hostapd/Default
@@ -142,7 +149,8 @@ define Package/hostapd/Default
SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Authenticator
URL:=http://hostap.epitest.fi/
- DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus
+ DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
+ EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
PROVIDES:=hostapd
CONFLICTS:=$(HOSTAPD_PROVIDERS)
@@ -164,7 +172,7 @@ define Package/hostapd-openssl
$(call Package/hostapd/Default,$(1))
TITLE+= (OpenSSL full)
VARIANT:=full-openssl
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
endef
Package/hostapd-openssl/description = $(Package/hostapd/description)
@@ -173,11 +181,20 @@ define Package/hostapd-wolfssl
$(call Package/hostapd/Default,$(1))
TITLE+= (wolfSSL full)
VARIANT:=full-wolfssl
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_hostapd-wolfssl:libwolfssl
endef
Package/hostapd-wolfssl/description = $(Package/hostapd/description)
+define Package/hostapd-mbedtls
+$(call Package/hostapd/Default,$(1))
+ TITLE+= (mbedTLS full)
+ VARIANT:=full-mbedtls
+ DEPENDS+=+PACKAGE_hostapd-mbedtls:libmbedtls
+endef
+
+Package/hostapd-mbedtls/description = $(Package/hostapd/description)
+
define Package/hostapd-basic
$(call Package/hostapd/Default,$(1))
TITLE+= (WPA-PSK, 11r, 11w)
@@ -192,7 +209,7 @@ define Package/hostapd-basic-openssl
$(call Package/hostapd/Default,$(1))
TITLE+= (WPA-PSK, 11r and 11w)
VARIANT:=basic-openssl
- DEPENDS+=+libopenssl
+ DEPENDS+=+PACKAGE_hostapd-basic-openssl:libopenssl
endef
define Package/hostapd-basic-openssl/description
@@ -203,13 +220,24 @@ define Package/hostapd-basic-wolfssl
$(call Package/hostapd/Default,$(1))
TITLE+= (WPA-PSK, 11r and 11w)
VARIANT:=basic-wolfssl
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_hostapd-basic-wolfssl:libwolfssl
endef
define Package/hostapd-basic-wolfssl/description
This package contains a basic IEEE 802.1x/WPA Authenticator with WPA-PSK, 802.11r and 802.11w support.
endef
+define Package/hostapd-basic-mbedtls
+$(call Package/hostapd/Default,$(1))
+ TITLE+= (WPA-PSK, 11r and 11w)
+ VARIANT:=basic-mbedtls
+ DEPENDS+=+PACKAGE_hostapd-basic-mbedtls:libmbedtls
+endef
+
+define Package/hostapd-basic-mbedtls/description
+ This package contains a basic IEEE 802.1x/WPA Authenticator with WPA-PSK, 802.11r and 802.11w support.
+endef
+
define Package/hostapd-mini
$(call Package/hostapd/Default,$(1))
TITLE+= (WPA-PSK only)
@@ -226,7 +254,8 @@ define Package/wpad/Default
CATEGORY:=Network
SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Auth/Supplicant
- DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus
+ DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
+ EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
URL:=http://hostap.epitest.fi/
PROVIDES:=hostapd wpa-supplicant
@@ -250,7 +279,7 @@ define Package/wpad-openssl
$(call Package/wpad/Default,$(1))
TITLE+= (OpenSSL full)
VARIANT:=wpad-full-openssl
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
endef
Package/wpad-openssl/description = $(Package/wpad/description)
@@ -259,11 +288,20 @@ define Package/wpad-wolfssl
$(call Package/wpad/Default,$(1))
TITLE+= (wolfSSL full)
VARIANT:=wpad-full-wolfssl
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_wpad-wolfssl:libwolfssl
endef
Package/wpad-wolfssl/description = $(Package/wpad/description)
+define Package/wpad-mbedtls
+$(call Package/wpad/Default,$(1))
+ TITLE+= (mbedTLS full)
+ VARIANT:=wpad-full-mbedtls
+ DEPENDS+=+PACKAGE_wpad-mbedtls:libmbedtls
+endef
+
+Package/wpad-mbedtls/description = $(Package/wpad/description)
+
define Package/wpad-basic
$(call Package/wpad/Default,$(1))
TITLE+= (WPA-PSK, 11r, 11w)
@@ -278,7 +316,7 @@ define Package/wpad-basic-openssl
$(call Package/wpad/Default,$(1))
TITLE+= (OpenSSL, 11r, 11w)
VARIANT:=wpad-basic-openssl
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
endef
define Package/wpad-basic-openssl/description
@@ -289,13 +327,24 @@ define Package/wpad-basic-wolfssl
$(call Package/wpad/Default,$(1))
TITLE+= (wolfSSL, 11r, 11w)
VARIANT:=wpad-basic-wolfssl
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_wpad-basic-wolfssl:libwolfssl
endef
define Package/wpad-basic-wolfssl/description
This package contains a basic IEEE 802.1x/WPA Authenticator and Supplicant with WPA-PSK, SAE (WPA3-Personal), 802.11r and 802.11w support.
endef
+define Package/wpad-basic-mbedtls
+$(call Package/wpad/Default,$(1))
+ TITLE+= (mbedTLS, 11r, 11w)
+ VARIANT:=wpad-basic-mbedtls
+ DEPENDS+=+PACKAGE_wpad-basic-mbedtls:libmbedtls
+endef
+
+define Package/wpad-basic-mbedtls/description
+ This package contains a basic IEEE 802.1x/WPA Authenticator and Supplicant with WPA-PSK, SAE (WPA3-Personal), 802.11r and 802.11w support.
+endef
+
define Package/wpad-mini
$(call Package/wpad/Default,$(1))
TITLE+= (WPA-PSK only)
@@ -308,7 +357,7 @@ endef
define Package/wpad-mesh
$(call Package/wpad/Default,$(1))
- DEPENDS+=@PACKAGE_kmod-cfg80211 @(!TARGET_uml||BROKEN)
+ DEPENDS+=@(!TARGET_uml||BROKEN)
PROVIDES+=wpa-supplicant-mesh wpad-mesh
endef
@@ -319,7 +368,7 @@ endef
define Package/wpad-mesh-openssl
$(call Package/wpad-mesh,$(1))
TITLE+= (OpenSSL, 11s, SAE)
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
VARIANT:=wpad-mesh-openssl
endef
@@ -328,12 +377,21 @@ Package/wpad-mesh-openssl/description = $(Package/wpad-mesh/description)
define Package/wpad-mesh-wolfssl
$(call Package/wpad-mesh,$(1))
TITLE+= (wolfSSL, 11s, SAE)
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_wpad-mesh-wolfssl:libwolfssl
VARIANT:=wpad-mesh-wolfssl
endef
Package/wpad-mesh-wolfssl/description = $(Package/wpad-mesh/description)
+define Package/wpad-mesh-mbedtls
+$(call Package/wpad-mesh,$(1))
+ TITLE+= (mbedTLS, 11s, SAE)
+ DEPENDS+=+PACKAGE_wpad-mesh-mbedtls:libmbedtls
+ VARIANT:=wpad-mesh-mbedtls
+endef
+
+Package/wpad-mesh-mbedtls/description = $(Package/wpad-mesh/description)
+
define Package/wpa-supplicant/Default
SECTION:=net
@@ -341,7 +399,8 @@ define Package/wpa-supplicant/Default
SUBMENU:=WirelessAPD
TITLE:=WPA Supplicant
URL:=http://hostap.epitest.fi/wpa_supplicant/
- DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus
+ DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
+ EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
PROVIDES:=wpa-supplicant
CONFLICTS:=$(SUPPLICANT_PROVIDERS)
@@ -358,14 +417,21 @@ define Package/wpa-supplicant-openssl
$(call Package/wpa-supplicant/Default,$(1))
TITLE+= (OpenSSL full)
VARIANT:=supplicant-full-openssl
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
endef
define Package/wpa-supplicant-wolfssl
$(call Package/wpa-supplicant/Default,$(1))
TITLE+= (wolfSSL full)
VARIANT:=supplicant-full-wolfssl
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_wpa-supplicant-wolfssl:libwolfssl
+endef
+
+define Package/wpa-supplicant-mbedtls
+$(call Package/wpa-supplicant/Default,$(1))
+ TITLE+= (mbedTLS full)
+ VARIANT:=supplicant-full-mbedtls
+ DEPENDS+=+PACKAGE_wpa-supplicant-mbedtls:libmbedtls
endef
define Package/wpa-supplicant/config
@@ -375,13 +441,12 @@ endef
define Package/wpa-supplicant-p2p
$(call Package/wpa-supplicant/Default,$(1))
TITLE+= (Wi-Fi P2P support)
- DEPENDS+=@PACKAGE_kmod-cfg80211
VARIANT:=supplicant-p2p-internal
endef
define Package/wpa-supplicant-mesh/Default
$(call Package/wpa-supplicant/Default,$(1))
- DEPENDS+=@PACKAGE_kmod-cfg80211 @(!TARGET_uml||BROKEN)
+ DEPENDS+=@(!TARGET_uml||BROKEN)
PROVIDES+=wpa-supplicant-mesh
endef
@@ -389,14 +454,21 @@ define Package/wpa-supplicant-mesh-openssl
$(call Package/wpa-supplicant-mesh/Default,$(1))
TITLE+= (OpenSSL, 11s, SAE)
VARIANT:=supplicant-mesh-openssl
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
endef
define Package/wpa-supplicant-mesh-wolfssl
$(call Package/wpa-supplicant-mesh/Default,$(1))
TITLE+= (wolfSSL, 11s, SAE)
VARIANT:=supplicant-mesh-wolfssl
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_wpa-supplicant-mesh-wolfssl:libwolfssl
+endef
+
+define Package/wpa-supplicant-mesh-mbedtls
+$(call Package/wpa-supplicant-mesh/Default,$(1))
+ TITLE+= (mbedTLS, 11s, SAE)
+ VARIANT:=supplicant-mesh-mbedtls
+ DEPENDS+=+PACKAGE_wpa-supplicant-mesh-mbedtls:libmbedtls
endef
define Package/wpa-supplicant-basic
@@ -426,6 +498,7 @@ define Package/hostapd-utils
TITLE:=IEEE 802.1x Authenticator (utils)
URL:=http://hostap.epitest.fi/
DEPENDS:=@$(subst $(space),||,$(foreach pkg,$(HOSTAPD_PROVIDERS),PACKAGE_$(pkg)))
+ VARIANT:=*
endef
define Package/hostapd-utils/description
@@ -439,6 +512,7 @@ define Package/wpa-cli
SUBMENU:=WirelessAPD
DEPENDS:=@$(subst $(space),||,$(foreach pkg,$(SUPPLICANT_PROVIDERS),PACKAGE_$(pkg)))
TITLE:=WPA Supplicant command line control utility
+ VARIANT:=*
endef
define Package/eapol-test/Default
@@ -446,7 +520,7 @@ define Package/eapol-test/Default
SECTION:=net
SUBMENU:=WirelessAPD
CATEGORY:=Network
- DEPENDS:=$(DRV_DEPENDS) +libubus
+ DEPENDS:=$(DRV_DEPENDS) $(CORE_DEPENDS)
endef
define Package/eapol-test
@@ -460,7 +534,7 @@ define Package/eapol-test-openssl
TITLE+= (OpenSSL full)
VARIANT:=supplicant-full-openssl
CONFLICTS:=$(filter-out eapol-test-openssl ,$(EAPOL_TEST_PROVIDERS))
- DEPENDS+=+libopenssl
+ DEPENDS+=$(OPENSSL_DEPENDS)
PROVIDES:=eapol-test
endef
@@ -469,7 +543,16 @@ define Package/eapol-test-wolfssl
TITLE+= (wolfSSL full)
VARIANT:=supplicant-full-wolfssl
CONFLICTS:=$(filter-out eapol-test-openssl ,$(filter-out eapol-test-wolfssl ,$(EAPOL_TEST_PROVIDERS)))
- DEPENDS+=+libwolfssl
+ DEPENDS+=+PACKAGE_eapol-test-wolfssl:libwolfssl
+ PROVIDES:=eapol-test
+endef
+
+define Package/eapol-test-mbedtls
+ $(call Package/eapol-test/Default,$(1))
+ TITLE+= (mbedTLS full)
+ VARIANT:=supplicant-full-mbedtls
+ CONFLICTS:=$(filter-out eapol-test-openssl ,$(filter-out eapol-test-mbedtls ,$(EAPOL_TEST_PROVIDERS)))
+ DEPENDS+=+PACKAGE_eapol-test-mbedtls:libmbedtls
PROVIDES:=eapol-test
endef
@@ -502,12 +585,7 @@ TARGET_CPPFLAGS := \
-D_GNU_SOURCE \
$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
-TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
-TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -lubox -lubus
-
-ifdef CONFIG_PACKAGE_kmod-cfg80211
- TARGET_LDFLAGS += -lm -lnl-tiny
-endif
+TARGET_LDFLAGS += -lubox -lubus -lblobmsg_json -lucode -lm -lnl-tiny -ludebug
ifdef CONFIG_WPA_ENABLE_WEP
DRIVER_MAKEOPTS += CONFIG_WEP=y
@@ -581,22 +659,59 @@ define Build/Compile/supplicant-full-wolfssl
)
endef
+define Build/Compile/supplicant-full-mbedtls
+ +$(call Build/RunMake,wpa_supplicant, \
+ eapol_test \
+ )
+endef
+
define Build/Compile
$(Build/Compile/$(LOCAL_TYPE))
$(Build/Compile/$(BUILD_VARIANT))
endef
+define Install/hostapd/full
+ $(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/config $(1)/etc/radius
+ ln -sf hostapd $(1)/usr/sbin/hostapd-radius
+ $(INSTALL_BIN) ./files/radius.init $(1)/etc/init.d/radius
+ $(INSTALL_DATA) ./files/radius.config $(1)/etc/config/radius
+ $(INSTALL_DATA) ./files/radius.clients $(1)/etc/radius/clients
+ $(INSTALL_DATA) ./files/radius.users $(1)/etc/radius/users
+endef
+
+define Package/hostapd-full/conffiles
+/etc/config/radius
+/etc/radius
+endef
+
+ifeq ($(CONFIG_VARIANT),full)
+Package/wpad-mesh-openssl/conffiles = $(Package/hostapd-full/conffiles)
+Package/wpad-mesh-wolfssl/conffiles = $(Package/hostapd-full/conffiles)
+Package/wpad-mesh-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
+Package/wpad/conffiles = $(Package/hostapd-full/conffiles)
+Package/wpad-openssl/conffiles = $(Package/hostapd-full/conffiles)
+Package/wpad-wolfssl/conffiles = $(Package/hostapd-full/conffiles)
+Package/wpad-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
+Package/hostapd/conffiles = $(Package/hostapd-full/conffiles)
+Package/hostapd-openssl/conffiles = $(Package/hostapd-full/conffiles)
+Package/hostapd-wolfssl/conffiles = $(Package/hostapd-full/conffiles)
+Package/hostapd-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
+endif
+
define Install/hostapd
- $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
+ $(INSTALL_DATA) ./files/hostapd.uc $(1)/usr/share/hostap/
+ $(if $(findstring full,$(CONFIG_VARIANT)),$(Install/hostapd/full))
endef
define Install/supplicant
- $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
+ $(INSTALL_DATA) ./files/wpa_supplicant.uc $(1)/usr/share/hostap/
endef
define Package/hostapd-common/install
- $(INSTALL_DIR) $(1)/etc/capabilities $(1)/etc/rc.button $(1)/etc/hotplug.d/ieee80211 $(1)/etc/init.d $(1)/lib/netifd $(1)/usr/share/acl.d
- $(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh
+ $(INSTALL_DIR) $(1)/etc/capabilities $(1)/etc/rc.button $(1)/etc/hotplug.d/ieee80211 $(1)/etc/init.d $(1)/lib/netifd $(1)/usr/share/acl.d $(1)/usr/share/hostap
+ $(INSTALL_BIN) ./files/dhcp-get-server.sh $(1)/lib/netifd/dhcp-get-server.sh
$(INSTALL_BIN) ./files/wpad.init $(1)/etc/init.d/wpad
$(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps
$(INSTALL_DATA) ./files/wpad_acl.json $(1)/usr/share/acl.d
@@ -610,9 +725,11 @@ endef
Package/hostapd-basic/install = $(Package/hostapd/install)
Package/hostapd-basic-openssl/install = $(Package/hostapd/install)
Package/hostapd-basic-wolfssl/install = $(Package/hostapd/install)
+Package/hostapd-basic-mbedtls/install = $(Package/hostapd/install)
Package/hostapd-mini/install = $(Package/hostapd/install)
Package/hostapd-openssl/install = $(Package/hostapd/install)
Package/hostapd-wolfssl/install = $(Package/hostapd/install)
+Package/hostapd-mbedtls/install = $(Package/hostapd/install)
ifneq ($(LOCAL_TYPE),supplicant)
define Package/hostapd-utils/install
@@ -631,11 +748,14 @@ endef
Package/wpad-basic/install = $(Package/wpad/install)
Package/wpad-basic-openssl/install = $(Package/wpad/install)
Package/wpad-basic-wolfssl/install = $(Package/wpad/install)
+Package/wpad-basic-mbedtls/install = $(Package/wpad/install)
Package/wpad-mini/install = $(Package/wpad/install)
Package/wpad-openssl/install = $(Package/wpad/install)
Package/wpad-wolfssl/install = $(Package/wpad/install)
+Package/wpad-mbedtls/install = $(Package/wpad/install)
Package/wpad-mesh-openssl/install = $(Package/wpad/install)
Package/wpad-mesh-wolfssl/install = $(Package/wpad/install)
+Package/wpad-mesh-mbedtls/install = $(Package/wpad/install)
define Package/wpa-supplicant/install
$(call Install/supplicant,$(1))
@@ -646,8 +766,10 @@ Package/wpa-supplicant-mini/install = $(Package/wpa-supplicant/install)
Package/wpa-supplicant-p2p/install = $(Package/wpa-supplicant/install)
Package/wpa-supplicant-openssl/install = $(Package/wpa-supplicant/install)
Package/wpa-supplicant-wolfssl/install = $(Package/wpa-supplicant/install)
+Package/wpa-supplicant-mbedtls/install = $(Package/wpa-supplicant/install)
Package/wpa-supplicant-mesh-openssl/install = $(Package/wpa-supplicant/install)
Package/wpa-supplicant-mesh-wolfssl/install = $(Package/wpa-supplicant/install)
+Package/wpa-supplicant-mesh-mbedtls/install = $(Package/wpa-supplicant/install)
ifneq ($(LOCAL_TYPE),hostapd)
define Package/wpa-cli/install
@@ -677,33 +799,50 @@ ifeq ($(BUILD_VARIANT),supplicant-full-wolfssl)
endef
endif
+ifeq ($(BUILD_VARIANT),supplicant-full-mbedtls)
+ define Package/eapol-test-mbedtls/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(CP) $(PKG_BUILD_DIR)/wpa_supplicant/eapol_test $(1)/usr/sbin/
+ endef
+endif
+
+# Build hostapd-common before its dependents, to avoid
+# spurious rebuilds when building multiple variants.
+$(eval $(call BuildPackage,hostapd-common))
$(eval $(call BuildPackage,hostapd))
$(eval $(call BuildPackage,hostapd-basic))
$(eval $(call BuildPackage,hostapd-basic-openssl))
$(eval $(call BuildPackage,hostapd-basic-wolfssl))
+$(eval $(call BuildPackage,hostapd-basic-mbedtls))
$(eval $(call BuildPackage,hostapd-mini))
$(eval $(call BuildPackage,hostapd-openssl))
$(eval $(call BuildPackage,hostapd-wolfssl))
+$(eval $(call BuildPackage,hostapd-mbedtls))
$(eval $(call BuildPackage,wpad))
$(eval $(call BuildPackage,wpad-mesh-openssl))
$(eval $(call BuildPackage,wpad-mesh-wolfssl))
+$(eval $(call BuildPackage,wpad-mesh-mbedtls))
$(eval $(call BuildPackage,wpad-basic))
$(eval $(call BuildPackage,wpad-basic-openssl))
$(eval $(call BuildPackage,wpad-basic-wolfssl))
+$(eval $(call BuildPackage,wpad-basic-mbedtls))
$(eval $(call BuildPackage,wpad-mini))
$(eval $(call BuildPackage,wpad-openssl))
$(eval $(call BuildPackage,wpad-wolfssl))
+$(eval $(call BuildPackage,wpad-mbedtls))
$(eval $(call BuildPackage,wpa-supplicant))
$(eval $(call BuildPackage,wpa-supplicant-mesh-openssl))
$(eval $(call BuildPackage,wpa-supplicant-mesh-wolfssl))
+$(eval $(call BuildPackage,wpa-supplicant-mesh-mbedtls))
$(eval $(call BuildPackage,wpa-supplicant-basic))
$(eval $(call BuildPackage,wpa-supplicant-mini))
$(eval $(call BuildPackage,wpa-supplicant-p2p))
$(eval $(call BuildPackage,wpa-supplicant-openssl))
$(eval $(call BuildPackage,wpa-supplicant-wolfssl))
+$(eval $(call BuildPackage,wpa-supplicant-mbedtls))
$(eval $(call BuildPackage,wpa-cli))
$(eval $(call BuildPackage,hostapd-utils))
-$(eval $(call BuildPackage,hostapd-common))
$(eval $(call BuildPackage,eapol-test))
$(eval $(call BuildPackage,eapol-test-openssl))
$(eval $(call BuildPackage,eapol-test-wolfssl))
+$(eval $(call BuildPackage,eapol-test-mbedtls))
diff --git a/package/network/services/hostapd/README.md b/package/network/services/hostapd/README.md
new file mode 100644
index 00000000000..21508633062
--- /dev/null
+++ b/package/network/services/hostapd/README.md
@@ -0,0 +1,419 @@
+# UBUS methods - hostapd
+
+## bss_mgmt_enable
+Enable 802.11k/v features.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| neighbor_report | bool | no | enable 802.11k neighbor reports |
+| beacon_report | bool | no | enable 802.11k beacon reports |
+| link_measurements | bool | no | enable 802.11k link measurements |
+| bss_transition | bool | no | enable 802.11v BSS transition support |
+
+### example
+`ubus call hostapd.wl5-fb bss_mgmt_enable '{ "neighbor_report": true, "beacon_report": true, "link_measurements": true, "bss_transition": true
+}'`
+
+
+## bss_transition_request
+Initiate an 802.11v transition request.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| addr | string | yes | client MAC address |
+| disassociation_imminent | bool | no | set Disassociation Imminent bit |
+| disassociation_timer | int32 | no | disassociate client if it doesn't roam after this time |
+| validity_period | int32 | no | validity of the BSS Transition Candiate List |
+| neighbors | array | no | BSS Transition Candidate List |
+| abridged | bool | no | prefer APs in the BSS Transition Candidate List |
+| dialog_token | int32 | no | identifier for the request/report transaction |
+| mbo_reason | int32 | no | MBO Transition Reason Code Attribute |
+| cell_pref | int32 | no | MBO Cellular Data Connection Preference Attribute |
+| reassoc_delay | int32 | no | MBO Re-association retry delay |
+
+### example
+`ubus call hostapd.wl5-fb bss_transition_request '{ "addr": "68:2F:67:8B:98:ED", "disassociation_imminent": false, "disassociation_timer": 0, "validity_period": 30, "neighbors": ["b6a7b9cbeebabf5900008064090603026a00"], "abridged": 1 }'`
+
+
+## config_add
+Dynamically load a BSS configuration from a file. This is used by netifd's mac80211 support script to configure BSSes on multiple PHYs in a single hostapd instance.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| iface | string | yes | WiFi interface name |
+| config | string | yes | path to hostapd config file |
+
+
+## config_remove
+Dynamically remove a BSS configuration.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| iface | string | yes | WiFi interface name |
+
+
+## del_client
+Kick a client off the network.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| addr | string | yes | client MAC address |
+| reason | int32 | no | 802.11 reason code |
+| deauth | bool | no | deauthenticates client instead of disassociating |
+| ban_time | int32 | no | ban client for N milliseconds |
+
+### example
+`ubus call hostapd.wl5-fb del_client '{ "addr": "68:2f:67:8b:98:ed", "reason": 5, "deauth": true, "ban_time": 10000 }'`
+
+
+## get_clients
+Show associated clients.
+
+### example
+`ubus call hostapd.wl5-fb get_clients`
+
+### output
+```json
+{
+ "freq": 5260,
+ "clients": {
+ "68:2f:67:8b:98:ed": {
+ "auth": true,
+ "assoc": true,
+ "authorized": true,
+ "preauth": false,
+ "wds": false,
+ "wmm": true,
+ "ht": true,
+ "vht": true,
+ "he": false,
+ "wps": false,
+ "mfp": true,
+ "rrm": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "extended_capabilities": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 64
+ ],
+ "aid": 3,
+ "signature": "wifi4|probe:0,1,45,127,107,191,221(0017f2,10),221(001018,2),htcap:006f,htagg:1b,htmcs:0000ffff,vhtcap:0f825832,vhtrxmcs:0000ffea,vhttxmcs:0000ffea,extcap:0000008000000040|assoc:0,1,33,36,48,45,127,191,221(0017f2,10),221(001018,2),221(0050f2,2),htcap:006f,htagg:1b,htmcs:0000ffff,vhtcap:0f825832,vhtrxmcs:0000ffea,vhttxmcs:0000ffea,txpow:14f9,extcap:0000000000000040",
+ "bytes": {
+ "rx": 1933667,
+ "tx": 746805
+ },
+ "airtime": {
+ "rx": 208863,
+ "tx": 9037883
+ },
+ "packets": {
+ "rx": 3587,
+ "tx": 2185
+ },
+ "rate": {
+ "rx": 866700,
+ "tx": 866700
+ },
+ "signal": -50,
+ "capabilities": {
+ "vht": {
+ "su_beamformee": true,
+ "mu_beamformee": false,
+ "mcs_map": {
+ "rx": {
+ "1ss": 9,
+ "2ss": 9,
+ "3ss": 9,
+ "4ss": -1,
+ "5ss": -1,
+ "6ss": -1,
+ "7ss": -1,
+ "8ss": -1
+ },
+ "tx": {
+ "1ss": 9,
+ "2ss": 9,
+ "3ss": 9,
+ "4ss": -1,
+ "5ss": -1,
+ "6ss": -1,
+ "7ss": -1,
+ "8ss": -1
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+
+## get_features
+Show HT/VHT support.
+
+### example
+`ubus call hostapd.wl5-fb get_features`
+
+### output
+```json
+{
+ "ht_supported": true,
+ "vht_supported": true
+}
+```
+
+
+## get_status
+Get BSS status.
+
+### example
+`ubus call hostapd.wl5-fb get_status`
+
+### output
+```json
+{
+ "status": "ENABLED",
+ "bssid": "b6:a7:b9:cb:ee:bc",
+ "ssid": "fb",
+ "freq": 5260,
+ "channel": 52,
+ "op_class": 128,
+ "beacon_interval": 100,
+ "phy": "wl5-lan",
+ "rrm": {
+ "neighbor_report_tx": 0
+ },
+ "wnm": {
+ "bss_transition_query_rx": 0,
+ "bss_transition_request_tx": 0,
+ "bss_transition_response_rx": 0
+ },
+ "airtime": {
+ "time": 259561738,
+ "time_busy": 2844249,
+ "utilization": 0
+ },
+ "dfs": {
+ "cac_seconds": 60,
+ "cac_active": false,
+ "cac_seconds_left": 0
+ }
+}
+```
+
+
+## link_measurement_req
+Initiate an 802.11k Link Measurement Request.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| addr | string | yes | client MAC address |
+| tx-power-used | int32 | no | transmit power used to transmit the Link Measurement Request frame |
+| tx-power-max | int32 | no | upper limit of transmit power to be used by the client |
+
+
+## list_bans
+List banned clients.
+
+### example
+`ubus call hostapd.wl5-fb list_bans`
+
+### output
+```json
+{
+ "clients": [
+ "68:2f:67:8b:98:ed"
+ ]
+}
+```
+
+
+## notify_response
+When enabled, hostapd will send a ubus notification and wait for a response before responding to various requests. This is used by e.g. usteer to make it possible to ignore probe requests.
+
+:warning: enabling this will cause hostapd to stop responding to probe requests unless a ubus subscriber responds to the ubus notifications.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| notify_response | int32 | yes | disable (0) or enable (!0) |
+
+### example
+`ubus call hostapd.wl5-fb notify_response '{ "notify_response": 1 }'`
+
+## reload
+Reload BSS configuration.
+
+:warning: this can cause problems for certain configurations:
+
+```
+Mon May 16 16:09:08 2022 daemon.warn hostapd: Failed to check if DFS is required; ret=-1
+Mon May 16 16:09:08 2022 daemon.warn hostapd: Failed to check if DFS is required; ret=-1
+Mon May 16 16:09:08 2022 daemon.err hostapd: Wrong coupling between HT and VHT/HE channel setting
+```
+
+### example
+`ubus call hostapd.wl5-fb reload`
+
+
+## rrm_beacon_req
+Send a Beacon Measurement Request to a client.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| addr | string | yes | client MAC address |
+| op_class | int32 | yes | the Regulatory Class for which this Measurement Request applies |
+| channel | int32 | yes | channel to measure |
+| duration | int32 | yes | compile Beacon Measurement Report after N TU |
+| mode | int32 | yes | mode to be used for measurement (0: passive, 1: active, 2: beacon table) |
+| bssid | string | no | filter BSSes in Beacon Measurement Report by BSSID |
+| ssid | string | no | filter BSSes in Beacon Measurement Report by SSID|
+
+
+## rrm_nr_get_own
+Show Neighbor Report Element for this BSS.
+
+### example
+`ubus call hostapd.wl5-fb rrm_nr_get_own`
+
+### output
+```json
+{
+ "value": [
+ "b6:a7:b9:cb:ee:bc",
+ "fb",
+ "b6a7b9cbeebcaf5900008095090603029b00"
+ ]
+}
+```
+
+
+## rrm_nr_list
+Show Neighbor Report Elements for other BSSes in this ESS.
+
+### example
+`ubus call hostapd.wl5-fb rrm_nr_list`
+
+### output
+```json
+{
+ "list": [
+ [
+ "b6:a7:b9:cb:ee:ba",
+ "fb",
+ "b6a7b9cbeebabf5900008064090603026a00"
+ ]
+ ]
+}
+```
+
+## rrm_nr_set
+Set the Neighbor Report Elements. An element for the node on which this command is executed will always be added.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| list | array | yes | array of Neighbor Report Elements in the format of the rrm_nr_list output |
+
+### example
+`ubus call hostapd.wl5-fb rrm_nr_set '{ "list": [ [ "b6:a7:b9:cb:ee:ba", "fb", "b6a7b9cbeebabf5900008064090603026a00" ] ] }'`
+
+
+## set_vendor_elements
+Configure Vendor-specific Information Elements for BSS.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| vendor_elements | string | yes | Vendor-specific Information Elements as hex string |
+
+### example
+`ubus call hostapd.wl5-fb set_vendor_elements '{ "vendor_elements": "dd054857dd6662" }'`
+
+
+## switch_chan
+Initiate a channel switch.
+
+:warning: trying to switch to the channel that is currently in use will fail: `Command failed: Operation not supported`
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| freq | int32 | yes | frequency in MHz to switch to |
+| bcn_count | int32 | no | count in Beacon frames (TBTT) to perform the switch |
+| center_freq1 | int32 | no | segment 0 center frequency in MHz (valid for HT and VHT) |
+| center_freq2 | int32 | no | segment 1 center frequency in MHz (valid only for 80 MHz channel width and an 80+80 channel) |
+| bandwidth | int32 | no | channel width to use |
+| sec_channel_offset| int32 | no | secondary channel offset for HT40 (0 = disabled, 1 = HT40+, -1 = HT40-) |
+| ht | bool | no | enable 802.11n |
+| vht | bool | no | enable 802.11ac |
+| he | bool | no | enable 802.11ax |
+| block_tx | bool | no | block transmission during CSA period |
+| csa_force | bool | no | restart the interface in case the CSA fails |
+
+## example
+`ubus call hostapd.wl5-fb switch_chan '{ "freq": 5180, "bcn_count": 10, "center_freq1": 5210, "bandwidth": 80, "he": 1, "block_tx": 1, "csa_force": 0 }'`
+
+
+## update_airtime
+Set dynamic airtime weight for client.
+
+### arguments
+| Name | Type | Required | Description |
+|---|---|---|---|
+| sta | string | yes | client MAC address |
+| weight | int32 | yes | airtime weight |
+
+
+## update_beacon
+Force beacon frame content to be updated and to start beaconing on an interface that uses start_disabled=1.
+
+### example
+`ubus call hostapd.wl5-fb update_beacon`
+
+
+## wps_status
+Get WPS status for BSS.
+
+### example
+`ubus call hostapd.wl5-fb wps_status`
+
+### output
+```json
+{
+ "pbc_status": "Disabled",
+ "last_wps_result": "None"
+}
+```
+
+
+## wps_cancel
+Cancel WPS Push Button Configuration.
+
+### example
+`ubus call hostapd.wl5-fb wps_cancel`
+
+
+## wps_start
+Start WPS Push Button Configuration.
+
+### example
+`ubus call hostapd.wl5-fb wps_start`
diff --git a/package/network/services/hostapd/files/dhcp-get-server.sh b/package/network/services/hostapd/files/dhcp-get-server.sh
new file mode 100644
index 00000000000..a1509ace2f1
--- /dev/null
+++ b/package/network/services/hostapd/files/dhcp-get-server.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+[ "$1" = bound ] && echo "$serverid"
diff --git a/package/network/services/hostapd/files/hostapd-basic.config b/package/network/services/hostapd/files/hostapd-basic.config
index 33c38192b1f..3d19d8f902f 100644
--- a/package/network/services/hostapd/files/hostapd-basic.config
+++ b/package/network/services/hostapd/files/hostapd-basic.config
@@ -54,7 +54,7 @@ CONFIG_RSN_PREAUTH=y
#CONFIG_IEEE80211W=y
# Support Operating Channel Validation
-#CONFIG_OCV=y
+CONFIG_OCV=y
# Integrated EAP server
#CONFIG_EAP=y
@@ -386,6 +386,9 @@ CONFIG_TLS=internal
# Airtime policy support
CONFIG_AIRTIME_POLICY=y
+# Proxy ARP support
+#CONFIG_PROXYARP=y
+
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
diff --git a/package/network/services/hostapd/files/hostapd-full.config b/package/network/services/hostapd/files/hostapd-full.config
index df272e443a8..9076ebc44f9 100644
--- a/package/network/services/hostapd/files/hostapd-full.config
+++ b/package/network/services/hostapd/files/hostapd-full.config
@@ -54,13 +54,13 @@ CONFIG_RSN_PREAUTH=y
#CONFIG_IEEE80211W=y
# Support Operating Channel Validation
-#CONFIG_OCV=y
+CONFIG_OCV=y
# Integrated EAP server
CONFIG_EAP=y
# EAP Re-authentication Protocol (ERP) in integrated EAP server
-#CONFIG_ERP=y
+CONFIG_ERP=y
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
@@ -142,7 +142,7 @@ CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# server from external hosts using RADIUS.
-#CONFIG_RADIUS_SERVER=y
+CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
@@ -316,7 +316,7 @@ CONFIG_INTERNAL_LIBTOMMATH=y
CONFIG_INTERWORKING=y
# Hotspot 2.0
-#CONFIG_HS20=y
+CONFIG_HS20=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
@@ -386,6 +386,9 @@ CONFIG_TAXONOMY=y
# Airtime policy support
CONFIG_AIRTIME_POLICY=y
+# Proxy ARP support
+CONFIG_PROXYARP=y
+
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
diff --git a/package/network/services/hostapd/files/hostapd-mini.config b/package/network/services/hostapd/files/hostapd-mini.config
index b3050f7bbc7..f2ed071ec09 100644
--- a/package/network/services/hostapd/files/hostapd-mini.config
+++ b/package/network/services/hostapd/files/hostapd-mini.config
@@ -386,6 +386,9 @@ CONFIG_TLS=internal
# Airtime policy support
#CONFIG_AIRTIME_POLICY=y
+# Proxy ARP support
+#CONFIG_PROXYARP=y
+
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
diff --git a/package/network/services/hostapd/files/hostapd.uc b/package/network/services/hostapd/files/hostapd.uc
new file mode 100644
index 00000000000..dfddf8185ba
--- /dev/null
+++ b/package/network/services/hostapd/files/hostapd.uc
@@ -0,0 +1,901 @@
+let libubus = require("ubus");
+import { open, readfile } from "fs";
+import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open } from "common";
+
+let ubus = libubus.connect(null, 60);
+
+hostapd.data.config = {};
+hostapd.data.pending_config = {};
+
+hostapd.data.file_fields = {
+ vlan_file: true,
+ wpa_psk_file: true,
+ accept_mac_file: true,
+ deny_mac_file: true,
+ eap_user_file: true,
+ ca_cert: true,
+ server_cert: true,
+ server_cert2: true,
+ private_key: true,
+ private_key2: true,
+ dh_file: true,
+ eap_sim_db: true,
+};
+
+function iface_remove(cfg)
+{
+ if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname)
+ return;
+
+ for (let bss in cfg.bss)
+ wdev_remove(bss.ifname);
+}
+
+function iface_gen_config(phy, config, start_disabled)
+{
+ let str = `data:
+${join("\n", config.radio.data)}
+channel=${config.radio.channel}
+`;
+
+ for (let i = 0; i < length(config.bss); i++) {
+ let bss = config.bss[i];
+ let type = i > 0 ? "bss" : "interface";
+ let nasid = bss.nasid ?? replace(bss.bssid, ":", "");
+
+ str += `
+${type}=${bss.ifname}
+bssid=${bss.bssid}
+${join("\n", bss.data)}
+nas_identifier=${nasid}
+`;
+ if (start_disabled)
+ str += `
+start_disabled=1
+`;
+ }
+
+ return str;
+}
+
+function iface_freq_info(iface, config, params)
+{
+ let freq = params.frequency;
+ if (!freq)
+ return null;
+
+ let sec_offset = params.sec_chan_offset;
+ if (sec_offset != -1 && sec_offset != 1)
+ sec_offset = 0;
+
+ let width = 0;
+ for (let line in config.radio.data) {
+ if (!sec_offset && match(line, /^ht_capab=.*HT40/)) {
+ sec_offset = null; // auto-detect
+ continue;
+ }
+
+ let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/);
+ if (!val)
+ continue;
+
+ val = int(val[2]);
+ if (val > width)
+ width = val;
+ }
+
+ if (freq < 4000)
+ width = 0;
+
+ return hostapd.freq_info(freq, sec_offset, width);
+}
+
+function iface_add(phy, config, phy_status)
+{
+ let config_inline = iface_gen_config(phy, config, !!phy_status);
+
+ let bss = config.bss[0];
+ let ret = hostapd.add_iface(`bss_config=${phy}:${config_inline}`);
+ if (ret < 0)
+ return false;
+
+ if (!phy_status)
+ return true;
+
+ let iface = hostapd.interfaces[phy];
+ if (!iface)
+ return false;
+
+ let freq_info = iface_freq_info(iface, config, phy_status);
+
+ return iface.start(freq_info) >= 0;
+}
+
+function iface_config_macaddr_list(config)
+{
+ let macaddr_list = {};
+ for (let i = 0; i < length(config.bss); i++) {
+ let bss = config.bss[i];
+ if (!bss.default_macaddr)
+ macaddr_list[bss.bssid] = i;
+ }
+
+ return macaddr_list;
+}
+
+function iface_update_supplicant_macaddr(phy, config)
+{
+ let macaddr_list = [];
+ for (let i = 0; i < length(config.bss); i++)
+ push(macaddr_list, config.bss[i].bssid);
+ ubus.defer("wpa_supplicant", "phy_set_macaddr_list", { phy: phy, macaddr: macaddr_list });
+}
+
+function __iface_pending_next(pending, state, ret, data)
+{
+ let config = pending.config;
+ let phydev = pending.phydev;
+ let phy = pending.phy;
+ let bss = config.bss[0];
+
+ if (pending.defer)
+ pending.defer.abort();
+ delete pending.defer;
+ switch (state) {
+ case "init":
+ let macaddr_list = [];
+ for (let i = 0; i < length(config.bss); i++)
+ push(macaddr_list, config.bss[i].bssid);
+ pending.call("wpa_supplicant", "phy_set_macaddr_list", { phy: phy, macaddr: macaddr_list });
+ return "create_bss";
+ case "create_bss":
+ let err = wdev_create(phy, bss.ifname, { mode: "ap" });
+ if (err) {
+ hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
+ return null;
+ }
+
+ pending.call("wpa_supplicant", "phy_status", { phy: phy });
+ return "check_phy";
+ case "check_phy":
+ let phy_status = data;
+ if (phy_status && phy_status.state == "COMPLETED") {
+ if (iface_add(phy, config, phy_status))
+ return "done";
+
+ hostapd.printf(`Failed to bring up phy ${phy} ifname=${bss.ifname} with supplicant provided frequency`);
+ }
+ pending.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: true });
+ return "wpas_stopped";
+ case "wpas_stopped":
+ if (!iface_add(phy, config))
+ hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`);
+ pending.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false });
+ return null;
+ case "done":
+ default:
+ delete hostapd.data.pending_config[phy];
+ break;
+ }
+}
+
+function iface_pending_next(ret, data)
+{
+ let pending = true;
+ let cfg = this;
+
+ while (pending) {
+ this.next_state = __iface_pending_next(cfg, this.next_state, ret, data);
+ if (!this.next_state) {
+ __iface_pending_next(cfg, "done");
+ return;
+ }
+ pending = !this.defer;
+ }
+}
+
+function iface_pending_abort()
+{
+ this.next_state = "done";
+ this.next();
+}
+
+function iface_pending_ubus_call(obj, method, arg)
+{
+ let ubus = hostapd.data.ubus;
+ let pending = this;
+ this.defer = ubus.defer(obj, method, arg, (ret, data) => { delete pending.defer; pending.next(ret, data) });
+}
+
+const iface_pending_proto = {
+ next: iface_pending_next,
+ call: iface_pending_ubus_call,
+ abort: iface_pending_abort,
+};
+
+function iface_pending_init(phydev, config)
+{
+ let phy = phydev.name;
+
+ let pending = proto({
+ next_state: "init",
+ phydev: phydev,
+ phy: phy,
+ config: config,
+ next: iface_pending_next,
+ }, iface_pending_proto);
+
+ hostapd.data.pending_config[phy] = pending;
+ pending.next();
+}
+
+function iface_restart(phydev, config, old_config)
+{
+ let phy = phydev.name;
+ let pending = hostapd.data.pending_config[phy];
+
+ if (pending)
+ pending.abort();
+
+ hostapd.remove_iface(phy);
+ iface_remove(old_config);
+ iface_remove(config);
+
+ if (!config.bss || !config.bss[0]) {
+ hostapd.printf(`No bss for phy ${phy}`);
+ return;
+ }
+
+ phydev.macaddr_init(iface_config_macaddr_list(config));
+ for (let i = 0; i < length(config.bss); i++) {
+ let bss = config.bss[i];
+ if (bss.default_macaddr)
+ bss.bssid = phydev.macaddr_next();
+ }
+
+ iface_pending_init(phydev, config);
+}
+
+function array_to_obj(arr, key, start)
+{
+ let obj = {};
+
+ start ??= 0;
+ for (let i = start; i < length(arr); i++) {
+ let cur = arr[i];
+ obj[cur[key]] = cur;
+ }
+
+ return obj;
+}
+
+function find_array_idx(arr, key, val)
+{
+ for (let i = 0; i < length(arr); i++)
+ if (arr[i][key] == val)
+ return i;
+
+ return -1;
+}
+
+function bss_reload_psk(bss, config, old_config)
+{
+ if (is_equal(old_config.hash.wpa_psk_file, config.hash.wpa_psk_file))
+ return;
+
+ old_config.hash.wpa_psk_file = config.hash.wpa_psk_file;
+ if (!is_equal(old_config, config))
+ return;
+
+ let ret = bss.ctrl("RELOAD_WPA_PSK");
+ ret ??= "failed";
+
+ hostapd.printf(`Reload WPA PSK file for bss ${config.ifname}: ${ret}`);
+}
+
+function remove_file_fields(config)
+{
+ return filter(config, (line) => !hostapd.data.file_fields[split(line, "=")[0]]);
+}
+
+function bss_remove_file_fields(config)
+{
+ let new_cfg = {};
+
+ for (let key in config)
+ new_cfg[key] = config[key];
+ new_cfg.data = remove_file_fields(new_cfg.data);
+ new_cfg.hash = {};
+ for (let key in config.hash)
+ new_cfg.hash[key] = config.hash[key];
+ delete new_cfg.hash.wpa_psk_file;
+ delete new_cfg.hash.vlan_file;
+
+ return new_cfg;
+}
+
+function bss_config_hash(config)
+{
+ return hostapd.sha1(remove_file_fields(config) + "");
+}
+
+function bss_find_existing(config, prev_config, prev_hash)
+{
+ let hash = bss_config_hash(config.data);
+
+ for (let i = 0; i < length(prev_config.bss); i++) {
+ if (!prev_hash[i] || hash != prev_hash[i])
+ continue;
+
+ prev_hash[i] = null;
+ return i;
+ }
+
+ return -1;
+}
+
+function get_config_bss(config, idx)
+{
+ if (!config.bss[idx]) {
+ hostapd.printf(`Invalid bss index ${idx}`);
+ return null;
+ }
+
+ let ifname = config.bss[idx].ifname;
+ if (!ifname)
+ hostapd.printf(`Could not find bss ${config.bss[idx].ifname}`);
+
+ return hostapd.bss[ifname];
+}
+
+function iface_reload_config(phydev, config, old_config)
+{
+ let phy = phydev.name;
+
+ if (!old_config || !is_equal(old_config.radio, config.radio))
+ return false;
+
+ if (is_equal(old_config.bss, config.bss))
+ return true;
+
+ if (hostapd.data.pending_config[phy])
+ return false;
+
+ if (!old_config.bss || !old_config.bss[0])
+ return false;
+
+ let iface = hostapd.interfaces[phy];
+ let iface_name = old_config.bss[0].ifname;
+ if (!iface) {
+ hostapd.printf(`Could not find previous interface ${iface_name}`);
+ return false;
+ }
+
+ let first_bss = hostapd.bss[iface_name];
+ if (!first_bss) {
+ hostapd.printf(`Could not find bss of previous interface ${iface_name}`);
+ return false;
+ }
+
+ let macaddr_list = iface_config_macaddr_list(config);
+ let bss_list = [];
+ let bss_list_cfg = [];
+ let prev_bss_hash = [];
+
+ for (let bss in old_config.bss) {
+ let hash = bss_config_hash(bss.data);
+ push(prev_bss_hash, bss_config_hash(bss.data));
+ }
+
+ // Step 1: find (possibly renamed) interfaces with the same config
+ // and store them in the new order (with gaps)
+ for (let i = 0; i < length(config.bss); i++) {
+ let prev;
+
+ // For fullmac devices, the first interface needs to be preserved,
+ // since it's treated as the master
+ if (!i && phy_is_fullmac(phy)) {
+ prev = 0;
+ prev_bss_hash[0] = null;
+ } else {
+ prev = bss_find_existing(config.bss[i], old_config, prev_bss_hash);
+ }
+ if (prev < 0)
+ continue;
+
+ let cur_config = config.bss[i];
+ let prev_config = old_config.bss[prev];
+
+ let prev_bss = get_config_bss(old_config, prev);
+ if (!prev_bss)
+ return false;
+
+ // try to preserve MAC address of this BSS by reassigning another
+ // BSS if necessary
+ if (cur_config.default_macaddr &&
+ !macaddr_list[prev_config.bssid]) {
+ macaddr_list[prev_config.bssid] = i;
+ cur_config.bssid = prev_config.bssid;
+ }
+
+ bss_list[i] = prev_bss;
+ bss_list_cfg[i] = old_config.bss[prev];
+ }
+
+ if (config.mbssid && !bss_list_cfg[0]) {
+ hostapd.printf("First BSS changed with MBSSID enabled");
+ return false;
+ }
+
+ // Step 2: if none were found, rename and preserve the first one
+ if (length(bss_list) == 0) {
+ // can't change the bssid of the first bss
+ if (config.bss[0].bssid != old_config.bss[0].bssid) {
+ if (!config.bss[0].default_macaddr) {
+ hostapd.printf(`BSSID of first interface changed: ${lc(old_config.bss[0].bssid)} -> ${lc(config.bss[0].bssid)}`);
+ return false;
+ }
+
+ config.bss[0].bssid = old_config.bss[0].bssid;
+ }
+
+ let prev_bss = get_config_bss(old_config, 0);
+ if (!prev_bss)
+ return false;
+
+ macaddr_list[config.bss[0].bssid] = 0;
+ bss_list[0] = prev_bss;
+ bss_list_cfg[0] = old_config.bss[0];
+ prev_bss_hash[0] = null;
+ }
+
+ // Step 3: delete all unused old interfaces
+ for (let i = 0; i < length(prev_bss_hash); i++) {
+ if (!prev_bss_hash[i])
+ continue;
+
+ let prev_bss = get_config_bss(old_config, i);
+ if (!prev_bss)
+ return false;
+
+ let ifname = old_config.bss[i].ifname;
+ hostapd.printf(`Remove bss '${ifname}' on phy '${phy}'`);
+ prev_bss.delete();
+ wdev_remove(ifname);
+ }
+
+ // Step 4: rename preserved interfaces, use temporary name on duplicates
+ let rename_list = [];
+ for (let i = 0; i < length(bss_list); i++) {
+ if (!bss_list[i])
+ continue;
+
+ let old_ifname = bss_list_cfg[i].ifname;
+ let new_ifname = config.bss[i].ifname;
+ if (old_ifname == new_ifname)
+ continue;
+
+ if (hostapd.bss[new_ifname]) {
+ new_ifname = "tmp_" + substr(hostapd.sha1(new_ifname), 0, 8);
+ push(rename_list, i);
+ }
+
+ hostapd.printf(`Rename bss ${old_ifname} to ${new_ifname}`);
+ if (!bss_list[i].rename(new_ifname)) {
+ hostapd.printf(`Failed to rename bss ${old_ifname} to ${new_ifname}`);
+ return false;
+ }
+
+ bss_list_cfg[i].ifname = new_ifname;
+ }
+
+ // Step 5: rename interfaces with temporary names
+ for (let i in rename_list) {
+ let new_ifname = config.bss[i].ifname;
+ if (!bss_list[i].rename(new_ifname)) {
+ hostapd.printf(`Failed to rename bss to ${new_ifname}`);
+ return false;
+ }
+ bss_list_cfg[i].ifname = new_ifname;
+ }
+
+ // Step 6: assign BSSID for newly created interfaces
+ let macaddr_data = {
+ num_global: config.num_global_macaddr ?? 1,
+ mbssid: config.mbssid ?? 0,
+ };
+ macaddr_list = phydev.macaddr_init(macaddr_list, macaddr_data);
+ for (let i = 0; i < length(config.bss); i++) {
+ if (bss_list[i])
+ continue;
+ let bsscfg = config.bss[i];
+
+ let mac_idx = macaddr_list[bsscfg.bssid];
+ if (mac_idx < 0)
+ macaddr_list[bsscfg.bssid] = i;
+ if (mac_idx == i)
+ continue;
+
+ // statically assigned bssid of the new interface is in conflict
+ // with the bssid of a reused interface. reassign the reused interface
+ if (!bsscfg.default_macaddr) {
+ // can't update bssid of the first BSS, need to restart
+ if (!mac_idx < 0)
+ return false;
+
+ bsscfg = config.bss[mac_idx];
+ }
+
+ let addr = phydev.macaddr_next(i);
+ if (!addr) {
+ hostapd.printf(`Failed to generate mac address for phy ${phy}`);
+ return false;
+ }
+ bsscfg.bssid = addr;
+ }
+
+ let config_inline = iface_gen_config(phy, config);
+
+ // Step 7: fill in the gaps with new interfaces
+ for (let i = 0; i < length(config.bss); i++) {
+ let ifname = config.bss[i].ifname;
+ let bss = bss_list[i];
+
+ if (bss)
+ continue;
+
+ hostapd.printf(`Add bss ${ifname} on phy ${phy}`);
+ bss_list[i] = iface.add_bss(config_inline, i);
+ if (!bss_list[i]) {
+ hostapd.printf(`Failed to add new bss ${ifname} on phy ${phy}`);
+ return false;
+ }
+ }
+
+ // Step 8: update interface bss order
+ if (!iface.set_bss_order(bss_list)) {
+ hostapd.printf(`Failed to update BSS order on phy '${phy}'`);
+ return false;
+ }
+
+ // Step 9: update config
+ for (let i = 0; i < length(config.bss); i++) {
+ if (!bss_list_cfg[i])
+ continue;
+
+ let ifname = config.bss[i].ifname;
+ let bss = bss_list[i];
+
+ if (is_equal(config.bss[i], bss_list_cfg[i]))
+ continue;
+
+ if (is_equal(bss_remove_file_fields(config.bss[i]),
+ bss_remove_file_fields(bss_list_cfg[i]))) {
+ hostapd.printf(`Update config data files for bss ${ifname}`);
+ if (bss.set_config(config_inline, i, true) < 0) {
+ hostapd.printf(`Could not update config data files for bss ${ifname}`);
+ return false;
+ } else {
+ bss.ctrl("RELOAD_WPA_PSK");
+ continue;
+ }
+ }
+
+ bss_reload_psk(bss, config.bss[i], bss_list_cfg[i]);
+ if (is_equal(config.bss[i], bss_list_cfg[i]))
+ continue;
+
+ hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`);
+ if (bss.set_config(config_inline, i) < 0) {
+ hostapd.printf(`Failed to set config for bss ${ifname}`);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function iface_set_config(phy, config)
+{
+ let old_config = hostapd.data.config[phy];
+
+ hostapd.data.config[phy] = config;
+
+ if (!config) {
+ hostapd.remove_iface(phy);
+ return iface_remove(old_config);
+ }
+
+ let phydev = phy_open(phy);
+ if (!phydev) {
+ hostapd.printf(`Failed to open phy ${phy}`);
+ return false;
+ }
+
+ try {
+ let ret = iface_reload_config(phydev, config, old_config);
+ if (ret) {
+ iface_update_supplicant_macaddr(phy, config);
+ hostapd.printf(`Reloaded settings for phy ${phy}`);
+ return 0;
+ }
+ } catch (e) {
+ hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`);
+ }
+
+ hostapd.printf(`Restart interface for phy ${phy}`);
+ let ret = iface_restart(phydev, config, old_config);
+
+ return ret;
+}
+
+function config_add_bss(config, name)
+{
+ let bss = {
+ ifname: name,
+ data: [],
+ hash: {}
+ };
+
+ push(config.bss, bss);
+
+ return bss;
+}
+
+function iface_load_config(filename)
+{
+ let f = open(filename, "r");
+ if (!f)
+ return null;
+
+ let config = {
+ radio: {
+ data: []
+ },
+ bss: [],
+ orig_file: filename,
+ };
+
+ let bss;
+ let line;
+ while ((line = rtrim(f.read("line"), "\n")) != null) {
+ let val = split(line, "=", 2);
+ if (!val[0])
+ continue;
+
+ if (val[0] == "interface") {
+ bss = config_add_bss(config, val[1]);
+ break;
+ }
+
+ if (val[0] == "channel") {
+ config.radio.channel = val[1];
+ continue;
+ }
+
+ if (val[0] == "#num_global_macaddr" ||
+ val[0] == "mbssid")
+ config[val[0]] = int(val[1]);
+
+ push(config.radio.data, line);
+ }
+
+ while ((line = rtrim(f.read("line"), "\n")) != null) {
+ if (line == "#default_macaddr")
+ bss.default_macaddr = true;
+
+ let val = split(line, "=", 2);
+ if (!val[0])
+ continue;
+
+ if (val[0] == "bssid") {
+ bss.bssid = lc(val[1]);
+ continue;
+ }
+
+ if (val[0] == "nas_identifier")
+ bss.nasid = val[1];
+
+ if (val[0] == "bss") {
+ bss = config_add_bss(config, val[1]);
+ continue;
+ }
+
+ if (hostapd.data.file_fields[val[0]])
+ bss.hash[val[0]] = hostapd.sha1(readfile(val[1]));
+
+ push(bss.data, line);
+ }
+ f.close();
+
+ return config;
+}
+
+function ex_wrap(func) {
+ return (req) => {
+ try {
+ let ret = func(req);
+ return ret;
+ } catch(e) {
+ hostapd.printf(`Exception in ubus function: ${e}\n${e.stacktrace[0].context}`);
+ }
+ return libubus.STATUS_UNKNOWN_ERROR;
+ };
+}
+
+let main_obj = {
+ reload: {
+ args: {
+ phy: "",
+ },
+ call: ex_wrap(function(req) {
+ let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config);
+ for (let phy_name in phy_list) {
+ let phy = hostapd.data.config[phy_name];
+ let config = iface_load_config(phy.orig_file);
+ iface_set_config(phy_name, config);
+ }
+
+ return 0;
+ })
+ },
+ apsta_state: {
+ args: {
+ phy: "",
+ up: true,
+ frequency: 0,
+ sec_chan_offset: 0,
+ csa: true,
+ csa_count: 0,
+ },
+ call: ex_wrap(function(req) {
+ if (req.args.up == null || !req.args.phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ let phy = req.args.phy;
+ let config = hostapd.data.config[phy];
+ if (!config || !config.bss || !config.bss[0] || !config.bss[0].ifname)
+ return 0;
+
+ let iface = hostapd.interfaces[phy];
+ if (!iface)
+ return 0;
+
+ if (!req.args.up) {
+ iface.stop();
+ return 0;
+ }
+
+ if (!req.args.frequency)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ let freq_info = iface_freq_info(iface, config, req.args);
+ if (!freq_info)
+ return libubus.STATUS_UNKNOWN_ERROR;
+
+ let ret;
+ if (req.args.csa) {
+ freq_info.csa_count = req.args.csa_count ?? 10;
+ ret = iface.switch_channel(freq_info);
+ } else {
+ ret = iface.start(freq_info);
+ }
+ if (!ret)
+ return libubus.STATUS_UNKNOWN_ERROR;
+
+ return 0;
+ })
+ },
+ config_get_macaddr_list: {
+ args: {
+ phy: ""
+ },
+ call: ex_wrap(function(req) {
+ let phy = req.args.phy;
+ if (!phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ let ret = {
+ macaddr: [],
+ };
+
+ let config = hostapd.data.config[phy];
+ if (!config)
+ return ret;
+
+ ret.macaddr = map(config.bss, (bss) => bss.bssid);
+ return ret;
+ })
+ },
+ config_set: {
+ args: {
+ phy: "",
+ config: "",
+ prev_config: "",
+ },
+ call: ex_wrap(function(req) {
+ let phy = req.args.phy;
+ let file = req.args.config;
+ let prev_file = req.args.prev_config;
+
+ if (!phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ if (prev_file && !hostapd.data.config[phy]) {
+ let config = iface_load_config(prev_file);
+ if (config)
+ config.radio.data = [];
+ hostapd.data.config[phy] = config;
+ }
+
+ let config = iface_load_config(file);
+
+ hostapd.printf(`Set new config for phy ${phy}: ${file}`);
+ iface_set_config(phy, config);
+
+ return {
+ pid: hostapd.getpid()
+ };
+ })
+ },
+ config_add: {
+ args: {
+ iface: "",
+ config: "",
+ },
+ call: ex_wrap(function(req) {
+ if (!req.args.iface || !req.args.config)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ if (hostapd.add_iface(`bss_config=${req.args.iface}:${req.args.config}`) < 0)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ return {
+ pid: hostapd.getpid()
+ };
+ })
+ },
+ config_remove: {
+ args: {
+ iface: ""
+ },
+ call: ex_wrap(function(req) {
+ if (!req.args.iface)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ hostapd.remove_iface(req.args.iface);
+ return 0;
+ })
+ },
+};
+
+hostapd.data.ubus = ubus;
+hostapd.data.obj = ubus.publish("hostapd", main_obj);
+hostapd.udebug_set("hostapd", hostapd.data.ubus);
+
+function bss_event(type, name, data) {
+ let ubus = hostapd.data.ubus;
+
+ data ??= {};
+ data.name = name;
+ hostapd.data.obj.notify(`bss.${type}`, data, null, null, null, -1);
+ ubus.call("service", "event", { type: `hostapd.${name}.${type}`, data: {} });
+}
+
+return {
+ shutdown: function() {
+ for (let phy in hostapd.data.config)
+ iface_set_config(phy, null);
+ hostapd.udebug_set(null);
+ hostapd.ubus.disconnect();
+ },
+ bss_add: function(name, obj) {
+ bss_event("add", name);
+ },
+ bss_reload: function(name, obj, reconf) {
+ bss_event("reload", name, { reconf: reconf != 0 });
+ },
+ bss_remove: function(name, obj) {
+ bss_event("remove", name);
+ }
+};
diff --git a/package/network/services/hostapd/files/radius.clients b/package/network/services/hostapd/files/radius.clients
new file mode 100644
index 00000000000..3175dcfd04a
--- /dev/null
+++ b/package/network/services/hostapd/files/radius.clients
@@ -0,0 +1 @@
+0.0.0.0/0 radius
diff --git a/package/network/services/hostapd/files/radius.config b/package/network/services/hostapd/files/radius.config
new file mode 100644
index 00000000000..ad8730748bb
--- /dev/null
+++ b/package/network/services/hostapd/files/radius.config
@@ -0,0 +1,9 @@
+config radius
+ option disabled '1'
+ option ca_cert '/etc/radius/ca.pem'
+ option cert '/etc/radius/cert.pem'
+ option key '/etc/radius/key.pem'
+ option users '/etc/radius/users'
+ option clients '/etc/radius/clients'
+ option auth_port '1812'
+ option acct_port '1813'
diff --git a/package/network/services/hostapd/files/radius.init b/package/network/services/hostapd/files/radius.init
new file mode 100644
index 00000000000..4c562c24738
--- /dev/null
+++ b/package/network/services/hostapd/files/radius.init
@@ -0,0 +1,42 @@
+#!/bin/sh /etc/rc.common
+
+START=30
+
+USE_PROCD=1
+NAME=radius
+
+radius_start() {
+ local cfg="$1"
+
+ config_get_bool disabled "$cfg" disabled 0
+
+ [ "$disabled" -gt 0 ] && return
+
+ config_get ca "$cfg" ca_cert
+ config_get key "$cfg" key
+ config_get cert "$cfg" cert
+ config_get users "$cfg" users
+ config_get clients "$cfg" clients
+ config_get auth_port "$cfg" auth_port 1812
+ config_get acct_port "$cfg" acct_port 1813
+ config_get identity "$cfg" identity "$(cat /proc/sys/kernel/hostname)"
+
+ procd_open_instance $cfg
+ procd_set_param command /usr/sbin/hostapd-radius \
+ -C "$ca" \
+ -c "$cert" -k "$key" \
+ -s "$clients" -u "$users" \
+ -p "$auth_port" -P "$acct_port" \
+ -i "$identity"
+ procd_close_instance
+}
+
+start_service() {
+ config_load radius
+ config_foreach radius_start radius
+}
+
+service_triggers()
+{
+ procd_add_reload_trigger "radius"
+}
diff --git a/package/network/services/hostapd/files/radius.users b/package/network/services/hostapd/files/radius.users
new file mode 100644
index 00000000000..03e2fc8fae7
--- /dev/null
+++ b/package/network/services/hostapd/files/radius.users
@@ -0,0 +1,14 @@
+{
+ "phase1": {
+ "wildcard": [
+ {
+ "name": "*",
+ "methods": [ "PEAP" ]
+ }
+ ]
+ },
+ "phase2": {
+ "users": {
+ }
+ }
+}
diff --git a/package/network/services/hostapd/files/wpa_supplicant-basic.config b/package/network/services/hostapd/files/wpa_supplicant-basic.config
index c550b37b21b..944b4d92876 100644
--- a/package/network/services/hostapd/files/wpa_supplicant-basic.config
+++ b/package/network/services/hostapd/files/wpa_supplicant-basic.config
@@ -26,7 +26,7 @@
# replacement for WEXT and its use allows wpa_supplicant to properly control
# the driver to improve existing functionality like roaming and to support new
# functionality.
-CONFIG_DRIVER_WEXT=y
+#CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
@@ -315,7 +315,7 @@ CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
#CONFIG_IEEE80211W=y
# Support Operating Channel Validation
-#CONFIG_OCV=y
+CONFIG_OCV=y
# Select TLS implementation
# openssl = OpenSSL (default)
diff --git a/package/network/services/hostapd/files/wpa_supplicant-full.config b/package/network/services/hostapd/files/wpa_supplicant-full.config
index b3e85d073d5..b39dabca069 100644
--- a/package/network/services/hostapd/files/wpa_supplicant-full.config
+++ b/package/network/services/hostapd/files/wpa_supplicant-full.config
@@ -26,7 +26,7 @@
# replacement for WEXT and its use allows wpa_supplicant to properly control
# the driver to improve existing functionality like roaming and to support new
# functionality.
-CONFIG_DRIVER_WEXT=y
+#CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
@@ -315,7 +315,7 @@ CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
#CONFIG_IEEE80211W=y
# Support Operating Channel Validation
-#CONFIG_OCV=y
+CONFIG_OCV=y
# Select TLS implementation
# openssl = OpenSSL (default)
@@ -578,7 +578,7 @@ CONFIG_HS20=y
#CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-#CONFIG_FILS=y
+CONFIG_FILS=y
# FILS shared key authentication with PFS
#CONFIG_FILS_SK_PFS=y
diff --git a/package/network/services/hostapd/files/wpa_supplicant-mini.config b/package/network/services/hostapd/files/wpa_supplicant-mini.config
index 9eb1111e523..2a3f8fb69de 100644
--- a/package/network/services/hostapd/files/wpa_supplicant-mini.config
+++ b/package/network/services/hostapd/files/wpa_supplicant-mini.config
@@ -26,7 +26,7 @@
# replacement for WEXT and its use allows wpa_supplicant to properly control
# the driver to improve existing functionality like roaming and to support new
# functionality.
-CONFIG_DRIVER_WEXT=y
+#CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
diff --git a/package/network/services/hostapd/files/wpa_supplicant-p2p.config b/package/network/services/hostapd/files/wpa_supplicant-p2p.config
index b00847a2565..7f5140622cc 100644
--- a/package/network/services/hostapd/files/wpa_supplicant-p2p.config
+++ b/package/network/services/hostapd/files/wpa_supplicant-p2p.config
@@ -26,7 +26,7 @@
# replacement for WEXT and its use allows wpa_supplicant to properly control
# the driver to improve existing functionality like roaming and to support new
# functionality.
-CONFIG_DRIVER_WEXT=y
+#CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
@@ -578,7 +578,7 @@ CONFIG_P2P=y
#CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-#CONFIG_FILS=y
+CONFIG_FILS=y
# FILS shared key authentication with PFS
#CONFIG_FILS_SK_PFS=y
@@ -622,4 +622,4 @@ CONFIG_UBUS=y
# OpenWrt patch 380-disable-ctrl-iface-mib.patch
# leads to the MIB only being compiled in if
# CONFIG_CTRL_IFACE_MIB is enabled.
-#CONFIG_CTRL_IFACE_MIB=y
+CONFIG_CTRL_IFACE_MIB=y
diff --git a/package/network/services/hostapd/files/wpa_supplicant.uc b/package/network/services/hostapd/files/wpa_supplicant.uc
new file mode 100644
index 00000000000..1709bb019e3
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant.uc
@@ -0,0 +1,349 @@
+let libubus = require("ubus");
+import { open, readfile } from "fs";
+import { wdev_create, wdev_set_mesh_params, wdev_remove, is_equal, wdev_set_up, vlist_new, phy_open } from "common";
+
+let ubus = libubus.connect();
+
+wpas.data.config = {};
+wpas.data.iface_phy = {};
+wpas.data.macaddr_list = {};
+
+function iface_stop(iface)
+{
+ let ifname = iface.config.iface;
+
+ if (!iface.running)
+ return;
+
+ delete wpas.data.iface_phy[ifname];
+ wpas.remove_iface(ifname);
+ wdev_remove(ifname);
+ iface.running = false;
+}
+
+function iface_start(phydev, iface, macaddr_list)
+{
+ let phy = phydev.name;
+
+ if (iface.running)
+ return;
+
+ let ifname = iface.config.iface;
+ let wdev_config = {};
+ for (let field in iface.config)
+ wdev_config[field] = iface.config[field];
+ if (!wdev_config.macaddr)
+ wdev_config.macaddr = phydev.macaddr_next();
+
+ wpas.data.iface_phy[ifname] = phy;
+ wdev_remove(ifname);
+ let ret = wdev_create(phy, ifname, wdev_config);
+ if (ret)
+ wpas.printf(`Failed to create device ${ifname}: ${ret}`);
+ wdev_set_up(ifname, true);
+ wpas.add_iface(iface.config);
+ iface.running = true;
+}
+
+function iface_cb(new_if, old_if)
+{
+ if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
+ new_if.running = old_if.running;
+ return;
+ }
+
+ if (new_if && old_if)
+ wpas.printf(`Update configuration for interface ${old_if.config.iface}`);
+ else if (old_if)
+ wpas.printf(`Remove interface ${old_if.config.iface}`);
+
+ if (old_if)
+ iface_stop(old_if);
+}
+
+function prepare_config(config)
+{
+ config.config_data = readfile(config.config);
+
+ return { config: config };
+}
+
+function set_config(phy_name, config_list)
+{
+ let phy = wpas.data.config[phy_name];
+
+ if (!phy) {
+ phy = vlist_new(iface_cb, false);
+ wpas.data.config[phy_name] = phy;
+ }
+
+ let values = [];
+ for (let config in config_list)
+ push(values, [ config.iface, prepare_config(config) ]);
+
+ phy.update(values);
+}
+
+function start_pending(phy_name)
+{
+ let phy = wpas.data.config[phy_name];
+ let ubus = wpas.data.ubus;
+
+ if (!phy || !phy.data)
+ return;
+
+ let phydev = phy_open(phy_name);
+ if (!phydev) {
+ wpas.printf(`Could not open phy ${phy_name}`);
+ return;
+ }
+
+ let macaddr_list = wpas.data.macaddr_list[phy_name];
+ phydev.macaddr_init(macaddr_list);
+
+ for (let ifname in phy.data)
+ iface_start(phydev, phy.data[ifname]);
+}
+
+let main_obj = {
+ phy_set_state: {
+ args: {
+ phy: "",
+ stop: true,
+ },
+ call: function(req) {
+ if (!req.args.phy || req.args.stop == null)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ let phy = wpas.data.config[req.args.phy];
+ if (!phy)
+ return libubus.STATUS_NOT_FOUND;
+
+ try {
+ if (req.args.stop) {
+ for (let ifname in phy.data)
+ iface_stop(phy.data[ifname]);
+ } else {
+ start_pending(req.args.phy);
+ }
+ } catch (e) {
+ wpas.printf(`Error chaging state: ${e}\n${e.stacktrace[0].context}`);
+ return libubus.STATUS_INVALID_ARGUMENT;
+ }
+ return 0;
+ }
+ },
+ phy_set_macaddr_list: {
+ args: {
+ phy: "",
+ macaddr: [],
+ },
+ call: function(req) {
+ let phy = req.args.phy;
+ if (!phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ wpas.data.macaddr_list[phy] = req.args.macaddr;
+ return 0;
+ }
+ },
+ phy_status: {
+ args: {
+ phy: ""
+ },
+ call: function(req) {
+ if (!req.args.phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ let phy = wpas.data.config[req.args.phy];
+ if (!phy)
+ return libubus.STATUS_NOT_FOUND;
+
+ for (let ifname in phy.data) {
+ try {
+ let iface = wpas.interfaces[ifname];
+ if (!iface)
+ continue;
+
+ let status = iface.status();
+ if (!status)
+ continue;
+
+ if (status.state == "INTERFACE_DISABLED")
+ continue;
+
+ status.ifname = ifname;
+ return status;
+ } catch (e) {
+ continue;
+ }
+ }
+
+ return libubus.STATUS_NOT_FOUND;
+ }
+ },
+ config_set: {
+ args: {
+ phy: "",
+ config: [],
+ defer: true,
+ },
+ call: function(req) {
+ if (!req.args.phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ wpas.printf(`Set new config for phy ${req.args.phy}`);
+ try {
+ if (req.args.config)
+ set_config(req.args.phy, req.args.config);
+
+ if (!req.args.defer)
+ start_pending(req.args.phy);
+ } catch (e) {
+ wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
+ return libubus.STATUS_INVALID_ARGUMENT;
+ }
+
+ return {
+ pid: wpas.getpid()
+ };
+ }
+ },
+ config_add: {
+ args: {
+ driver: "",
+ iface: "",
+ bridge: "",
+ hostapd_ctrl: "",
+ ctrl: "",
+ config: "",
+ },
+ call: function(req) {
+ if (!req.args.iface || !req.args.config)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ if (wpas.add_iface(req.args) < 0)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ return {
+ pid: wpas.getpid()
+ };
+ }
+ },
+ config_remove: {
+ args: {
+ iface: ""
+ },
+ call: function(req) {
+ if (!req.args.iface)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ wpas.remove_iface(req.args.iface);
+ return 0;
+ }
+ },
+};
+
+wpas.data.ubus = ubus;
+wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
+wpas.udebug_set("wpa_supplicant", wpas.data.ubus);
+
+function iface_event(type, name, data) {
+ let ubus = wpas.data.ubus;
+
+ data ??= {};
+ data.name = name;
+ wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
+ ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
+}
+
+function iface_hostapd_notify(phy, ifname, iface, state)
+{
+ let ubus = wpas.data.ubus;
+ let status = iface.status();
+ let msg = { phy: phy };
+
+ switch (state) {
+ case "DISCONNECTED":
+ case "AUTHENTICATING":
+ case "SCANNING":
+ msg.up = false;
+ break;
+ case "INTERFACE_DISABLED":
+ case "INACTIVE":
+ msg.up = true;
+ break;
+ case "COMPLETED":
+ msg.up = true;
+ msg.frequency = status.frequency;
+ msg.sec_chan_offset = status.sec_chan_offset;
+ break;
+ default:
+ return;
+ }
+
+ ubus.call("hostapd", "apsta_state", msg);
+}
+
+function iface_channel_switch(phy, ifname, iface, info)
+{
+ let msg = {
+ phy: phy,
+ up: true,
+ csa: true,
+ csa_count: info.csa_count ? info.csa_count - 1 : 0,
+ frequency: info.frequency,
+ sec_chan_offset: info.sec_chan_offset,
+ };
+ ubus.call("hostapd", "apsta_state", msg);
+}
+
+return {
+ shutdown: function() {
+ for (let phy in wpas.data.config)
+ set_config(phy, []);
+ wpas.ubus.disconnect();
+ },
+ iface_add: function(name, obj) {
+ iface_event("add", name);
+ },
+ iface_remove: function(name, obj) {
+ iface_event("remove", name);
+ },
+ state: function(ifname, iface, state) {
+ let phy = wpas.data.iface_phy[ifname];
+ if (!phy) {
+ wpas.printf(`no PHY for ifname ${ifname}`);
+ return;
+ }
+
+ iface_hostapd_notify(phy, ifname, iface, state);
+
+ if (state != "COMPLETED")
+ return;
+
+ let phy_data = wpas.data.config[phy];
+ if (!phy_data)
+ return;
+
+ let iface_data = phy_data.data[ifname];
+ if (!iface_data)
+ return;
+
+ let wdev_config = iface_data.config;
+ if (!wdev_config || wdev_config.mode != "mesh")
+ return;
+
+ wdev_set_mesh_params(ifname, wdev_config);
+ },
+ event: function(ifname, iface, ev, info) {
+ let phy = wpas.data.iface_phy[ifname];
+ if (!phy) {
+ wpas.printf(`no PHY for ifname ${ifname}`);
+ return;
+ }
+
+ if (ev == "CH_SWITCH_STARTED")
+ iface_channel_switch(phy, ifname, iface, info);
+ }
+};
diff --git a/package/network/services/hostapd/files/wpad.init b/package/network/services/hostapd/files/wpad.init
index 79c5bf1075c..65d46df982a 100644
--- a/package/network/services/hostapd/files/wpad.init
+++ b/package/network/services/hostapd/files/wpad.init
@@ -13,6 +13,7 @@ start_service() {
procd_open_instance hostapd
procd_set_param command /usr/sbin/hostapd -s -g /var/run/hostapd/global
procd_set_param respawn 3600 1 0
+ procd_set_param limits core="unlimited"
[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && {
procd_add_jail hostapd
procd_set_param capabilities /etc/capabilities/wpad.json
@@ -29,6 +30,7 @@ start_service() {
procd_open_instance supplicant
procd_set_param command /usr/sbin/wpa_supplicant -n -s -g /var/run/wpa_supplicant/global
procd_set_param respawn 3600 1 0
+ procd_set_param limits core="unlimited"
[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && {
procd_add_jail wpa_supplicant
procd_set_param capabilities /etc/capabilities/wpad.json
diff --git a/package/network/services/hostapd/files/wpad_acl.json b/package/network/services/hostapd/files/wpad_acl.json
index c77ccd8ea0c..7532953cabd 100644
--- a/package/network/services/hostapd/files/wpad_acl.json
+++ b/package/network/services/hostapd/files/wpad_acl.json
@@ -3,8 +3,18 @@
"access": {
"service": {
"methods": [ "event" ]
+ },
+ "wpa_supplicant": {
+ "methods": [ "phy_set_state", "phy_set_macaddr_list", "phy_status" ]
+ },
+ "hostapd": {
+ "methods": [ "apsta_state" ]
+ },
+ "udebug": {
+ "methods": [ "get_config" ]
}
},
+ "subscribe": [ "udebug" ],
"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*" ],
"send": [ "bss.*", "wps_credentials" ]
}
diff --git a/package/network/services/hostapd/files/wps-hotplug.sh b/package/network/services/hostapd/files/wps-hotplug.sh
index d00939d769b..073bdd18687 100644
--- a/package/network/services/hostapd/files/wps-hotplug.sh
+++ b/package/network/services/hostapd/files/wps-hotplug.sh
@@ -38,13 +38,20 @@ wps_catch_credentials() {
done
}
-if [ "$ACTION" = "pressed" -a "$BUTTON" = "wps" ]; then
- wps_done=0
- ubusobjs="$( ubus -S list hostapd.* )"
- for ubusobj in $ubusobjs; do
- ubus -S call $ubusobj wps_start && wps_done=1
- done
- [ $wps_done = 0 ] || return 0
+if [ "$ACTION" = "released" ] && [ "$BUTTON" = "wps" ]; then
+ # If the button was pressed for 3 seconds or more, trigger WPS on
+ # wpa_supplicant only, no matter if hostapd is running or not. If
+ # was pressed for less than 3 seconds, try triggering on
+ # hostapd. If there is no hostapd instance to trigger it on or WPS
+ # is not enabled on them, trigger it on wpa_supplicant.
+ if [ "$SEEN" -lt 3 ] ; then
+ wps_done=0
+ ubusobjs="$( ubus -S list hostapd.* )"
+ for ubusobj in $ubusobjs; do
+ ubus -S call $ubusobj wps_start && wps_done=1
+ done
+ [ $wps_done = 0 ] || return 0
+ fi
wps_done=0
ubusobjs="$( ubus -S list wpa_supplicant.* )"
for ubusobj in $ubusobjs; do
diff --git a/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch b/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch
index 84fc1c93513..269dcaac75c 100644
--- a/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch
+++ b/package/network/services/hostapd/patches/001-wolfssl-init-RNG-with-ECC-key.patch
@@ -16,7 +16,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
-@@ -1303,6 +1303,7 @@ int ecc_projective_add_point(ecc_point *
+@@ -1340,6 +1340,7 @@ int ecc_projective_add_point(ecc_point *
struct crypto_ec {
ecc_key key;
@@ -24,7 +24,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
mp_int a;
mp_int prime;
mp_int order;
-@@ -1357,6 +1358,8 @@ struct crypto_ec * crypto_ec_init(int gr
+@@ -1394,6 +1395,8 @@ struct crypto_ec * crypto_ec_init(int gr
return NULL;
if (wc_ecc_init(&e->key) != 0 ||
@@ -33,7 +33,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
mp_init(&e->a) != MP_OKAY ||
mp_init(&e->prime) != MP_OKAY ||
-@@ -1388,6 +1391,7 @@ void crypto_ec_deinit(struct crypto_ec*
+@@ -1425,6 +1428,7 @@ void crypto_ec_deinit(struct crypto_ec*
mp_clear(&e->order);
mp_clear(&e->prime);
mp_clear(&e->a);
diff --git a/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch b/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch
index d948c41b30b..0a51c84d215 100644
--- a/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch
+++ b/package/network/services/hostapd/patches/010-mesh-Allow-DFS-channels-to-be-selected-if-dfs-is-ena.patch
@@ -14,16 +14,37 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com>
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -2395,6 +2395,8 @@ void ibss_mesh_setup_freq(struct wpa_sup
- int chwidth, seg0, seg1;
- u32 vht_caps = 0;
- int is_24ghz;
-+ int dfs_enabled = wpa_s->conf->country[0] &&
-+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_RADAR);
+@@ -2638,7 +2638,7 @@ static int drv_supports_vht(struct wpa_s
+ }
- freq->freq = ssid->frequency;
-@@ -2484,8 +2486,11 @@ void ibss_mesh_setup_freq(struct wpa_sup
+-static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode)
++static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode, bool dfs_enabled)
+ {
+ int i;
+
+@@ -2647,7 +2647,10 @@ static bool ibss_mesh_is_80mhz_avail(int
+
+ chan = hw_get_channel_chan(mode, i, NULL);
+ if (!chan ||
+- chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
++ chan->flag & HOSTAPD_CHAN_DISABLED)
++ return false;
++
++ if (!dfs_enabled && chan->flag & (HOSTAPD_CHAN_RADAR | HOSTAPD_CHAN_NO_IR))
+ return false;
+ }
+
+@@ -2774,7 +2777,7 @@ static void ibss_mesh_select_40mhz(struc
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode,
+ struct hostapd_freq_params *freq,
+- int obss_scan) {
++ int obss_scan, bool dfs_enabled) {
+ int chan_idx;
+ struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
+ int i, res;
+@@ -2798,8 +2801,11 @@ static void ibss_mesh_select_40mhz(struc
return;
/* Check primary channel flags */
@@ -34,9 +55,9 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com>
+ if (!dfs_enabled)
+ return;
- freq->channel = pri_chan->chan;
-
-@@ -2518,8 +2523,11 @@ void ibss_mesh_setup_freq(struct wpa_sup
+ #ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40)
+@@ -2825,8 +2831,11 @@ static void ibss_mesh_select_40mhz(struc
return;
/* Check secondary channel flags */
@@ -49,20 +70,34 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com>
if (ht40 == -1) {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
-@@ -2612,8 +2620,11 @@ skip_ht40:
- return;
-
- /* Back to HT configuration if channel not usable */
-- if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
-+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
- return;
-+ if (chan->flag & (HOSTAPD_CHAN_RADAR | HOSTAPD_CHAN_NO_IR))
-+ if (!dfs_enabled)
-+ return;
- }
+@@ -2880,7 +2889,7 @@ static bool ibss_mesh_select_80_160mhz(s
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode,
+ struct hostapd_freq_params *freq,
+- int ieee80211_mode, bool is_6ghz) {
++ int ieee80211_mode, bool is_6ghz, bool dfs_enabled) {
+ static const int bw80[] = {
+ 5180, 5260, 5500, 5580, 5660, 5745, 5825,
+ 5955, 6035, 6115, 6195, 6275, 6355, 6435,
+@@ -2925,7 +2934,7 @@ static bool ibss_mesh_select_80_160mhz(s
+ goto skip_80mhz;
- chwidth = CHANWIDTH_80MHZ;
-@@ -2633,10 +2644,12 @@ skip_ht40:
+ /* Use 40 MHz if channel not usable */
+- if (!ibss_mesh_is_80mhz_avail(channel, mode))
++ if (!ibss_mesh_is_80mhz_avail(channel, mode, dfs_enabled))
+ goto skip_80mhz;
+
+ chwidth = CONF_OPER_CHWIDTH_80MHZ;
+@@ -2939,7 +2948,7 @@ static bool ibss_mesh_select_80_160mhz(s
+ if ((mode->he_capab[ieee80211_mode].phy_cap[
+ HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz &&
+- ibss_mesh_is_80mhz_avail(channel + 16, mode)) {
++ ibss_mesh_is_80mhz_avail(channel + 16, mode, dfs_enabled)) {
+ for (j = 0; j < ARRAY_SIZE(bw160); j++) {
+ if (freq->freq == bw160[j]) {
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
+@@ -2967,10 +2976,12 @@ static bool ibss_mesh_select_80_160mhz(s
if (!chan)
continue;
@@ -77,4 +112,24 @@ Signed-off-by: Peter Oh <peter.oh@bowerswilkins.com>
+ continue;
/* Found a suitable second segment for 80+80 */
- chwidth = CHANWIDTH_80P80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
+@@ -3025,6 +3036,7 @@ void ibss_mesh_setup_freq(struct wpa_sup
+ int i, obss_scan = 1;
+ u8 channel;
+ bool is_6ghz;
++ bool dfs_enabled = wpa_s->conf->country[0] && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_RADAR);
+
+ freq->freq = ssid->frequency;
+
+@@ -3070,9 +3082,9 @@ void ibss_mesh_setup_freq(struct wpa_sup
+ freq->channel = channel;
+ /* Setup higher BW only for 5 GHz */
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A) {
+- ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan);
++ ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan, dfs_enabled);
+ if (!ibss_mesh_select_80_160mhz(wpa_s, ssid, mode, freq,
+- ieee80211_mode, is_6ghz))
++ ieee80211_mode, is_6ghz, dfs_enabled))
+ freq->he_enabled = freq->vht_enabled = false;
+ }
+
diff --git a/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch b/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch
index 03a1e339a91..07b7a5971d3 100644
--- a/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch
+++ b/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch
@@ -28,8 +28,8 @@ Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
+#include "crypto/crypto.h"
- static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
-@@ -480,9 +481,14 @@ dfs_get_valid_channel(struct hostapd_ifa
+ enum dfs_channel_type {
+@@ -526,9 +527,14 @@ dfs_get_valid_channel(struct hostapd_ifa
int num_available_chandefs;
int chan_idx, chan_idx2;
int sec_chan_idx_80p80 = -1;
@@ -44,7 +44,7 @@ Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
*secondary_channel = 0;
*oper_centr_freq_seg0_idx = 0;
-@@ -502,8 +508,20 @@ dfs_get_valid_channel(struct hostapd_ifa
+@@ -548,8 +554,20 @@ dfs_get_valid_channel(struct hostapd_ifa
if (num_available_chandefs == 0)
return NULL;
@@ -64,11 +64,11 @@ Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
return NULL;
+
chan_idx = _rand % num_available_chandefs;
- dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ dfs_find_channel(iface, &chan, chan_idx, type);
if (!chan) {
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
-@@ -9872,6 +9872,10 @@ static int nl80211_switch_channel(void *
+@@ -11017,6 +11017,10 @@ static int nl80211_switch_channel(void *
if (ret)
goto error;
diff --git a/package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch b/package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch
deleted file mode 100644
index 75726a6750f..00000000000
--- a/package/network/services/hostapd/patches/020-mesh-make-forwarding-configurable.patch
+++ /dev/null
@@ -1,219 +0,0 @@
-From 90fe6429624fc48bc0e5d2d7eeecb7498708b5e3 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Wed, 18 Apr 2018 19:24:31 +0200
-Subject: [PATCH 18/18] mesh: make forwarding configurable
-
-Allow mesh_fwding to be specified in a mesh bss config, pass that
-to the driver (only nl80211 implemented for now) and announce
-forwarding capability accordingly.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- src/ap/ap_config.h | 2 ++
- src/drivers/driver.h | 2 ++
- src/drivers/driver_nl80211.c | 3 +++
- wpa_supplicant/config.c | 4 ++++
- wpa_supplicant/config.h | 9 +++++++++
- wpa_supplicant/config_file.c | 4 ++++
- wpa_supplicant/config_ssid.h | 5 +++++
- wpa_supplicant/mesh.c | 6 ++++++
- wpa_supplicant/mesh_mpm.c | 4 ++--
- wpa_supplicant/wpa_supplicant.conf | 3 +++
- 10 files changed, 40 insertions(+), 2 deletions(-)
-
---- a/src/ap/ap_config.h
-+++ b/src/ap/ap_config.h
-@@ -51,6 +51,7 @@ struct mesh_conf {
- int dot11MeshRetryTimeout; /* msec */
- int dot11MeshConfirmTimeout; /* msec */
- int dot11MeshHoldingTimeout; /* msec */
-+ int mesh_fwding;
- };
-
- #define MAX_STA_COUNT 2007
-@@ -696,6 +697,7 @@ struct hostapd_bss_config {
-
- #define MESH_ENABLED BIT(0)
- int mesh;
-+ int mesh_fwding;
-
- u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
-
---- a/src/drivers/driver.h
-+++ b/src/drivers/driver.h
-@@ -1584,6 +1584,7 @@ struct wpa_driver_mesh_bss_params {
- #define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS 0x00000004
- #define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE 0x00000008
- #define WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD 0x00000010
-+#define WPA_DRIVER_MESH_CONF_FLAG_FORWARDING 0x00000020
- /*
- * TODO: Other mesh configuration parameters would go here.
- * See NL80211_MESHCONF_* for all the mesh config parameters.
-@@ -1593,6 +1594,7 @@ struct wpa_driver_mesh_bss_params {
- int peer_link_timeout;
- int max_peer_links;
- int rssi_threshold;
-+ int forwarding;
- u16 ht_opmode;
- };
-
---- a/src/drivers/driver_nl80211.c
-+++ b/src/drivers/driver_nl80211.c
-@@ -10456,6 +10456,9 @@ static int nl80211_put_mesh_config(struc
- if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
- nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
- params->auto_plinks)) ||
-+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_FORWARDING) &&
-+ nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
-+ params->forwarding)) ||
- ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
- nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
- params->max_peer_links)) ||
---- a/wpa_supplicant/config.c
-+++ b/wpa_supplicant/config.c
-@@ -2527,6 +2527,7 @@ static const struct parse_data ssid_fiel
- #ifdef CONFIG_MESH
- { INT_RANGE(mode, 0, 5) },
- { INT_RANGE(no_auto_peer, 0, 1) },
-+ { INT_RANGE(mesh_fwding, 0, 1) },
- { INT_RANGE(mesh_rssi_threshold, -255, 1) },
- #else /* CONFIG_MESH */
- { INT_RANGE(mode, 0, 4) },
-@@ -3106,6 +3107,7 @@ void wpa_config_set_network_defaults(str
- ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
- ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
- ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
-+ ssid->mesh_fwding = DEFAULT_MESH_FWDING;
- ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD;
- #endif /* CONFIG_MESH */
- #ifdef CONFIG_HT_OVERRIDES
-@@ -4347,6 +4349,7 @@ struct wpa_config * wpa_config_alloc_emp
- config->user_mpm = DEFAULT_USER_MPM;
- config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
- config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
-+ config->mesh_fwding = DEFAULT_MESH_FWDING;
- config->dot11RSNASAERetransPeriod =
- DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD;
- config->fast_reauth = DEFAULT_FAST_REAUTH;
-@@ -5047,6 +5050,7 @@ static const struct global_parse_data gl
- { INT(user_mpm), 0 },
- { INT_RANGE(max_peer_links, 0, 255), 0 },
- { INT(mesh_max_inactivity), 0 },
-+ { INT_RANGE(mesh_fwding, 0, 1), 0 },
- { INT(dot11RSNASAERetransPeriod), 0 },
- #endif /* CONFIG_MESH */
- { INT(disable_scan_offload), 0 },
---- a/wpa_supplicant/config.h
-+++ b/wpa_supplicant/config.h
-@@ -18,6 +18,7 @@
- #define DEFAULT_USER_MPM 1
- #define DEFAULT_MAX_PEER_LINKS 99
- #define DEFAULT_MESH_MAX_INACTIVITY 300
-+#define DEFAULT_MESH_FWDING 1
- /*
- * The default dot11RSNASAERetransPeriod is defined as 40 ms in the standard,
- * but use 1000 ms in practice to avoid issues on low power CPUs.
-@@ -1378,6 +1379,14 @@ struct wpa_config {
- int mesh_max_inactivity;
-
- /**
-+ * mesh_fwding - Mesh network layer-2 forwarding
-+ *
-+ * This controls whether to enable layer-2 forwarding.
-+ * By default: 1: enabled
-+ */
-+ int mesh_fwding;
-+
-+ /**
- * dot11RSNASAERetransPeriod - Timeout to retransmit SAE Auth frame
- *
- * This timeout value is used in mesh STA to retransmit
---- a/wpa_supplicant/config_file.c
-+++ b/wpa_supplicant/config_file.c
-@@ -768,6 +768,7 @@ static void wpa_config_write_network(FIL
- #endif /* IEEE8021X_EAPOL */
- INT(mode);
- INT(no_auto_peer);
-+ INT(mesh_fwding);
- INT(frequency);
- INT(enable_edmg);
- INT(edmg_channel);
-@@ -1449,6 +1450,9 @@ static void wpa_config_write_global(FILE
- fprintf(f, "mesh_max_inactivity=%d\n",
- config->mesh_max_inactivity);
-
-+ if (config->mesh_fwding != DEFAULT_MESH_FWDING)
-+ fprintf(f, "mesh_fwding=%d\n", config->mesh_fwding);
-+
- if (config->dot11RSNASAERetransPeriod !=
- DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD)
- fprintf(f, "dot11RSNASAERetransPeriod=%d\n",
---- a/wpa_supplicant/config_ssid.h
-+++ b/wpa_supplicant/config_ssid.h
-@@ -546,6 +546,11 @@ struct wpa_ssid {
- int dot11MeshConfirmTimeout; /* msec */
- int dot11MeshHoldingTimeout; /* msec */
-
-+ /**
-+ * Mesh network layer-2 forwarding
-+ */
-+ int mesh_fwding;
-+
- int ht;
- int ht40;
-
---- a/wpa_supplicant/mesh.c
-+++ b/wpa_supplicant/mesh.c
-@@ -140,6 +140,7 @@ static struct mesh_conf * mesh_config_cr
- conf->mesh_cc_id = 0;
- conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
- conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
-+ conf->mesh_fwding = ssid->mesh_fwding;
- conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
- conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
- conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
-@@ -441,6 +442,7 @@ static int wpa_supplicant_mesh_init(stru
- bss->conf->start_disabled = 1;
- bss->conf->mesh = MESH_ENABLED;
- bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
-+ bss->conf->mesh_fwding = wpa_s->conf->mesh_fwding;
-
- if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
- wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
-@@ -655,6 +657,10 @@ int wpa_supplicant_join_mesh(struct wpa_
- }
- params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
-
-+ /* always explicitely set forwarding to on or off for now */
-+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_FORWARDING;
-+ params->conf.forwarding = ssid->mesh_fwding;
-+
- os_free(wpa_s->mesh_params);
- wpa_s->mesh_params = params;
- if (wpa_supplicant_mesh_init(wpa_s, ssid, &params->freq)) {
---- a/wpa_supplicant/mesh_mpm.c
-+++ b/wpa_supplicant/mesh_mpm.c
-@@ -303,9 +303,9 @@ static void mesh_mpm_send_plink_action(s
- info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1;
- /* TODO: Add Connected to Mesh Gate/AS subfields */
- wpabuf_put_u8(buf, info);
-- /* always forwarding & accepting plinks for now */
-+ /* set forwarding & always accepting plinks for now */
- wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
-- MESH_CAP_FORWARDING);
-+ (conf->mesh_fwding ? MESH_CAP_FORWARDING : 0));
- } else { /* Peer closing frame */
- /* IE: Mesh ID */
- wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
---- a/wpa_supplicant/wpa_supplicant.conf
-+++ b/wpa_supplicant/wpa_supplicant.conf
-@@ -150,6 +150,9 @@ ap_scan=1
- # This timeout value is used in mesh STA to clean up inactive stations.
- #mesh_max_inactivity=300
-
-+# Enable 802.11s layer-2 routing and forwarding
-+#mesh_fwding=1
-+
- # cert_in_cb - Whether to include a peer certificate dump in events
- # This controls whether peer certificates for authentication server and
- # its certificate chain are included in EAP peer certificate events. This is
diff --git a/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch b/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch
index 124fd8bdf13..edf599e3e28 100644
--- a/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch
+++ b/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch
@@ -1,6 +1,6 @@
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
-@@ -4942,6 +4942,13 @@ static int add_associated_sta(struct hos
+@@ -4621,6 +4621,13 @@ static int add_associated_sta(struct hos
* drivers to accept the STA parameter configuration. Since this is
* after a new FT-over-DS exchange, a new TK has been derived, so key
* reinstallation is not a concern for this case.
@@ -14,7 +14,7 @@
*/
wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
" (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
-@@ -4955,7 +4962,8 @@ static int add_associated_sta(struct hos
+@@ -4634,7 +4641,8 @@ static int add_associated_sta(struct hos
(!(sta->flags & WLAN_STA_AUTHORIZED) ||
(reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
(!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
diff --git a/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch b/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch
index c7da33f0290..8dec325c985 100644
--- a/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch
+++ b/package/network/services/hostapd/patches/022-hostapd-fix-use-of-uninitialized-stack-variables.patch
@@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -3431,7 +3431,7 @@ static int hostapd_change_config_freq(st
+@@ -3764,7 +3764,7 @@ static int hostapd_change_config_freq(st
struct hostapd_freq_params *old_params)
{
int channel;
diff --git a/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch b/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch
new file mode 100644
index 00000000000..9ff9b2398de
--- /dev/null
+++ b/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch
@@ -0,0 +1,19 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 28 Jul 2021 05:43:29 +0200
+Subject: [PATCH] ndisc_snoop: call dl_list_del before freeing ipv6 addresses
+
+Fixes a segmentation fault on sta disconnect
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/ap/ndisc_snoop.c
++++ b/src/ap/ndisc_snoop.c
+@@ -61,6 +61,7 @@ void sta_ip6addr_del(struct hostapd_data
+ dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
+ list) {
+ hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
++ dl_list_del(&ip6addr->list);
+ os_free(ip6addr);
+ }
+ }
diff --git a/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch
new file mode 100644
index 00000000000..ef2bb408fb2
--- /dev/null
+++ b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch
@@ -0,0 +1,275 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 28 Jul 2021 05:49:46 +0200
+Subject: [PATCH] driver_nl80211: rewrite neigh code to not depend on
+ libnl3-route
+
+Removes an unnecessary dependency and also makes the code smaller
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -16,9 +16,6 @@
+ #include <net/if.h>
+ #include <netlink/genl/genl.h>
+ #include <netlink/genl/ctrl.h>
+-#ifdef CONFIG_LIBNL3_ROUTE
+-#include <netlink/route/neighbour.h>
+-#endif /* CONFIG_LIBNL3_ROUTE */
+ #include <linux/rtnetlink.h>
+ #include <netpacket/packet.h>
+ #include <linux/errqueue.h>
+@@ -5783,26 +5780,29 @@ fail:
+
+ static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
+ {
+-#ifdef CONFIG_LIBNL3_ROUTE
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+- struct rtnl_neigh *rn;
+- struct nl_addr *nl_addr;
++ struct ndmsg nhdr = {
++ .ndm_state = NUD_PERMANENT,
++ .ndm_ifindex = bss->ifindex,
++ .ndm_family = AF_BRIDGE,
++ };
++ struct nl_msg *msg;
+ int err;
+
+- rn = rtnl_neigh_alloc();
+- if (!rn)
++ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE);
++ if (!msg)
+ return;
+
+- rtnl_neigh_set_family(rn, AF_BRIDGE);
+- rtnl_neigh_set_ifindex(rn, bss->ifindex);
+- nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
+- if (!nl_addr) {
+- rtnl_neigh_put(rn);
+- return;
+- }
+- rtnl_neigh_set_lladdr(rn, nl_addr);
++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
++ goto errout;
++
++ if (nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *)addr))
++ goto errout;
++
++ if (nl_send_auto_complete(drv->rtnl_sk, msg) < 0)
++ goto errout;
+
+- err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
++ err = nl_wait_for_ack(drv->rtnl_sk);
+ if (err < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
+ MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
+@@ -5812,9 +5812,8 @@ static void rtnl_neigh_delete_fdb_entry(
+ MACSTR, MAC2STR(addr));
+ }
+
+- nl_addr_put(nl_addr);
+- rtnl_neigh_put(rn);
+-#endif /* CONFIG_LIBNL3_ROUTE */
++errout:
++ nlmsg_free(msg);
+ }
+
+
+@@ -8492,7 +8491,6 @@ static void *i802_init(struct hostapd_da
+ (params->num_bridge == 0 || !params->bridge[0]))
+ add_ifidx(drv, br_ifindex, drv->ifindex);
+
+-#ifdef CONFIG_LIBNL3_ROUTE
+ if (bss->added_if_into_bridge || bss->already_in_bridge) {
+ int err;
+
+@@ -8509,7 +8507,6 @@ static void *i802_init(struct hostapd_da
+ goto failed;
+ }
+ }
+-#endif /* CONFIG_LIBNL3_ROUTE */
+
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
+ wpa_printf(MSG_DEBUG,
+@@ -11883,13 +11880,14 @@ static int wpa_driver_br_add_ip_neigh(vo
+ const u8 *ipaddr, int prefixlen,
+ const u8 *addr)
+ {
+-#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+- struct rtnl_neigh *rn;
+- struct nl_addr *nl_ipaddr = NULL;
+- struct nl_addr *nl_lladdr = NULL;
+- int family, addrsize;
++ struct ndmsg nhdr = {
++ .ndm_state = NUD_PERMANENT,
++ .ndm_ifindex = bss->br_ifindex,
++ };
++ struct nl_msg *msg;
++ int addrsize;
+ int res;
+
+ if (!ipaddr || prefixlen == 0 || !addr)
+@@ -11908,85 +11906,66 @@ static int wpa_driver_br_add_ip_neigh(vo
+ }
+
+ if (version == 4) {
+- family = AF_INET;
++ nhdr.ndm_family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+- family = AF_INET6;
++ nhdr.ndm_family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+- rn = rtnl_neigh_alloc();
+- if (rn == NULL)
++ msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
++ if (!msg)
+ return -ENOMEM;
+
+- /* set the destination ip address for neigh */
+- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+- if (nl_ipaddr == NULL) {
+- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+- res = -ENOMEM;
++ res = -ENOMEM;
++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
+ goto errout;
+- }
+- nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
+- res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+- if (res) {
+- wpa_printf(MSG_DEBUG,
+- "nl80211: neigh set destination addr failed");
++
++ if (nla_put(msg, NDA_DST, addrsize, (void *)ipaddr))
+ goto errout;
+- }
+
+- /* set the corresponding lladdr for neigh */
+- nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
+- if (nl_lladdr == NULL) {
+- wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
+- res = -ENOMEM;
++ if (nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *)addr))
+ goto errout;
+- }
+- rtnl_neigh_set_lladdr(rn, nl_lladdr);
+
+- rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+- rtnl_neigh_set_state(rn, NUD_PERMANENT);
++ res = nl_send_auto_complete(drv->rtnl_sk, msg);
++ if (res < 0)
++ goto errout;
+
+- res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
++ res = nl_wait_for_ack(drv->rtnl_sk);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Adding bridge ip neigh failed: %s",
+ nl_geterror(res));
+ }
+ errout:
+- if (nl_lladdr)
+- nl_addr_put(nl_lladdr);
+- if (nl_ipaddr)
+- nl_addr_put(nl_ipaddr);
+- if (rn)
+- rtnl_neigh_put(rn);
++ nlmsg_free(msg);
+ return res;
+-#else /* CONFIG_LIBNL3_ROUTE */
+- return -1;
+-#endif /* CONFIG_LIBNL3_ROUTE */
+ }
+
+
+ static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr)
+ {
+-#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+- struct rtnl_neigh *rn;
+- struct nl_addr *nl_ipaddr;
+- int family, addrsize;
++ struct ndmsg nhdr = {
++ .ndm_state = NUD_PERMANENT,
++ .ndm_ifindex = bss->br_ifindex,
++ };
++ struct nl_msg *msg;
++ int addrsize;
+ int res;
+
+ if (!ipaddr)
+ return -EINVAL;
+
+ if (version == 4) {
+- family = AF_INET;
++ nhdr.ndm_family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+- family = AF_INET6;
++ nhdr.ndm_family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+@@ -12004,41 +11983,30 @@ static int wpa_driver_br_delete_ip_neigh
+ return -1;
+ }
+
+- rn = rtnl_neigh_alloc();
+- if (rn == NULL)
++ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE);
++ if (!msg)
+ return -ENOMEM;
+
+- /* set the destination ip address for neigh */
+- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+- if (nl_ipaddr == NULL) {
+- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+- res = -ENOMEM;
++ res = -ENOMEM;
++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
+ goto errout;
+- }
+- res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+- if (res) {
+- wpa_printf(MSG_DEBUG,
+- "nl80211: neigh set destination addr failed");
++
++ if (nla_put(msg, NDA_DST, addrsize, (void *)ipaddr))
+ goto errout;
+- }
+
+- rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
++ res = nl_send_auto_complete(drv->rtnl_sk, msg);
++ if (res < 0)
++ goto errout;
+
+- res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
++ res = nl_wait_for_ack(drv->rtnl_sk);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Deleting bridge ip neigh failed: %s",
+ nl_geterror(res));
+ }
+ errout:
+- if (nl_ipaddr)
+- nl_addr_put(nl_ipaddr);
+- if (rn)
+- rtnl_neigh_put(rn);
++ nlmsg_free(msg);
+ return res;
+-#else /* CONFIG_LIBNL3_ROUTE */
+- return -1;
+-#endif /* CONFIG_LIBNL3_ROUTE */
+ }
+
+
diff --git a/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch
new file mode 100644
index 00000000000..b7bf9e351e0
--- /dev/null
+++ b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch
@@ -0,0 +1,34 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 18 Feb 2019 12:57:11 +0100
+Subject: [PATCH] mesh: allow processing authentication frames in blocked state
+
+If authentication fails repeatedly e.g. because of a weak signal, the link
+can end up in blocked state. If one of the nodes tries to establish a link
+again before it is unblocked on the other side, it will block the link to
+that other side. The same happens on the other side when it unblocks the
+link. In that scenario, the link never recovers on its own.
+
+To fix this, allow restarting authentication even if the link is in blocked
+state, but don't initiate the attempt until the blocked period is over.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -3020,15 +3020,6 @@ static void handle_auth(struct hostapd_d
+ seq_ctrl);
+ return;
+ }
+-#ifdef CONFIG_MESH
+- if ((hapd->conf->mesh & MESH_ENABLED) &&
+- sta->plink_state == PLINK_BLOCKED) {
+- wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
+- " is blocked - drop Authentication frame",
+- MAC2STR(sa));
+- return;
+- }
+-#endif /* CONFIG_MESH */
+ #ifdef CONFIG_PASN
+ if (auth_alg == WLAN_AUTH_PASN &&
+ (sta->flags & WLAN_STA_ASSOC)) {
diff --git a/package/network/services/hostapd/patches/050-build_fix.patch b/package/network/services/hostapd/patches/050-build_fix.patch
new file mode 100644
index 00000000000..8680b07c66a
--- /dev/null
+++ b/package/network/services/hostapd/patches/050-build_fix.patch
@@ -0,0 +1,20 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -324,6 +324,7 @@ ifdef CONFIG_FILS
+ CFLAGS += -DCONFIG_FILS
+ OBJS += ../src/ap/fils_hlp.o
+ NEED_SHA384=y
++NEED_HMAC_SHA384_KDF=y
+ NEED_AES_SIV=y
+ ifdef CONFIG_FILS_SK_PFS
+ CFLAGS += -DCONFIG_FILS_SK_PFS
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -331,6 +331,7 @@ endif
+ ifdef CONFIG_FILS
+ CFLAGS += -DCONFIG_FILS
+ NEED_SHA384=y
++NEED_HMAC_SHA384_KDF=y
+ NEED_AES_SIV=y
+ ifdef CONFIG_FILS_SK_PFS
+ CFLAGS += -DCONFIG_FILS_SK_PFS
diff --git a/package/network/services/hostapd/patches/100-daemonize_fix.patch b/package/network/services/hostapd/patches/100-daemonize_fix.patch
deleted file mode 100644
index 687bd4082dd..00000000000
--- a/package/network/services/hostapd/patches/100-daemonize_fix.patch
+++ /dev/null
@@ -1,97 +0,0 @@
---- a/src/utils/os_unix.c
-+++ b/src/utils/os_unix.c
-@@ -10,6 +10,7 @@
-
- #include <time.h>
- #include <sys/wait.h>
-+#include <fcntl.h>
-
- #ifdef ANDROID
- #include <sys/capability.h>
-@@ -188,59 +189,46 @@ int os_gmtime(os_time_t t, struct os_tm
- return 0;
- }
-
--
--#ifdef __APPLE__
--#include <fcntl.h>
--static int os_daemon(int nochdir, int noclose)
-+int os_daemonize(const char *pid_file)
- {
-- int devnull;
-+ int pid = 0, i, devnull;
-
-- if (chdir("/") < 0)
-- return -1;
-+#if defined(__uClinux__) || defined(__sun__)
-+ return -1;
-+#else /* defined(__uClinux__) || defined(__sun__) */
-
-- devnull = open("/dev/null", O_RDWR);
-- if (devnull < 0)
-+#ifndef __APPLE__
-+ pid = fork();
-+ if (pid < 0)
- return -1;
-+#endif
-
-- if (dup2(devnull, STDIN_FILENO) < 0) {
-- close(devnull);
-- return -1;
-+ if (pid > 0) {
-+ if (pid_file) {
-+ FILE *f = fopen(pid_file, "w");
-+ if (f) {
-+ fprintf(f, "%u\n", pid);
-+ fclose(f);
-+ }
-+ }
-+ _exit(0);
- }
-
-- if (dup2(devnull, STDOUT_FILENO) < 0) {
-- close(devnull);
-+ if (setsid() < 0)
- return -1;
-- }
-
-- if (dup2(devnull, STDERR_FILENO) < 0) {
-- close(devnull);
-+ if (chdir("/") < 0)
- return -1;
-- }
--
-- return 0;
--}
--#else /* __APPLE__ */
--#define os_daemon daemon
--#endif /* __APPLE__ */
-
--
--int os_daemonize(const char *pid_file)
--{
--#if defined(__uClinux__) || defined(__sun__)
-- return -1;
--#else /* defined(__uClinux__) || defined(__sun__) */
-- if (os_daemon(0, 0)) {
-- perror("daemon");
-+ devnull = open("/dev/null", O_RDWR);
-+ if (devnull < 0)
- return -1;
-- }
-
-- if (pid_file) {
-- FILE *f = fopen(pid_file, "w");
-- if (f) {
-- fprintf(f, "%u\n", getpid());
-- fclose(f);
-- }
-- }
-+ for (i = 0; i <= STDERR_FILENO; i++)
-+ dup2(devnull, i);
-+
-+ if (devnull > 2)
-+ close(devnull);
-
- return -0;
- #endif /* defined(__uClinux__) || defined(__sun__) */
diff --git a/package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch b/package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch
new file mode 100644
index 00000000000..22107944dce
--- /dev/null
+++ b/package/network/services/hostapd/patches/110-mbedtls-TLS-crypto-option-initial-port.patch
@@ -0,0 +1,8051 @@
+From e16f200dc1d2f69efc78c7c55af0d7b410a981f9 Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <gstrauss@gluelogic.com>
+Date: Tue, 5 Jul 2022 02:49:50 -0400
+Subject: [PATCH 1/7] mbedtls: TLS/crypto option (initial port)
+
+Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
+---
+ hostapd/Makefile | 91 +
+ hostapd/defconfig | 15 +-
+ src/crypto/crypto_mbedtls.c | 4043 +++++++++++++++++
+ src/crypto/tls_mbedtls.c | 3313 ++++++++++++++
+ .../build/build-wpa_supplicant-mbedtls.config | 24 +
+ tests/hwsim/example-hostapd.config | 4 +
+ tests/hwsim/example-wpa_supplicant.config | 4 +
+ wpa_supplicant/Makefile | 74 +
+ wpa_supplicant/defconfig | 6 +-
+ 9 files changed, 7571 insertions(+), 3 deletions(-)
+ create mode 100644 src/crypto/crypto_mbedtls.c
+ create mode 100644 src/crypto/tls_mbedtls.c
+ create mode 100644 tests/build/build-wpa_supplicant-mbedtls.config
+
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -745,6 +745,40 @@ endif
+ CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
+ endif
+
++ifeq ($(CONFIG_TLS), mbedtls)
++ifndef CONFIG_CRYPTO
++CONFIG_CRYPTO=mbedtls
++endif
++ifdef TLS_FUNCS
++OBJS += ../src/crypto/tls_mbedtls.o
++LIBS += -lmbedtls
++ifndef CONFIG_DPP
++LIBS += -lmbedx509
++endif
++endif
++OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
++HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
++SOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
++ifdef NEED_FIPS186_2_PRF
++OBJS += ../src/crypto/fips_prf_internal.o
++SHA1OBJS += ../src/crypto/sha1-internal.o
++endif
++ifeq ($(CONFIG_CRYPTO), mbedtls)
++ifdef CONFIG_DPP
++LIBS += -lmbedx509
++LIBS_h += -lmbedx509
++LIBS_n += -lmbedx509
++LIBS_s += -lmbedx509
++endif
++LIBS += -lmbedcrypto
++LIBS_h += -lmbedcrypto
++LIBS_n += -lmbedcrypto
++LIBS_s += -lmbedcrypto
++# XXX: create a config option?
++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
++endif
++endif
++
+ ifeq ($(CONFIG_TLS), gnutls)
+ ifndef CONFIG_CRYPTO
+ # default to libgcrypt
+@@ -924,9 +958,11 @@ endif
+
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-wrap.o
+ endif
+ endif
++endif
+ ifdef NEED_AES_EAX
+ AESOBJS += ../src/crypto/aes-eax.o
+ NEED_AES_CTR=y
+@@ -936,38 +972,48 @@ AESOBJS += ../src/crypto/aes-siv.o
+ NEED_AES_CTR=y
+ endif
+ ifdef NEED_AES_CTR
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-ctr.o
+ endif
++endif
+ ifdef NEED_AES_ENCBLOCK
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-encblock.o
+ endif
++endif
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-omac1.o
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_AES_UNWRAP
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ NEED_AES_DEC=y
+ AESOBJS += ../src/crypto/aes-unwrap.o
+ endif
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_AES_CBC
+ NEED_AES_DEC=y
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-cbc.o
+ endif
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_AES_DEC
+ ifdef CONFIG_INTERNAL_AES
+ AESOBJS += ../src/crypto/aes-internal-dec.o
+@@ -982,12 +1028,16 @@ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1.o
+ endif
+ endif
+ endif
+ endif
++endif
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-prf.o
++endif
+ ifdef CONFIG_INTERNAL_SHA1
+ SHA1OBJS += ../src/crypto/sha1-internal.o
+ ifdef NEED_FIPS186_2_PRF
+@@ -996,16 +1046,22 @@ endif
+ endif
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+ endif
+ endif
++endif
+ ifdef NEED_T_PRF
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-tprf.o
+ endif
++endif
+ ifdef NEED_TLS_PRF
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+ endif
+ endif
++endif
+
+ ifdef NEED_SHA1
+ OBJS += $(SHA1OBJS)
+@@ -1015,11 +1071,13 @@ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/md5.o
+ endif
+ endif
+ endif
+ endif
++endif
+
+ ifdef NEED_MD5
+ ifdef CONFIG_INTERNAL_MD5
+@@ -1058,56 +1116,81 @@ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha256.o
+ endif
+ endif
+ endif
+ endif
++endif
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha256-prf.o
++endif
+ ifdef CONFIG_INTERNAL_SHA256
+ OBJS += ../src/crypto/sha256-internal.o
+ endif
+ ifdef NEED_TLS_PRF_SHA256
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha256-tlsprf.o
+ endif
++endif
+ ifdef NEED_TLS_PRF_SHA384
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384-tlsprf.o
+ endif
++endif
+ ifdef NEED_HMAC_SHA256_KDF
++CFLAGS += -DCONFIG_HMAC_SHA256_KDF
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha256-kdf.o
+ endif
++endif
+ ifdef NEED_HMAC_SHA384_KDF
++CFLAGS += -DCONFIG_HMAC_SHA384_KDF
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384-kdf.o
+ endif
++endif
+ ifdef NEED_HMAC_SHA512_KDF
++CFLAGS += -DCONFIG_HMAC_SHA512_KDF
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha512-kdf.o
+ endif
++endif
+ ifdef NEED_SHA384
+ CFLAGS += -DCONFIG_SHA384
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384.o
+ endif
+ endif
+ endif
+ endif
++endif
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384-prf.o
+ endif
++endif
+ ifdef NEED_SHA512
+ CFLAGS += -DCONFIG_SHA512
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha512.o
+ endif
+ endif
+ endif
+ endif
++endif
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha512-prf.o
+ endif
++endif
+
+ ifdef CONFIG_INTERNAL_SHA384
+ CFLAGS += -DCONFIG_INTERNAL_SHA384
+@@ -1152,11 +1235,13 @@ HOBJS += $(SHA1OBJS)
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ HOBJS += ../src/crypto/md5.o
+ endif
+ endif
+ endif
+ endif
++endif
+
+ ifdef CONFIG_RADIUS_SERVER
+ CFLAGS += -DRADIUS_SERVER
+@@ -1329,7 +1414,9 @@ NOBJS += ../src/utils/trace.o
+ endif
+
+ HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
++ifneq ($(CONFIG_TLS), mbedtls)
+ HOBJS += ../src/crypto/aes-encblock.o
++endif
+ ifdef CONFIG_INTERNAL_AES
+ HOBJS += ../src/crypto/aes-internal.o
+ HOBJS += ../src/crypto/aes-internal-enc.o
+@@ -1352,13 +1439,17 @@ SOBJS += ../src/common/sae.o
+ SOBJS += ../src/common/sae_pk.o
+ SOBJS += ../src/common/dragonfly.o
+ SOBJS += $(AESOBJS)
++ifneq ($(CONFIG_TLS), mbedtls)
+ SOBJS += ../src/crypto/sha256-prf.o
+ SOBJS += ../src/crypto/sha384-prf.o
+ SOBJS += ../src/crypto/sha512-prf.o
++endif
+ SOBJS += ../src/crypto/dh_groups.o
++ifneq ($(CONFIG_TLS), mbedtls)
+ SOBJS += ../src/crypto/sha256-kdf.o
+ SOBJS += ../src/crypto/sha384-kdf.o
+ SOBJS += ../src/crypto/sha512-kdf.o
++endif
+
+ _OBJS_VAR := NOBJS
+ include ../src/objs.mk
+--- a/hostapd/defconfig
++++ b/hostapd/defconfig
+@@ -6,9 +6,21 @@
+ # just setting VARIABLE=n is not disabling that variable.
+ #
+ # This file is included in Makefile, so variables like CFLAGS and LIBS can also
+-# be modified from here. In most cass, these lines should use += in order not
++# be modified from here. In most cases, these lines should use += in order not
+ # to override previous values of the variables.
+
++
++# Uncomment following two lines and fix the paths if you have installed TLS
++# libraries in a non-default location
++#CFLAGS += -I/usr/local/openssl/include
++#LIBS += -L/usr/local/openssl/lib
++
++# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
++# the kerberos files are not in the default include path. Following line can be
++# used to fix build issues on such systems (krb5.h not found).
++#CFLAGS += -I/usr/include/kerberos
++
++
+ # Driver interface for Host AP driver
+ CONFIG_DRIVER_HOSTAP=y
+
+@@ -278,6 +290,7 @@ CONFIG_IPV6=y
+ # openssl = OpenSSL (default)
+ # gnutls = GnuTLS
+ # internal = Internal TLSv1 implementation (experimental)
++# mbedtls = mbed TLS
+ # linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
+ # none = Empty template
+ #CONFIG_TLS=openssl
+--- /dev/null
++++ b/src/crypto/crypto_mbedtls.c
+@@ -0,0 +1,4043 @@
++/*
++ * crypto wrapper functions for mbed TLS
++ *
++ * SPDX-FileCopyrightText: 2022 Glenn Strauss <gstrauss@gluelogic.com>
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include "utils/includes.h"
++#include "utils/common.h"
++
++#include <mbedtls/version.h>
++#include <mbedtls/entropy.h>
++#include <mbedtls/ctr_drbg.h>
++#include <mbedtls/platform_util.h> /* mbedtls_platform_zeroize() */
++#include <mbedtls/asn1.h>
++#include <mbedtls/asn1write.h>
++#include <mbedtls/aes.h>
++#include <mbedtls/md.h>
++#include <mbedtls/md5.h>
++#include <mbedtls/sha1.h>
++#include <mbedtls/sha256.h>
++#include <mbedtls/sha512.h>
++
++#ifndef MBEDTLS_PRIVATE
++#define MBEDTLS_PRIVATE(x) x
++#endif
++
++/* hostapd/wpa_supplicant provides forced_memzero(),
++ * but prefer mbedtls_platform_zeroize() */
++#define forced_memzero(ptr,sz) mbedtls_platform_zeroize(ptr,sz)
++
++#ifndef __has_attribute
++#define __has_attribute(x) 0
++#endif
++
++#ifndef __GNUC_PREREQ
++#define __GNUC_PREREQ(maj,min) 0
++#endif
++
++#ifndef __attribute_cold__
++#if __has_attribute(cold) \
++ || __GNUC_PREREQ(4,3)
++#define __attribute_cold__ __attribute__((__cold__))
++#else
++#define __attribute_cold__
++#endif
++#endif
++
++#ifndef __attribute_noinline__
++#if __has_attribute(noinline) \
++ || __GNUC_PREREQ(3,1)
++#define __attribute_noinline__ __attribute__((__noinline__))
++#else
++#define __attribute_noinline__
++#endif
++#endif
++
++#include "crypto.h"
++#include "aes_wrap.h"
++#include "aes.h"
++#include "md5.h"
++#include "sha1.h"
++#include "sha256.h"
++#include "sha384.h"
++#include "sha512.h"
++
++
++/*
++ * selective code inclusion based on preprocessor defines
++ *
++ * future: additional code could be wrapped with preprocessor checks if
++ * wpa_supplicant/Makefile and hostap/Makefile were more consistent with
++ * setting preprocessor defines for named groups of functionality
++ */
++
++#if defined(CONFIG_FIPS)
++#undef MBEDTLS_MD4_C /* omit md4_vector() */
++#undef MBEDTLS_MD5_C /* omit md5_vector() hmac_md5_vector() hmac_md5() */
++#undef MBEDTLS_DES_C /* omit des_encrypt() */
++#undef MBEDTLS_NIST_KW_C /* omit aes_wrap() aes_unwrap() */
++#define CRYPTO_MBEDTLS_CONFIG_FIPS
++#endif
++
++#if !defined(CONFIG_FIPS)
++#if defined(EAP_PWD) \
++ || defined(EAP_LEAP) || defined(EAP_LEAP_DYNAMIC) \
++ || defined(EAP_TTLS) || defined(EAP_TTLS_DYNAMIC) \
++ || defined(EAP_MSCHAPv2) || defined(EAP_MSCHAPv2_DYNAMIC) \
++ || defined(EAP_SERVER_MSCHAPV2)
++#ifndef MBEDTLS_MD4_C /* (MD4 not in mbedtls 3.x) */
++#include "md4-internal.c"/* pull in hostap local implementation */
++#endif /* md4_vector() */
++#else
++#undef MBEDTLS_MD4_C /* omit md4_vector() */
++#endif
++#endif
++
++#if !defined(CONFIG_NO_RC4) && !defined(CONFIG_NO_WPA)
++#ifndef MBEDTLS_ARC4_C /* (RC4 not in mbedtls 3.x) */
++#include "rc4.c" /* pull in hostap local implementation */
++#endif /* rc4_skip() */
++#else
++#undef MBEDTLS_ARC4_C /* omit rc4_skip() */
++#endif
++
++#if defined(CONFIG_MACSEC) \
++ || defined(CONFIG_NO_RADIUS) \
++ || defined(CONFIG_IEEE80211R) \
++ || defined(EAP_SERVER_FAST) \
++ || defined(EAP_SERVER_TEAP) \
++ || !defined(CONFIG_NO_WPA)
++ /* aes_wrap() aes_unwrap() */
++#else
++#undef MBEDTLS_NIST_KW_C /* omit aes_wrap() aes_unwrap() */
++#endif
++
++#if !defined(CONFIG_SHA256)
++#undef MBEDTLS_SHA256_C
++#endif
++
++#if !defined(CONFIG_SHA384) && !defined(CONFIG_SHA512)
++#undef MBEDTLS_SHA512_C
++#endif
++
++#if defined(CONFIG_HMAC_SHA256_KDF)
++#define CRYPTO_MBEDTLS_HMAC_KDF_SHA256
++#endif
++#if defined(CONFIG_HMAC_SHA384_KDF)
++#define CRYPTO_MBEDTLS_HMAC_KDF_SHA384
++#endif
++#if defined(CONFIG_HMAC_SHA512_KDF)
++#define CRYPTO_MBEDTLS_HMAC_KDF_SHA512
++#endif
++
++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) \
++ || defined(EAP_TEAP) || defined(EAP_TEAP_DYNAMIC) || defined(EAP_SERVER_FAST)
++#define CRYPTO_MBEDTLS_SHA1_T_PRF
++#endif
++
++#if defined(CONFIG_DES)
++#define CRYPTO_MBEDTLS_DES_ENCRYPT
++#endif /* des_encrypt() */
++
++#if !defined(CONFIG_NO_PBKDF2)
++#define CRYPTO_MBEDTLS_PBKDF2_SHA1
++#endif /* pbkdf2_sha1() */
++
++#if defined(EAP_IKEV2) \
++ || defined(EAP_IKEV2_DYNAMIC) \
++ || defined(EAP_SERVER_IKEV2) /* CONFIG_EAP_IKEV2=y */
++#define CRYPTO_MBEDTLS_CRYPTO_CIPHER
++#endif /* crypto_cipher_*() */
++
++#if defined(EAP_PWD) || defined(EAP_SERVER_PWD) /* CONFIG_EAP_PWD=y */
++#define CRYPTO_MBEDTLS_CRYPTO_HASH
++#endif /* crypto_hash_*() */
++
++#if defined(EAP_PWD) || defined(EAP_SERVER_PWD) /* CONFIG_EAP_PWD=y */ \
++ || defined(CONFIG_SAE) /* CONFIG_SAE=y */
++#define CRYPTO_MBEDTLS_CRYPTO_BIGNUM
++#endif /* crypto_bignum_*() */
++
++#if defined(EAP_PWD) /* CONFIG_EAP_PWD=y */ \
++ || defined(EAP_EKE) /* CONFIG_EAP_EKE=y */ \
++ || defined(EAP_EKE_DYNAMIC) /* CONFIG_EAP_EKE=y */ \
++ || defined(EAP_SERVER_EKE) /* CONFIG_EAP_EKE=y */ \
++ || defined(EAP_IKEV2) /* CONFIG_EAP_IKEV2y */ \
++ || defined(EAP_IKEV2_DYNAMIC)/* CONFIG_EAP_IKEV2=y */ \
++ || defined(EAP_SERVER_IKEV2) /* CONFIG_EAP_IKEV2=y */ \
++ || defined(CONFIG_SAE) /* CONFIG_SAE=y */ \
++ || defined(CONFIG_WPS) /* CONFIG_WPS=y */
++#define CRYPTO_MBEDTLS_CRYPTO_DH
++#if defined(CONFIG_WPS_NFC)
++#define CRYPTO_MBEDTLS_DH5_INIT_FIXED
++#endif /* dh5_init_fixed() */
++#endif /* crypto_dh_*() */
++
++#if !defined(CONFIG_NO_WPA) /* CONFIG_NO_WPA= */
++#define CRYPTO_MBEDTLS_CRYPTO_ECDH
++#endif /* crypto_ecdh_*() */
++
++#if defined(CONFIG_ECC)
++#define CRYPTO_MBEDTLS_CRYPTO_BIGNUM
++#define CRYPTO_MBEDTLS_CRYPTO_EC
++#endif /* crypto_ec_*() crypto_ec_key_*() */
++
++#if defined(CONFIG_DPP) /* CONFIG_DPP=y */
++#define CRYPTO_MBEDTLS_CRYPTO_EC_DPP /* extra for DPP */
++#define CRYPTO_MBEDTLS_CRYPTO_CSR
++#endif /* crypto_csr_*() */
++
++#if defined(CONFIG_DPP3) /* CONFIG_DPP3=y */
++#define CRYPTO_MBEDTLS_CRYPTO_HPKE
++#endif
++
++#if defined(CONFIG_DPP2) /* CONFIG_DPP2=y */
++#define CRYPTO_MBEDTLS_CRYPTO_PKCS7
++#endif /* crypto_pkcs7_*() */
++
++#if defined(EAP_SIM) || defined(EAP_SIM_DYNAMIC) || defined(EAP_SERVER_SIM) \
++ || defined(EAP_AKA) || defined(EAP_AKA_DYNAMIC) || defined(EAP_SERVER_AKA) \
++ || defined(CONFIG_AP) || defined(HOSTAPD)
++/* CONFIG_EAP_SIM=y CONFIG_EAP_AKA=y CONFIG_AP=y HOSTAPD */
++#if defined(CRYPTO_RSA_OAEP_SHA256)
++#define CRYPTO_MBEDTLS_CRYPTO_RSA
++#endif
++#endif /* crypto_rsa_*() */
++
++
++static int ctr_drbg_init_state;
++static mbedtls_ctr_drbg_context ctr_drbg;
++static mbedtls_entropy_context entropy;
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_BIGNUM
++#include <mbedtls/bignum.h>
++static mbedtls_mpi mpi_sw_A;
++#endif
++
++__attribute_cold__
++__attribute_noinline__
++static mbedtls_ctr_drbg_context * ctr_drbg_init(void)
++{
++ mbedtls_ctr_drbg_init(&ctr_drbg);
++ mbedtls_entropy_init(&entropy);
++ if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
++ NULL, 0)) {
++ wpa_printf(MSG_ERROR, "Init of random number generator failed");
++ /* XXX: abort? */
++ }
++ else
++ ctr_drbg_init_state = 1;
++
++ return &ctr_drbg;
++}
++
++__attribute_cold__
++void crypto_unload(void)
++{
++ if (ctr_drbg_init_state) {
++ mbedtls_ctr_drbg_free(&ctr_drbg);
++ mbedtls_entropy_free(&entropy);
++ #ifdef CRYPTO_MBEDTLS_CRYPTO_BIGNUM
++ mbedtls_mpi_free(&mpi_sw_A);
++ #endif
++ ctr_drbg_init_state = 0;
++ }
++}
++
++/* init ctr_drbg on first use
++ * crypto_global_init() and crypto_global_deinit() are not available here
++ * (available only when CONFIG_TLS=internal, which is not CONFIG_TLS=mbedtls) */
++mbedtls_ctr_drbg_context * crypto_mbedtls_ctr_drbg(void); /*(not in header)*/
++inline
++mbedtls_ctr_drbg_context * crypto_mbedtls_ctr_drbg(void)
++{
++ return ctr_drbg_init_state ? &ctr_drbg : ctr_drbg_init();
++}
++
++#ifdef CRYPTO_MBEDTLS_CONFIG_FIPS
++int crypto_get_random(void *buf, size_t len)
++{
++ return mbedtls_ctr_drbg_random(crypto_mbedtls_ctr_drbg(),buf,len) ? -1 : 0;
++}
++#endif
++
++
++#if 1
++
++/* tradeoff: slightly smaller code size here at cost of slight increase
++ * in instructions and function calls at runtime versus the expanded
++ * per-message-digest code that follows in #else (~0.5 kib .text larger) */
++
++__attribute_noinline__
++static int md_vector(size_t num_elem, const u8 *addr[], const size_t *len,
++ u8 *mac, mbedtls_md_type_t md_type)
++{
++ mbedtls_md_context_t ctx;
++ mbedtls_md_init(&ctx);
++ if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0) != 0){
++ mbedtls_md_free(&ctx);
++ return -1;
++ }
++ mbedtls_md_starts(&ctx);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_md_update(&ctx, addr[i], len[i]);
++ mbedtls_md_finish(&ctx, mac);
++ mbedtls_md_free(&ctx);
++ return 0;
++}
++
++#ifdef MBEDTLS_SHA512_C
++int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA512);
++}
++
++int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA384);
++}
++#endif
++
++#ifdef MBEDTLS_SHA256_C
++int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA256);
++}
++#endif
++
++#ifdef MBEDTLS_SHA1_C
++int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_SHA1);
++}
++#endif
++
++#ifdef MBEDTLS_MD5_C
++int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_MD5);
++}
++#endif
++
++#ifdef MBEDTLS_MD4_C
++#include <mbedtls/md4.h>
++int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return md_vector(num_elem, addr, len, mac, MBEDTLS_MD_MD4);
++}
++#endif
++
++#else /* expanded per-message-digest functions */
++
++#ifdef MBEDTLS_SHA512_C
++#include <mbedtls/sha512.h>
++__attribute_noinline__
++static int sha384_512_vector(size_t num_elem, const u8 *addr[],
++ const size_t *len, u8 *mac, int is384)
++{
++ struct mbedtls_sha512_context ctx;
++ mbedtls_sha512_init(&ctx);
++ #if MBEDTLS_VERSION_MAJOR >= 3
++ mbedtls_sha512_starts(&ctx, is384);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_sha512_update(&ctx, addr[i], len[i]);
++ mbedtls_sha512_finish(&ctx, mac);
++ #else
++ mbedtls_sha512_starts_ret(&ctx, is384);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_sha512_update_ret(&ctx, addr[i], len[i]);
++ mbedtls_sha512_finish_ret(&ctx, mac);
++ #endif
++ mbedtls_sha512_free(&ctx);
++ return 0;
++}
++
++int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return sha384_512_vector(num_elem, addr, len, mac, 0);
++}
++
++int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return sha384_512_vector(num_elem, addr, len, mac, 1);
++}
++#endif
++
++#ifdef MBEDTLS_SHA256_C
++#include <mbedtls/sha256.h>
++int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ struct mbedtls_sha256_context ctx;
++ mbedtls_sha256_init(&ctx);
++ #if MBEDTLS_VERSION_MAJOR >= 3
++ mbedtls_sha256_starts(&ctx, 0);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_sha256_update(&ctx, addr[i], len[i]);
++ mbedtls_sha256_finish(&ctx, mac);
++ #else
++ mbedtls_sha256_starts_ret(&ctx, 0);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_sha256_update_ret(&ctx, addr[i], len[i]);
++ mbedtls_sha256_finish_ret(&ctx, mac);
++ #endif
++ mbedtls_sha256_free(&ctx);
++ return 0;
++}
++#endif
++
++#ifdef MBEDTLS_SHA1_C
++#include <mbedtls/sha1.h>
++int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ struct mbedtls_sha1_context ctx;
++ mbedtls_sha1_init(&ctx);
++ #if MBEDTLS_VERSION_MAJOR >= 3
++ mbedtls_sha1_starts(&ctx);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_sha1_update(&ctx, addr[i], len[i]);
++ mbedtls_sha1_finish(&ctx, mac);
++ #else
++ mbedtls_sha1_starts_ret(&ctx);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_sha1_update_ret(&ctx, addr[i], len[i]);
++ mbedtls_sha1_finish_ret(&ctx, mac);
++ #endif
++ mbedtls_sha1_free(&ctx);
++ return 0;
++}
++#endif
++
++#ifdef MBEDTLS_MD5_C
++#include <mbedtls/md5.h>
++int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ struct mbedtls_md5_context ctx;
++ mbedtls_md5_init(&ctx);
++ #if MBEDTLS_VERSION_MAJOR >= 3
++ mbedtls_md5_starts(&ctx);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_md5_update(&ctx, addr[i], len[i]);
++ mbedtls_md5_finish(&ctx, mac);
++ #else
++ mbedtls_md5_starts_ret(&ctx);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_md5_update_ret(&ctx, addr[i], len[i]);
++ mbedtls_md5_finish_ret(&ctx, mac);
++ #endif
++ mbedtls_md5_free(&ctx);
++ return 0;
++}
++#endif
++
++#ifdef MBEDTLS_MD4_C
++#include <mbedtls/md4.h>
++int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
++{
++ struct mbedtls_md4_context ctx;
++ mbedtls_md4_init(&ctx);
++ mbedtls_md4_starts_ret(&ctx);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_md4_update_ret(&ctx, addr[i], len[i]);
++ mbedtls_md4_finish_ret(&ctx, mac);
++ mbedtls_md4_free(&ctx);
++ return 0;
++}
++#endif
++
++#endif /* expanded per-message-digest functions */
++
++
++__attribute_noinline__
++static int hmac_vector(const u8 *key, size_t key_len, size_t num_elem,
++ const u8 *addr[], const size_t *len, u8 *mac,
++ mbedtls_md_type_t md_type)
++{
++ mbedtls_md_context_t ctx;
++ mbedtls_md_init(&ctx);
++ if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1) != 0){
++ mbedtls_md_free(&ctx);
++ return -1;
++ }
++ mbedtls_md_hmac_starts(&ctx, key, key_len);
++ for (size_t i = 0; i < num_elem; ++i)
++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]);
++ mbedtls_md_hmac_finish(&ctx, mac);
++ mbedtls_md_free(&ctx);
++ return 0;
++}
++
++#ifdef MBEDTLS_SHA512_C
++int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
++ const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return hmac_vector(key, key_len, num_elem, addr, len, mac,
++ MBEDTLS_MD_SHA512);
++}
++
++int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
++ u8 *mac)
++{
++ return hmac_vector(key, key_len, 1, &data, &data_len, mac,
++ MBEDTLS_MD_SHA512);
++}
++
++int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
++ const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return hmac_vector(key, key_len, num_elem, addr, len, mac,
++ MBEDTLS_MD_SHA384);
++}
++
++int hmac_sha384(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
++ u8 *mac)
++{
++ return hmac_vector(key, key_len, 1, &data, &data_len, mac,
++ MBEDTLS_MD_SHA384);
++}
++#endif
++
++#ifdef MBEDTLS_SHA256_C
++int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
++ const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return hmac_vector(key, key_len, num_elem, addr, len, mac,
++ MBEDTLS_MD_SHA256);
++}
++
++int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
++ u8 *mac)
++{
++ return hmac_vector(key, key_len, 1, &data, &data_len, mac,
++ MBEDTLS_MD_SHA256);
++}
++#endif
++
++#ifdef MBEDTLS_SHA1_C
++int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
++ const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return hmac_vector(key, key_len, num_elem, addr, len, mac,
++ MBEDTLS_MD_SHA1);
++}
++
++int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
++ u8 *mac)
++{
++ return hmac_vector(key, key_len, 1, &data, &data_len, mac,
++ MBEDTLS_MD_SHA1);
++}
++#endif
++
++#ifdef MBEDTLS_MD5_C
++int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
++ const u8 *addr[], const size_t *len, u8 *mac)
++{
++ return hmac_vector(key, key_len, num_elem, addr, len, mac,
++ MBEDTLS_MD_MD5);
++}
++
++int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
++ u8 *mac)
++{
++ return hmac_vector(key, key_len, 1, &data, &data_len, mac,
++ MBEDTLS_MD_MD5);
++}
++#endif
++
++
++#if defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C)
++
++#if defined(CRYPTO_MBEDTLS_HMAC_KDF_SHA256) \
++ || defined(CRYPTO_MBEDTLS_HMAC_KDF_SHA384) \
++ || defined(CRYPTO_MBEDTLS_HMAC_KDF_SHA512)
++
++#include <mbedtls/hkdf.h>
++
++/* sha256-kdf.c sha384-kdf.c sha512-kdf.c */
++
++/* HMAC-SHA256 KDF (RFC 5295) and HKDF-Expand(SHA256) (RFC 5869) */
++/* HMAC-SHA384 KDF (RFC 5295) and HKDF-Expand(SHA384) (RFC 5869) */
++/* HMAC-SHA512 KDF (RFC 5295) and HKDF-Expand(SHA512) (RFC 5869) */
++__attribute_noinline__
++static int hmac_kdf_expand(const u8 *prk, size_t prk_len,
++ const char *label, const u8 *info, size_t info_len,
++ u8 *okm, size_t okm_len, mbedtls_md_type_t md_type)
++{
++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
++ #ifdef MBEDTLS_HKDF_C
++ if (label == NULL) /* RFC 5869 HKDF-Expand when (label == NULL) */
++ return mbedtls_hkdf_expand(md_info, prk, prk_len, info,
++ info_len, okm, okm_len) ? -1 : 0;
++ #endif
++
++ const size_t mac_len = mbedtls_md_get_size(md_info);
++ /* okm_len must not exceed 255 times hash len (RFC 5869 Section 2.3) */
++ if (okm_len > ((mac_len << 8) - mac_len))
++ return -1;
++
++ mbedtls_md_context_t ctx;
++ mbedtls_md_init(&ctx);
++ if (mbedtls_md_setup(&ctx, md_info, 1) != 0) {
++ mbedtls_md_free(&ctx);
++ return -1;
++ }
++ mbedtls_md_hmac_starts(&ctx, prk, prk_len);
++
++ u8 iter = 1;
++ const u8 *addr[4] = { okm, (const u8 *)label, info, &iter };
++ size_t len[4] = { 0, label ? os_strlen(label)+1 : 0, info_len, 1 };
++
++ for (; okm_len >= mac_len; okm_len -= mac_len, ++iter) {
++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i)
++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]);
++ mbedtls_md_hmac_finish(&ctx, okm);
++ mbedtls_md_hmac_reset(&ctx);
++ addr[0] = okm;
++ okm += mac_len;
++ len[0] = mac_len; /*(include digest in subsequent rounds)*/
++ }
++
++ if (okm_len) {
++ u8 hash[MBEDTLS_MD_MAX_SIZE];
++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i)
++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]);
++ mbedtls_md_hmac_finish(&ctx, hash);
++ os_memcpy(okm, hash, okm_len);
++ forced_memzero(hash, mac_len);
++ }
++
++ mbedtls_md_free(&ctx);
++ return 0;
++}
++
++#ifdef MBEDTLS_SHA512_C
++#ifdef CRYPTO_MBEDTLS_HMAC_KDF_SHA512
++int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
++ const char *label, const u8 *seed, size_t seed_len,
++ u8 *out, size_t outlen)
++{
++ return hmac_kdf_expand(secret, secret_len, label, seed, seed_len,
++ out, outlen, MBEDTLS_MD_SHA512);
++}
++#endif
++
++#ifdef CRYPTO_MBEDTLS_HMAC_KDF_SHA384
++int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
++ const char *label, const u8 *seed, size_t seed_len,
++ u8 *out, size_t outlen)
++{
++ return hmac_kdf_expand(secret, secret_len, label, seed, seed_len,
++ out, outlen, MBEDTLS_MD_SHA384);
++}
++#endif
++#endif
++
++#ifdef MBEDTLS_SHA256_C
++#ifdef CRYPTO_MBEDTLS_HMAC_KDF_SHA256
++int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
++ const char *label, const u8 *seed, size_t seed_len,
++ u8 *out, size_t outlen)
++{
++ return hmac_kdf_expand(secret, secret_len, label, seed, seed_len,
++ out, outlen, MBEDTLS_MD_SHA256);
++}
++#endif
++#endif
++
++#endif /* CRYPTO_MBEDTLS_HMAC_KDF_* */
++
++
++/* sha256-prf.c sha384-prf.c sha512-prf.c */
++
++/* hmac_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function */
++__attribute_noinline__
++static int hmac_prf_bits(const u8 *key, size_t key_len, const char *label,
++ const u8 *data, size_t data_len, u8 *buf,
++ size_t buf_len_bits, mbedtls_md_type_t md_type)
++{
++ mbedtls_md_context_t ctx;
++ mbedtls_md_init(&ctx);
++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
++ if (mbedtls_md_setup(&ctx, md_info, 1) != 0) {
++ mbedtls_md_free(&ctx);
++ return -1;
++ }
++ mbedtls_md_hmac_starts(&ctx, key, key_len);
++
++ u16 ctr, n_le = host_to_le16(buf_len_bits);
++ const u8 * const addr[] = { (u8 *)&ctr,(u8 *)label,data,(u8 *)&n_le };
++ const size_t len[] = { 2, os_strlen(label), data_len, 2 };
++ const size_t mac_len = mbedtls_md_get_size(md_info);
++ size_t buf_len = (buf_len_bits + 7) / 8;
++ for (ctr = 1; buf_len >= mac_len; buf_len -= mac_len, ++ctr) {
++ #if __BYTE_ORDER == __BIG_ENDIAN
++ ctr = host_to_le16(ctr);
++ #endif
++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i)
++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]);
++ mbedtls_md_hmac_finish(&ctx, buf);
++ mbedtls_md_hmac_reset(&ctx);
++ buf += mac_len;
++ #if __BYTE_ORDER == __BIG_ENDIAN
++ ctr = le_to_host16(ctr);
++ #endif
++ }
++
++ if (buf_len) {
++ u8 hash[MBEDTLS_MD_MAX_SIZE];
++ #if __BYTE_ORDER == __BIG_ENDIAN
++ ctr = host_to_le16(ctr);
++ #endif
++ for (size_t i = 0; i < ARRAY_SIZE(addr); ++i)
++ mbedtls_md_hmac_update(&ctx, addr[i], len[i]);
++ mbedtls_md_hmac_finish(&ctx, hash);
++ os_memcpy(buf, hash, buf_len);
++ buf += buf_len;
++ forced_memzero(hash, mac_len);
++ }
++
++ /* Mask out unused bits in last octet if it does not use all the bits */
++ if ((buf_len_bits &= 0x7))
++ buf[-1] &= (u8)(0xff << (8 - buf_len_bits));
++
++ mbedtls_md_free(&ctx);
++ return 0;
++}
++
++#ifdef MBEDTLS_SHA512_C
++int sha512_prf(const u8 *key, size_t key_len, const char *label,
++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
++{
++ return hmac_prf_bits(key, key_len, label, data, data_len, buf,
++ buf_len * 8, MBEDTLS_MD_SHA512);
++}
++
++int sha384_prf(const u8 *key, size_t key_len, const char *label,
++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
++{
++ return hmac_prf_bits(key, key_len, label, data, data_len, buf,
++ buf_len * 8, MBEDTLS_MD_SHA384);
++}
++#endif
++
++#ifdef MBEDTLS_SHA256_C
++int sha256_prf(const u8 *key, size_t key_len, const char *label,
++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
++{
++ return hmac_prf_bits(key, key_len, label, data, data_len, buf,
++ buf_len * 8, MBEDTLS_MD_SHA256);
++}
++
++int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
++ const u8 *data, size_t data_len, u8 *buf,
++ size_t buf_len_bits)
++{
++ return hmac_prf_bits(key, key_len, label, data, data_len, buf,
++ buf_len_bits, MBEDTLS_MD_SHA256);
++}
++#endif
++
++#endif /* MBEDTLS_SHA256_C || MBEDTLS_SHA512_C */
++
++
++#ifdef MBEDTLS_SHA1_C
++
++/* sha1-prf.c */
++
++/* sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) */
++
++int sha1_prf(const u8 *key, size_t key_len, const char *label,
++ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
++{
++ /*(note: algorithm differs from hmac_prf_bits() */
++ /*(note: smaller code size instead of expanding hmac_sha1_vector()
++ * as is done in hmac_prf_bits(); not expecting large num of loops) */
++ u8 counter = 0;
++ const u8 *addr[] = { (u8 *)label, data, &counter };
++ const size_t len[] = { os_strlen(label)+1, data_len, 1 };
++
++ for (; buf_len >= SHA1_MAC_LEN; buf_len -= SHA1_MAC_LEN, ++counter) {
++ if (hmac_sha1_vector(key, key_len, 3, addr, len, buf))
++ return -1;
++ buf += SHA1_MAC_LEN;
++ }
++
++ if (buf_len) {
++ u8 hash[SHA1_MAC_LEN];
++ if (hmac_sha1_vector(key, key_len, 3, addr, len, hash))
++ return -1;
++ os_memcpy(buf, hash, buf_len);
++ forced_memzero(hash, sizeof(hash));
++ }
++
++ return 0;
++}
++
++#ifdef CRYPTO_MBEDTLS_SHA1_T_PRF
++
++/* sha1-tprf.c */
++
++/* sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) (RFC 4851,Section 5.5)*/
++
++int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
++ const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
++{
++ /*(note: algorithm differs from hmac_prf_bits() and hmac_kdf() above)*/
++ /*(note: smaller code size instead of expanding hmac_sha1_vector()
++ * as is done in hmac_prf_bits(); not expecting large num of loops) */
++ u8 ctr;
++ u16 olen = host_to_be16(buf_len);
++ const u8 *addr[] = { buf, (u8 *)label, seed, (u8 *)&olen, &ctr };
++ size_t len[] = { 0, os_strlen(label)+1, seed_len, 2, 1 };
++
++ for (ctr = 1; buf_len >= SHA1_MAC_LEN; buf_len -= SHA1_MAC_LEN, ++ctr) {
++ if (hmac_sha1_vector(key, key_len, 5, addr, len, buf))
++ return -1;
++ addr[0] = buf;
++ buf += SHA1_MAC_LEN;
++ len[0] = SHA1_MAC_LEN; /*(include digest in subsequent rounds)*/
++ }
++
++ if (buf_len) {
++ u8 hash[SHA1_MAC_LEN];
++ if (hmac_sha1_vector(key, key_len, 5, addr, len, hash))
++ return -1;
++ os_memcpy(buf, hash, buf_len);
++ forced_memzero(hash, sizeof(hash));
++ }
++
++ return 0;
++}
++
++#endif /* CRYPTO_MBEDTLS_SHA1_T_PRF */
++
++#endif /* MBEDTLS_SHA1_C */
++
++
++#ifdef CRYPTO_MBEDTLS_DES_ENCRYPT
++#ifdef MBEDTLS_DES_C
++#include <mbedtls/des.h>
++int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
++{
++ u8 pkey[8], next, tmp;
++ int i;
++
++ /* Add parity bits to the key */
++ next = 0;
++ for (i = 0; i < 7; i++) {
++ tmp = key[i];
++ pkey[i] = (tmp >> i) | next | 1;
++ next = tmp << (7 - i);
++ }
++ pkey[i] = next | 1;
++
++ mbedtls_des_context des;
++ mbedtls_des_init(&des);
++ int ret = mbedtls_des_setkey_enc(&des, pkey)
++ || mbedtls_des_crypt_ecb(&des, clear, cypher) ? -1 : 0;
++ mbedtls_des_free(&des);
++ return ret;
++}
++#else
++#include "des-internal.c"/* pull in hostap local implementation */
++#endif
++#endif
++
++
++#ifdef CRYPTO_MBEDTLS_PBKDF2_SHA1
++/* sha1-pbkdf2.c */
++#include <mbedtls/pkcs5.h>
++int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
++ int iterations, u8 *buf, size_t buflen)
++{
++ #if MBEDTLS_VERSION_NUMBER >= 0x03020200 /* mbedtls 3.2.2 */
++ return mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1,
++ (const u8 *)passphrase, os_strlen(passphrase),
++ ssid, ssid_len, iterations, 32, buf) ? -1 : 0;
++ #else
++ const mbedtls_md_info_t *md_info;
++ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
++ if (md_info == NULL)
++ return -1;
++ mbedtls_md_context_t ctx;
++ mbedtls_md_init(&ctx);
++ int ret = mbedtls_md_setup(&ctx, md_info, 1)
++ || mbedtls_pkcs5_pbkdf2_hmac(&ctx,
++ (const u8 *)passphrase, os_strlen(passphrase),
++ ssid, ssid_len, iterations, 32, buf) ? -1 : 0;
++ mbedtls_md_free(&ctx);
++ return ret;
++ #endif
++}
++#endif
++
++
++/*#include "aes.h"*/ /* prototypes also included in "crypto.h" */
++
++static void *aes_crypt_init_mode(const u8 *key, size_t len, int mode)
++{
++ mbedtls_aes_context *aes = os_malloc(sizeof(*aes));
++ if (!aes)
++ return NULL;
++
++ mbedtls_aes_init(aes);
++ if ((mode == MBEDTLS_AES_ENCRYPT
++ ? mbedtls_aes_setkey_enc(aes, key, len * 8)
++ : mbedtls_aes_setkey_dec(aes, key, len * 8)) == 0)
++ return aes;
++
++ mbedtls_aes_free(aes);
++ os_free(aes);
++ return NULL;
++}
++
++void *aes_encrypt_init(const u8 *key, size_t len)
++{
++ return aes_crypt_init_mode(key, len, MBEDTLS_AES_ENCRYPT);
++}
++
++int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
++{
++ return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, plain, crypt);
++}
++
++void aes_encrypt_deinit(void *ctx)
++{
++ mbedtls_aes_free(ctx);
++ os_free(ctx);
++}
++
++void *aes_decrypt_init(const u8 *key, size_t len)
++{
++ return aes_crypt_init_mode(key, len, MBEDTLS_AES_DECRYPT);
++}
++
++int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
++{
++ return mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_DECRYPT, crypt, plain);
++}
++
++void aes_decrypt_deinit(void *ctx)
++{
++ mbedtls_aes_free(ctx);
++ os_free(ctx);
++}
++
++
++#include "aes_wrap.h"
++
++
++#ifdef MBEDTLS_NIST_KW_C
++
++#include <mbedtls/nist_kw.h>
++
++/* aes-wrap.c */
++int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
++{
++ mbedtls_nist_kw_context ctx;
++ mbedtls_nist_kw_init(&ctx);
++ size_t olen;
++ int ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
++ kek, kek_len*8, 1)
++ || mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, plain, n*8,
++ cipher, &olen, (n+1)*8) ? -1 : 0;
++ mbedtls_nist_kw_free(&ctx);
++ return ret;
++}
++
++/* aes-unwrap.c */
++int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain)
++{
++ mbedtls_nist_kw_context ctx;
++ mbedtls_nist_kw_init(&ctx);
++ size_t olen;
++ int ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
++ kek, kek_len*8, 0)
++ || mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW, cipher,
++ (n+1)*8, plain, &olen, n*8) ? -1 : 0;
++ mbedtls_nist_kw_free(&ctx);
++ return ret;
++}
++
++#else
++
++#ifndef CRYPTO_MBEDTLS_CONFIG_FIPS
++#include "aes-wrap.c" /* pull in hostap local implementation */
++#include "aes-unwrap.c" /* pull in hostap local implementation */
++#endif
++
++#endif /* MBEDTLS_NIST_KW_C */
++
++
++#ifdef MBEDTLS_CMAC_C
++
++/* aes-omac1.c */
++
++#include <mbedtls/cmac.h>
++
++int omac1_aes_vector(
++ const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[],
++ const size_t *len, u8 *mac)
++{
++ mbedtls_cipher_type_t cipher_type;
++ switch (key_len) {
++ case 16: cipher_type = MBEDTLS_CIPHER_AES_128_ECB; break;
++ case 24: cipher_type = MBEDTLS_CIPHER_AES_192_ECB; break;
++ case 32: cipher_type = MBEDTLS_CIPHER_AES_256_ECB; break;
++ default: return -1;
++ }
++ const mbedtls_cipher_info_t *cipher_info;
++ cipher_info = mbedtls_cipher_info_from_type(cipher_type);
++ if (cipher_info == NULL)
++ return -1;
++
++ mbedtls_cipher_context_t ctx;
++ mbedtls_cipher_init(&ctx);
++ int ret = -1;
++ if (mbedtls_cipher_setup(&ctx, cipher_info) == 0
++ && mbedtls_cipher_cmac_starts(&ctx, key, key_len*8) == 0) {
++ ret = 0;
++ for (size_t i = 0; i < num_elem && ret == 0; ++i)
++ ret = mbedtls_cipher_cmac_update(&ctx, addr[i], len[i]);
++ }
++ if (ret == 0)
++ ret = mbedtls_cipher_cmac_finish(&ctx, mac);
++ mbedtls_cipher_free(&ctx);
++ return ret ? -1 : 0;
++}
++
++int omac1_aes_128_vector(const u8 *key, size_t num_elem,
++ const u8 *addr[], const size_t *len,
++ u8 *mac)
++{
++ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
++}
++
++int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
++{
++ return omac1_aes_vector(key, 16, 1, &data, &data_len, mac);
++}
++
++int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
++{
++ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
++}
++
++#else
++
++#include "aes-omac1.c" /* pull in hostap local implementation */
++
++#ifndef MBEDTLS_AES_BLOCK_SIZE
++#define MBEDTLS_AES_BLOCK_SIZE 16
++#endif
++
++#endif /* MBEDTLS_CMAC_C */
++
++
++/* These interfaces can be inefficient when used in loops, as the overhead of
++ * initialization each call is large for each block input (e.g. 16 bytes) */
++
++
++/* aes-encblock.c */
++int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
++{
++ mbedtls_aes_context aes;
++ mbedtls_aes_init(&aes);
++ int ret = mbedtls_aes_setkey_enc(&aes, key, 128)
++ || mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, in, out)
++ ? -1
++ : 0;
++ mbedtls_aes_free(&aes);
++ return ret;
++}
++
++
++/* aes-ctr.c */
++int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
++ u8 *data, size_t data_len)
++{
++ unsigned char counter[MBEDTLS_AES_BLOCK_SIZE];
++ unsigned char stream_block[MBEDTLS_AES_BLOCK_SIZE];
++ os_memcpy(counter, nonce, MBEDTLS_AES_BLOCK_SIZE);/*(must be writable)*/
++
++ mbedtls_aes_context ctx;
++ mbedtls_aes_init(&ctx);
++ size_t nc_off = 0;
++ int ret = mbedtls_aes_setkey_enc(&ctx, key, key_len*8)
++ || mbedtls_aes_crypt_ctr(&ctx, data_len, &nc_off,
++ counter, stream_block,
++ data, data) ? -1 : 0;
++ forced_memzero(stream_block, sizeof(stream_block));
++ mbedtls_aes_free(&ctx);
++ return ret;
++}
++
++int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
++ u8 *data, size_t data_len)
++{
++ return aes_ctr_encrypt(key, 16, nonce, data, data_len);
++}
++
++
++/* aes-cbc.c */
++static int aes_128_cbc_oper(const u8 *key, const u8 *iv,
++ u8 *data, size_t data_len, int mode)
++{
++ unsigned char ivec[MBEDTLS_AES_BLOCK_SIZE];
++ os_memcpy(ivec, iv, MBEDTLS_AES_BLOCK_SIZE); /*(must be writable)*/
++
++ mbedtls_aes_context ctx;
++ mbedtls_aes_init(&ctx);
++ int ret = (mode == MBEDTLS_AES_ENCRYPT
++ ? mbedtls_aes_setkey_enc(&ctx, key, 128)
++ : mbedtls_aes_setkey_dec(&ctx, key, 128))
++ || mbedtls_aes_crypt_cbc(&ctx, mode, data_len, ivec, data, data);
++ mbedtls_aes_free(&ctx);
++ return ret ? -1 : 0;
++}
++
++int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
++{
++ return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_ENCRYPT);
++}
++
++int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
++{
++ return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_DECRYPT);
++}
++
++
++/*
++ * Much of the following is documented in crypto.h as for CONFIG_TLS=internal
++ * but such comments are not accurate:
++ *
++ * "This function is only used with internal TLSv1 implementation
++ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
++ * to implement this."
++ */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_CIPHER
++
++#include <mbedtls/cipher.h>
++
++struct crypto_cipher
++{
++ mbedtls_cipher_context_t ctx_enc;
++ mbedtls_cipher_context_t ctx_dec;
++};
++
++struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
++ const u8 *iv, const u8 *key,
++ size_t key_len)
++{
++ /* IKEv2 src/eap_common/ikev2_common.c:ikev2_{encr,decr}_encrypt()
++ * uses one of CRYPTO_CIPHER_ALG_AES or CRYPTO_CIPHER_ALG_3DES */
++
++ mbedtls_cipher_type_t cipher_type;
++ size_t iv_len;
++ switch (alg) {
++ #ifdef MBEDTLS_ARC4_C
++ #if 0
++ case CRYPTO_CIPHER_ALG_RC4:
++ cipher_type = MBEDTLS_CIPHER_ARC4_128;
++ iv_len = 0;
++ break;
++ #endif
++ #endif
++ #ifdef MBEDTLS_AES_C
++ case CRYPTO_CIPHER_ALG_AES:
++ if (key_len == 16) cipher_type = MBEDTLS_CIPHER_AES_128_CTR;
++ if (key_len == 24) cipher_type = MBEDTLS_CIPHER_AES_192_CTR;
++ if (key_len == 32) cipher_type = MBEDTLS_CIPHER_AES_256_CTR;
++ iv_len = 16;
++ break;
++ #endif
++ #ifdef MBEDTLS_DES_C
++ case CRYPTO_CIPHER_ALG_3DES:
++ cipher_type = MBEDTLS_CIPHER_DES_EDE3_CBC;
++ iv_len = 8;
++ break;
++ #if 0
++ case CRYPTO_CIPHER_ALG_DES:
++ cipher_type = MBEDTLS_CIPHER_DES_CBC;
++ iv_len = 8;
++ break;
++ #endif
++ #endif
++ default:
++ return NULL;
++ }
++
++ const mbedtls_cipher_info_t *cipher_info;
++ cipher_info = mbedtls_cipher_info_from_type(cipher_type);
++ if (cipher_info == NULL)
++ return NULL;
++
++ key_len *= 8; /* key_bitlen */
++ #if 0 /*(were key_bitlen not already available)*/
++ #if MBEDTLS_VERSION_NUMBER >= 0x03010000 /* mbedtls 3.1.0 */
++ key_len = mbedtls_cipher_info_get_key_bitlen(cipher_info);
++ #else
++ key_len = cipher_info->MBEDTLS_PRIVATE(key_bitlen);
++ #endif
++ #endif
++
++ #if 0 /*(were iv_len not known above, would need MBEDTLS_PRIVATE(iv_size))*/
++ iv_len = cipher_info->MBEDTLS_PRIVATE(iv_size);
++ #endif
++
++ struct crypto_cipher *ctx = os_malloc(sizeof(*ctx));
++ if (!ctx)
++ return NULL;
++
++ mbedtls_cipher_init(&ctx->ctx_enc);
++ mbedtls_cipher_init(&ctx->ctx_dec);
++ if ( mbedtls_cipher_setup(&ctx->ctx_enc,cipher_info) == 0
++ && mbedtls_cipher_setup(&ctx->ctx_dec,cipher_info) == 0
++ && mbedtls_cipher_setkey(&ctx->ctx_enc,key,key_len,MBEDTLS_ENCRYPT) == 0
++ && mbedtls_cipher_setkey(&ctx->ctx_dec,key,key_len,MBEDTLS_DECRYPT) == 0
++ && mbedtls_cipher_set_iv(&ctx->ctx_enc,iv,iv_len) == 0
++ && mbedtls_cipher_set_iv(&ctx->ctx_dec,iv,iv_len) == 0
++ && mbedtls_cipher_reset(&ctx->ctx_enc) == 0
++ && mbedtls_cipher_reset(&ctx->ctx_dec) == 0) {
++ return ctx;
++ }
++
++ mbedtls_cipher_free(&ctx->ctx_enc);
++ mbedtls_cipher_free(&ctx->ctx_dec);
++ os_free(ctx);
++ return NULL;
++}
++
++int crypto_cipher_encrypt(struct crypto_cipher *ctx,
++ const u8 *plain, u8 *crypt, size_t len)
++{
++ size_t olen = 0; /*(poor interface above; unknown size of u8 *crypt)*/
++ return (mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen)
++ || mbedtls_cipher_finish(&ctx->ctx_enc, crypt + olen, &olen)) ? -1 : 0;
++}
++
++int crypto_cipher_decrypt(struct crypto_cipher *ctx,
++ const u8 *crypt, u8 *plain, size_t len)
++{
++ size_t olen = 0; /*(poor interface above; unknown size of u8 *plain)*/
++ return (mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen)
++ || mbedtls_cipher_finish(&ctx->ctx_dec, plain + olen, &olen)) ? -1 : 0;
++}
++
++void crypto_cipher_deinit(struct crypto_cipher *ctx)
++{
++ mbedtls_cipher_free(&ctx->ctx_enc);
++ mbedtls_cipher_free(&ctx->ctx_dec);
++ os_free(ctx);
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_CIPHER */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_HASH
++
++struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
++ size_t key_len)
++{
++ mbedtls_md_type_t md_type;
++ int is_hmac = 0;
++
++ switch (alg) {
++ #ifdef MBEDTLS_MD5_C
++ case CRYPTO_HASH_ALG_MD5:
++ md_type = MBEDTLS_MD_MD5;
++ break;
++ #endif
++ #ifdef MBEDTLS_SHA1_C
++ case CRYPTO_HASH_ALG_SHA1:
++ md_type = MBEDTLS_MD_SHA1;
++ break;
++ #endif
++ #ifdef MBEDTLS_MD5_C
++ case CRYPTO_HASH_ALG_HMAC_MD5:
++ md_type = MBEDTLS_MD_MD5;
++ is_hmac = 1;
++ break;
++ #endif
++ #ifdef MBEDTLS_SHA1_C
++ case CRYPTO_HASH_ALG_HMAC_SHA1:
++ md_type = MBEDTLS_MD_SHA1;
++ is_hmac = 1;
++ break;
++ #endif
++ #ifdef MBEDTLS_SHA256_C
++ case CRYPTO_HASH_ALG_SHA256:
++ md_type = MBEDTLS_MD_SHA256;
++ break;
++ case CRYPTO_HASH_ALG_HMAC_SHA256:
++ md_type = MBEDTLS_MD_SHA256;
++ is_hmac = 1;
++ break;
++ #endif
++ #ifdef MBEDTLS_SHA512_C
++ case CRYPTO_HASH_ALG_SHA384:
++ md_type = MBEDTLS_MD_SHA384;
++ break;
++ case CRYPTO_HASH_ALG_SHA512:
++ md_type = MBEDTLS_MD_SHA512;
++ break;
++ #endif
++ default:
++ return NULL;
++ }
++
++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
++ if (!md_info)
++ return NULL;
++
++ mbedtls_md_context_t *mctx = os_malloc(sizeof(*mctx));
++ if (mctx == NULL)
++ return NULL;
++
++ mbedtls_md_init(mctx);
++ if (mbedtls_md_setup(mctx, md_info, is_hmac) != 0) {
++ os_free(mctx);
++ return NULL;
++ }
++
++ if (is_hmac)
++ mbedtls_md_hmac_starts(mctx, key, key_len);
++ else
++ mbedtls_md_starts(mctx);
++ return (struct crypto_hash *)((uintptr_t)mctx | is_hmac);
++}
++
++void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
++{
++ mbedtls_md_context_t *mctx = (mbedtls_md_context_t*)((uintptr_t)ctx & ~1uL);
++ #if 0
++ /*(mbedtls_md_hmac_update() and mbedtls_md_update()
++ * make same modifications under the hood in mbedtls)*/
++ if ((uintptr_t)ctx & 1uL)
++ mbedtls_md_hmac_update(mctx, data, len);
++ else
++ #endif
++ mbedtls_md_update(mctx, data, len);
++}
++
++int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
++{
++ mbedtls_md_context_t *mctx = (mbedtls_md_context_t*)((uintptr_t)ctx & ~1uL);
++ if (mac != NULL && len != NULL) { /*(NULL if caller just freeing context)*/
++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */
++ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_ctx(mctx);
++ #else
++ const mbedtls_md_info_t *md_info = mctx->MBEDTLS_PRIVATE(md_info);
++ #endif
++ size_t maclen = mbedtls_md_get_size(md_info);
++ if (*len < maclen) {
++ *len = maclen;
++ /*(note: ctx not freed; can call again with larger *len)*/
++ return -1;
++ }
++ *len = maclen;
++ if ((uintptr_t)ctx & 1uL)
++ mbedtls_md_hmac_finish(mctx, mac);
++ else
++ mbedtls_md_finish(mctx, mac);
++ }
++ mbedtls_md_free(mctx);
++ os_free(mctx);
++ return 0;
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_HASH */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_BIGNUM
++
++#include <mbedtls/bignum.h>
++
++/* crypto.h bignum interfaces */
++
++struct crypto_bignum *crypto_bignum_init(void)
++{
++ mbedtls_mpi *bn = os_malloc(sizeof(*bn));
++ if (bn)
++ mbedtls_mpi_init(bn);
++ return (struct crypto_bignum *)bn;
++}
++
++struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)
++{
++ mbedtls_mpi *bn = os_malloc(sizeof(*bn));
++ if (bn) {
++ mbedtls_mpi_init(bn);
++ if (mbedtls_mpi_read_binary(bn, buf, len) == 0)
++ return (struct crypto_bignum *)bn;
++ }
++
++ os_free(bn);
++ return NULL;
++}
++
++struct crypto_bignum *crypto_bignum_init_uint(unsigned int val)
++{
++ #if 0 /*(hostap use of this interface passes int, not uint)*/
++ val = host_to_be32(val);
++ return crypto_bignum_init_set((const u8 *)&val, sizeof(val));
++ #else
++ mbedtls_mpi *bn = os_malloc(sizeof(*bn));
++ if (bn) {
++ mbedtls_mpi_init(bn);
++ if (mbedtls_mpi_lset(bn, (int)val) == 0)
++ return (struct crypto_bignum *)bn;
++ }
++
++ os_free(bn);
++ return NULL;
++ #endif
++}
++
++void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
++{
++ mbedtls_mpi_free((mbedtls_mpi *)n);
++ os_free(n);
++}
++
++int crypto_bignum_to_bin(const struct crypto_bignum *a,
++ u8 *buf, size_t buflen, size_t padlen)
++{
++ size_t n = mbedtls_mpi_size((mbedtls_mpi *)a);
++ if (n < padlen)
++ n = padlen;
++ return n > buflen || mbedtls_mpi_write_binary((mbedtls_mpi *)a, buf, n)
++ ? -1
++ : (int)(n);
++}
++
++int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
++{
++ /*assert(r != m);*//* r must not be same as m for mbedtls_mpi_random()*/
++ #if MBEDTLS_VERSION_NUMBER >= 0x021B0000 /* mbedtls 2.27.0 */
++ return mbedtls_mpi_random((mbedtls_mpi *)r, 0, (mbedtls_mpi *)m,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) ? -1 : 0;
++ #else
++ /* (needed by EAP_PWD, SAE, DPP) */
++ wpa_printf(MSG_ERROR,
++ "mbedtls 2.27.0 or later required for mbedtls_mpi_random()");
++ return -1;
++ #endif
++}
++
++int crypto_bignum_add(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ struct crypto_bignum *c)
++{
++ return mbedtls_mpi_add_mpi((mbedtls_mpi *)c,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b) ? -1 : 0;
++}
++
++int crypto_bignum_mod(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ struct crypto_bignum *c)
++{
++ return mbedtls_mpi_mod_mpi((mbedtls_mpi *)c,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b) ? -1 : 0;
++}
++
++int crypto_bignum_exptmod(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ const struct crypto_bignum *c,
++ struct crypto_bignum *d)
++{
++ /* (check if input params match d; d is the result) */
++ /* (a == d) is ok in current mbedtls implementation */
++ if (b == d || c == d) { /*(not ok; store result in intermediate)*/
++ mbedtls_mpi R;
++ mbedtls_mpi_init(&R);
++ int rc = mbedtls_mpi_exp_mod(&R,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b,
++ (const mbedtls_mpi *)c,
++ NULL)
++ || mbedtls_mpi_copy((mbedtls_mpi *)d, &R) ? -1 : 0;
++ mbedtls_mpi_free(&R);
++ return rc;
++ }
++ else {
++ return mbedtls_mpi_exp_mod((mbedtls_mpi *)d,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b,
++ (const mbedtls_mpi *)c,
++ NULL) ? -1 : 0;
++ }
++}
++
++int crypto_bignum_inverse(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ struct crypto_bignum *c)
++{
++ return mbedtls_mpi_inv_mod((mbedtls_mpi *)c,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b) ? -1 : 0;
++}
++
++int crypto_bignum_sub(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ struct crypto_bignum *c)
++{
++ return mbedtls_mpi_sub_mpi((mbedtls_mpi *)c,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b) ? -1 : 0;
++}
++
++int crypto_bignum_div(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ struct crypto_bignum *c)
++{
++ /*(most current use of this crypto.h interface has a == c (result),
++ * so store result in an intermediate to avoid overwritten input)*/
++ mbedtls_mpi R;
++ mbedtls_mpi_init(&R);
++ int rc = mbedtls_mpi_div_mpi(&R, NULL,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b)
++ || mbedtls_mpi_copy((mbedtls_mpi *)c, &R) ? -1 : 0;
++ mbedtls_mpi_free(&R);
++ return rc;
++}
++
++int crypto_bignum_addmod(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ const struct crypto_bignum *c,
++ struct crypto_bignum *d)
++{
++ return mbedtls_mpi_add_mpi((mbedtls_mpi *)d,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b)
++ || mbedtls_mpi_mod_mpi((mbedtls_mpi *)d,
++ (mbedtls_mpi *)d,
++ (const mbedtls_mpi *)c) ? -1 : 0;
++}
++
++int crypto_bignum_mulmod(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ const struct crypto_bignum *c,
++ struct crypto_bignum *d)
++{
++ return mbedtls_mpi_mul_mpi((mbedtls_mpi *)d,
++ (const mbedtls_mpi *)a,
++ (const mbedtls_mpi *)b)
++ || mbedtls_mpi_mod_mpi((mbedtls_mpi *)d,
++ (mbedtls_mpi *)d,
++ (const mbedtls_mpi *)c) ? -1 : 0;
++}
++
++int crypto_bignum_sqrmod(const struct crypto_bignum *a,
++ const struct crypto_bignum *b,
++ struct crypto_bignum *c)
++{
++ #if 1
++ return crypto_bignum_mulmod(a, a, b, c);
++ #else
++ mbedtls_mpi bn;
++ mbedtls_mpi_init(&bn);
++ if (mbedtls_mpi_lset(&bn, 2)) /* alt?: mbedtls_mpi_set_bit(&bn, 1) */
++ return -1;
++ int ret = mbedtls_mpi_exp_mod((mbedtls_mpi *)c,
++ (const mbedtls_mpi *)a, &bn,
++ (const mbedtls_mpi *)b, NULL) ? -1 : 0;
++ mbedtls_mpi_free(&bn);
++ return ret;
++ #endif
++}
++
++int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
++ struct crypto_bignum *r)
++{
++ return mbedtls_mpi_copy((mbedtls_mpi *)r, (const mbedtls_mpi *)a)
++ || mbedtls_mpi_shift_r((mbedtls_mpi *)r, n) ? -1 : 0;
++}
++
++int crypto_bignum_cmp(const struct crypto_bignum *a,
++ const struct crypto_bignum *b)
++{
++ return mbedtls_mpi_cmp_mpi((const mbedtls_mpi *)a, (const mbedtls_mpi *)b);
++}
++
++int crypto_bignum_is_zero(const struct crypto_bignum *a)
++{
++ /* XXX: src/common/sae.c:sswu() contains comment:
++ * "TODO: Make sure crypto_bignum_is_zero() is constant time"
++ * Note: mbedtls_mpi_cmp_int() *is not* constant time */
++ return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 0) == 0);
++}
++
++int crypto_bignum_is_one(const struct crypto_bignum *a)
++{
++ return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 1) == 0);
++}
++
++int crypto_bignum_is_odd(const struct crypto_bignum *a)
++{
++ return mbedtls_mpi_get_bit((const mbedtls_mpi *)a, 0);
++}
++
++#include "utils/const_time.h"
++int crypto_bignum_legendre(const struct crypto_bignum *a,
++ const struct crypto_bignum *p)
++{
++ /* Security Note:
++ * mbedtls_mpi_exp_mod() is not documented to run in constant time,
++ * though mbedtls/library/bignum.c uses constant_time_internal.h funcs.
++ * Compare to crypto_openssl.c:crypto_bignum_legendre()
++ * which uses openssl BN_mod_exp_mont_consttime()
++ * mbedtls/library/ecp.c has further countermeasures to timing attacks,
++ * (but ecp.c funcs are not used here) */
++
++ mbedtls_mpi exp, tmp;
++ mbedtls_mpi_init(&exp);
++ mbedtls_mpi_init(&tmp);
++
++ /* exp = (p-1) / 2 */
++ int res;
++ if (mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *)p, 1) == 0
++ && mbedtls_mpi_shift_r(&exp, 1) == 0
++ && mbedtls_mpi_exp_mod(&tmp, (const mbedtls_mpi *)a, &exp,
++ (const mbedtls_mpi *)p, NULL) == 0) {
++ /*(modified from crypto_openssl.c:crypto_bignum_legendre())*/
++ /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need
++ * to use constant time selection to avoid branches here. */
++ unsigned int mask;
++ res = -1;
++ mask = const_time_eq((mbedtls_mpi_cmp_int(&tmp, 1) == 0), 1);
++ res = const_time_select_int(mask, 1, res);
++ mask = const_time_eq((mbedtls_mpi_cmp_int(&tmp, 0) == 0), 1);
++ res = const_time_select_int(mask, 0, res);
++ } else {
++ res = -2;
++ }
++
++ mbedtls_mpi_free(&tmp);
++ mbedtls_mpi_free(&exp);
++ return res;
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_BIGNUM */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_DH
++
++/* crypto_internal-modexp.c */
++
++#include <mbedtls/bignum.h>
++#include <mbedtls/dhm.h>
++
++#if 0 /* crypto_dh_init() and crypto_dh_derive_secret() prefer to use mbedtls */
++int crypto_mod_exp(const u8 *base, size_t base_len,
++ const u8 *power, size_t power_len,
++ const u8 *modulus, size_t modulus_len,
++ u8 *result, size_t *result_len)
++{
++ mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result;
++ mbedtls_mpi_init(&bn_base);
++ mbedtls_mpi_init(&bn_exp);
++ mbedtls_mpi_init(&bn_modulus);
++ mbedtls_mpi_init(&bn_result);
++
++ size_t len;
++ int ret = mbedtls_mpi_read_binary(&bn_base, base, base_len)
++ || mbedtls_mpi_read_binary(&bn_exp, power, power_len)
++ || mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len)
++ || mbedtls_mpi_exp_mod(&bn_result,&bn_base,&bn_exp,&bn_modulus,NULL)
++ || (len = mbedtls_mpi_size(&bn_result)) > *result_len
++ || mbedtls_mpi_write_binary(&bn_result, result, (*result_len = len))
++ ? -1
++ : 0;
++
++ mbedtls_mpi_free(&bn_base);
++ mbedtls_mpi_free(&bn_exp);
++ mbedtls_mpi_free(&bn_modulus);
++ mbedtls_mpi_free(&bn_result);
++ return ret;
++}
++#endif
++
++static int crypto_mbedtls_dh_set_bin_pg(mbedtls_dhm_context *ctx, u8 generator,
++ const u8 *prime, size_t prime_len)
++{
++ /*(could set these directly in MBEDTLS_PRIVATE members)*/
++ mbedtls_mpi P, G;
++ mbedtls_mpi_init(&P);
++ mbedtls_mpi_init(&G);
++ int ret = mbedtls_mpi_lset(&G, generator)
++ || mbedtls_mpi_read_binary(&P, prime, prime_len)
++ || mbedtls_dhm_set_group(ctx, &P, &G);
++ mbedtls_mpi_free(&P);
++ mbedtls_mpi_free(&G);
++ return ret;
++}
++
++__attribute_noinline__
++static int crypto_mbedtls_dh_init_public(mbedtls_dhm_context *ctx, u8 generator,
++ const u8 *prime, size_t prime_len,
++ u8 *privkey, u8 *pubkey)
++{
++ if (crypto_mbedtls_dh_set_bin_pg(ctx, generator, prime, prime_len)
++ || mbedtls_dhm_make_public(ctx, (int)prime_len, pubkey, prime_len,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()))
++ return -1;
++
++ /*(enable later when upstream mbedtls interface changes require)*/
++ #if 0 && MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ mbedtls_mpi X;
++ mbedtls_mpi_init(&X);
++ int ret = mbedtls_dhm_get_value(ctx, MBEDTLS_DHM_PARAM_X, &X)
++ || mbedtls_mpi_write_binary(&X, privkey, prime_len) ? -1 : 0;
++ mbedtls_mpi_free(&X);
++ return ret;
++ #else
++ return mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(X),
++ privkey, prime_len) ? -1 : 0;
++ #endif
++}
++
++int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
++ u8 *pubkey)
++{
++ #if 0 /*(crypto_dh_init() duplicated (and identical) in crypto_*.c modules)*/
++ size_t pubkey_len, pad;
++
++ if (os_get_random(privkey, prime_len) < 0)
++ return -1;
++ if (os_memcmp(privkey, prime, prime_len) > 0) {
++ /* Make sure private value is smaller than prime */
++ privkey[0] = 0;
++ }
++
++ pubkey_len = prime_len;
++ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
++ pubkey, &pubkey_len) < 0)
++ return -1;
++ if (pubkey_len < prime_len) {
++ pad = prime_len - pubkey_len;
++ os_memmove(pubkey + pad, pubkey, pubkey_len);
++ os_memset(pubkey, 0, pad);
++ }
++
++ return 0;
++ #else
++ /* Prefer to use mbedtls to derive our public/private key, as doing so
++ * leverages mbedtls to properly format output and to perform blinding*/
++ mbedtls_dhm_context ctx;
++ mbedtls_dhm_init(&ctx);
++ int ret = crypto_mbedtls_dh_init_public(&ctx, generator, prime,
++ prime_len, privkey, pubkey);
++ mbedtls_dhm_free(&ctx);
++ return ret;
++ #endif
++}
++
++/*(crypto_dh_derive_secret() could be implemented using crypto.h APIs
++ * instead of being reimplemented in each crypto_*.c)*/
++int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
++ const u8 *order, size_t order_len,
++ const u8 *privkey, size_t privkey_len,
++ const u8 *pubkey, size_t pubkey_len,
++ u8 *secret, size_t *len)
++{
++ #if 0
++ if (pubkey_len > prime_len ||
++ (pubkey_len == prime_len &&
++ os_memcmp(pubkey, prime, prime_len) >= 0))
++ return -1;
++
++ int res = 0;
++ mbedtls_mpi pub;
++ mbedtls_mpi_init(&pub);
++ if (mbedtls_mpi_read_binary(&pub, pubkey, pubkey_len)
++ || mbedtls_mpi_cmp_int(&pub, 1) <= 0) {
++ res = -1;
++ } else if (order) {
++ mbedtls_mpi p, q, tmp;
++ mbedtls_mpi_init(&p);
++ mbedtls_mpi_init(&q);
++ mbedtls_mpi_init(&tmp);
++
++ /* verify: pubkey^q == 1 mod p */
++ res = (mbedtls_mpi_read_binary(&p, prime, prime_len)
++ || mbedtls_mpi_read_binary(&q, order, order_len)
++ || mbedtls_mpi_exp_mod(&tmp, &pub, &q, &p, NULL)
++ || mbedtls_mpi_cmp_int(&tmp, 1) != 0);
++
++ mbedtls_mpi_free(&p);
++ mbedtls_mpi_free(&q);
++ mbedtls_mpi_free(&tmp);
++ }
++ mbedtls_mpi_free(&pub);
++
++ return (res == 0)
++ ? crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
++ prime, prime_len, secret, len)
++ : -1;
++ #else
++ /* Prefer to use mbedtls to derive DH shared secret, as doing so
++ * leverages mbedtls to validate params and to perform blinding.
++ *
++ * Attempt to reconstitute DH context to derive shared secret
++ * (due to limitations of the interface, which ought to pass context).
++ * Force provided G (our private key) into context without validation.
++ * Regenerating GX (our public key) not needed to derive shared secret.
++ */
++ /*(older compilers might not support VLAs)*/
++ /*unsigned char buf[2+prime_len+2+1+2+pubkey_len];*/
++ unsigned char buf[2+MBEDTLS_MPI_MAX_SIZE+2+1+2+MBEDTLS_MPI_MAX_SIZE];
++ unsigned char *p = buf + 2 + prime_len;
++ if (2+prime_len+2+1+2+pubkey_len > sizeof(buf))
++ return -1;
++ WPA_PUT_BE16(buf, prime_len); /*(2-byte big-endian size of prime)*/
++ p[0] = 0; /*(2-byte big-endian size of generator)*/
++ p[1] = 1;
++ p[2] = generator;
++ WPA_PUT_BE16(p+3, pubkey_len); /*(2-byte big-endian size of pubkey)*/
++ os_memcpy(p+5, pubkey, pubkey_len);
++ os_memcpy(buf+2, prime, prime_len);
++
++ mbedtls_dhm_context ctx;
++ mbedtls_dhm_init(&ctx);
++ p = buf;
++ int ret = mbedtls_dhm_read_params(&ctx, &p, p+2+prime_len+5+pubkey_len)
++ || mbedtls_mpi_read_binary(&ctx.MBEDTLS_PRIVATE(X),
++ privkey, privkey_len)
++ || mbedtls_dhm_calc_secret(&ctx, secret, *len, len,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) ? -1 : 0;
++ mbedtls_dhm_free(&ctx);
++ return ret;
++ #endif
++}
++
++/* dh_group5.c */
++
++#include "dh_group5.h"
++
++/* RFC3526_PRIME_1536[] and RFC3526_GENERATOR_1536[] from crypto_wolfssl.c */
++
++static const unsigned char RFC3526_PRIME_1536[] = {
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
++ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
++ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
++ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
++ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
++ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
++ 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
++ 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
++ 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++};
++
++static const unsigned char RFC3526_GENERATOR_1536[] = {
++ 0x02
++};
++
++void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
++{
++ const unsigned char * const prime = RFC3526_PRIME_1536;
++ const size_t prime_len = sizeof(RFC3526_PRIME_1536);
++ const u8 generator = *RFC3526_GENERATOR_1536;
++ struct wpabuf *wpubl = NULL, *wpriv = NULL;
++
++ mbedtls_dhm_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_dhm_init(ctx);
++
++ if ( (wpubl = wpabuf_alloc(prime_len))
++ && (wpriv = wpabuf_alloc(prime_len))
++ && crypto_mbedtls_dh_init_public(ctx, generator, prime, prime_len,
++ wpabuf_put(wpriv, prime_len),
++ wpabuf_put(wpubl, prime_len))==0) {
++ wpabuf_free(*publ);
++ wpabuf_clear_free(*priv);
++ *publ = wpubl;
++ *priv = wpriv;
++ return ctx;
++ }
++
++ wpabuf_clear_free(wpriv);
++ wpabuf_free(wpubl);
++ mbedtls_dhm_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++
++#ifdef CRYPTO_MBEDTLS_DH5_INIT_FIXED
++void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
++{
++ const unsigned char * const prime = RFC3526_PRIME_1536;
++ const size_t prime_len = sizeof(RFC3526_PRIME_1536);
++ const u8 generator = *RFC3526_GENERATOR_1536;
++
++ mbedtls_dhm_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_dhm_init(ctx);
++
++ if (crypto_mbedtls_dh_set_bin_pg(ctx, generator, prime, prime_len)==0
++ #if 0 /*(ignore; not required to derive shared secret)*/
++ && mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(GX),
++ wpabuf_head(publ),wpabuf_len(publ))==0
++ #endif
++ && mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(X),
++ wpabuf_head(priv),wpabuf_len(priv))==0) {
++ return ctx;
++ }
++
++ mbedtls_dhm_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++#endif
++
++struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
++ const struct wpabuf *own_private)
++{
++ /*((mbedtls_dhm_context *)ctx must already contain own_private)*/
++ /* mbedtls 2.x: prime_len = ctx->len; */
++ /* mbedtls 3.x: prime_len = mbedtls_dhm_get_len(ctx); */
++ size_t olen = sizeof(RFC3526_PRIME_1536); /*(sizeof(); prime known)*/
++ struct wpabuf *buf = wpabuf_alloc(olen);
++ if (buf == NULL)
++ return NULL;
++ if (mbedtls_dhm_read_public((mbedtls_dhm_context *)ctx,
++ wpabuf_head(peer_public),
++ wpabuf_len(peer_public)) == 0
++ && mbedtls_dhm_calc_secret(ctx, wpabuf_mhead(buf), olen, &olen,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) == 0) {
++ wpabuf_put(buf, olen);
++ return buf;
++ }
++
++ wpabuf_free(buf);
++ return NULL;
++}
++
++void dh5_free(void *ctx)
++{
++ mbedtls_dhm_free(ctx);
++ os_free(ctx);
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_DH */
++
++
++#if defined(CRYPTO_MBEDTLS_CRYPTO_ECDH) || defined(CRYPTO_MBEDTLS_CRYPTO_EC)
++
++#include <mbedtls/ecp.h>
++
++#define CRYPTO_EC_pbits(e) (((mbedtls_ecp_group *)(e))->pbits)
++#define CRYPTO_EC_plen(e) ((((mbedtls_ecp_group *)(e))->pbits+7)>>3)
++#define CRYPTO_EC_P(e) (&((mbedtls_ecp_group *)(e))->P)
++#define CRYPTO_EC_N(e) (&((mbedtls_ecp_group *)(e))->N)
++#define CRYPTO_EC_A(e) (&((mbedtls_ecp_group *)(e))->A)
++#define CRYPTO_EC_B(e) (&((mbedtls_ecp_group *)(e))->B)
++#define CRYPTO_EC_G(e) (&((mbedtls_ecp_group *)(e))->G)
++
++static mbedtls_ecp_group_id crypto_mbedtls_ecp_group_id_from_ike_id(int group)
++{
++ /* https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml */
++ switch (group) {
++ #ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED
++ case 19: return MBEDTLS_ECP_DP_SECP256R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED
++ case 20: return MBEDTLS_ECP_DP_SECP384R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED
++ case 21: return MBEDTLS_ECP_DP_SECP521R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP192R1_ENABLED
++ case 25: return MBEDTLS_ECP_DP_SECP192R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP224R1_ENABLED
++ case 26: return MBEDTLS_ECP_DP_SECP224R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP256R1_ENABLED
++ case 28: return MBEDTLS_ECP_DP_BP256R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP384R1_ENABLED
++ case 29: return MBEDTLS_ECP_DP_BP384R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP512R1_ENABLED
++ case 30: return MBEDTLS_ECP_DP_BP512R1;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED
++ case 31: return MBEDTLS_ECP_DP_CURVE25519;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED
++ case 32: return MBEDTLS_ECP_DP_CURVE448;
++ #endif
++ default: return MBEDTLS_ECP_DP_NONE;
++ }
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC
++static int crypto_mbedtls_ike_id_from_ecp_group_id(mbedtls_ecp_group_id grp_id)
++{
++ /* https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml */
++ /*(for crypto_ec_key_group())*/
++ switch (grp_id) {
++ #ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP256R1: return 19;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP384R1: return 20;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP521R1: return 21;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP192R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP192R1: return 25;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP224R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP224R1: return 26;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP256R1_ENABLED
++ case MBEDTLS_ECP_DP_BP256R1: return 28;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP384R1_ENABLED
++ case MBEDTLS_ECP_DP_BP384R1: return 29;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP512R1_ENABLED
++ case MBEDTLS_ECP_DP_BP512R1: return 30;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED
++ case MBEDTLS_ECP_DP_CURVE25519: return 31;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED
++ case MBEDTLS_ECP_DP_CURVE448: return 32;
++ #endif
++ default: return -1;
++ }
++}
++#endif
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_ECDH || CRYPTO_MBEDTLS_CRYPTO_EC */
++
++
++#if defined(CRYPTO_MBEDTLS_CRYPTO_ECDH) || defined(CRYPTO_MBEDTLS_CRYPTO_EC_DPP)
++
++#include <mbedtls/ecp.h>
++#include <mbedtls/pk.h>
++
++static int crypto_mbedtls_keypair_gen(int group, mbedtls_pk_context *pk)
++{
++ mbedtls_ecp_group_id grp_id =
++ crypto_mbedtls_ecp_group_id_from_ike_id(group);
++ if (grp_id == MBEDTLS_ECP_DP_NONE)
++ return -1;
++ const mbedtls_pk_info_t *pk_info =
++ mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
++ if (pk_info == NULL)
++ return -1;
++ return mbedtls_pk_setup(pk, pk_info)
++ || mbedtls_ecp_gen_key(grp_id, mbedtls_pk_ec(*pk),
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) ? -1 : 0;
++}
++
++#endif
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_ECDH
++
++#include <mbedtls/ecdh.h>
++#include <mbedtls/ecdsa.h>
++#include <mbedtls/ecp.h>
++#include <mbedtls/pk.h>
++
++/* wrap mbedtls_ecdh_context for more future-proof direct access to components
++ * (mbedtls_ecdh_context internal implementation may change between releases)
++ *
++ * If mbedtls_pk_context -- specifically underlying mbedtls_ecp_keypair --
++ * lifetime were guaranteed to be longer than that of mbedtls_ecdh_context,
++ * then mbedtls_pk_context or mbedtls_ecp_keypair could be stored in crypto_ecdh
++ * (or crypto_ec_key could be stored in crypto_ecdh, and crypto_ec_key could
++ * wrap mbedtls_ecp_keypair and components, to avoid MBEDTLS_PRIVATE access) */
++struct crypto_ecdh {
++ mbedtls_ecdh_context ctx;
++ mbedtls_ecp_group grp;
++ mbedtls_ecp_point Q;
++};
++
++struct crypto_ecdh * crypto_ecdh_init(int group)
++{
++ mbedtls_pk_context pk;
++ mbedtls_pk_init(&pk);
++ struct crypto_ecdh *ecdh = crypto_mbedtls_keypair_gen(group, &pk) == 0
++ ? crypto_ecdh_init2(group, (struct crypto_ec_key *)&pk)
++ : NULL;
++ mbedtls_pk_free(&pk);
++ return ecdh;
++}
++
++struct crypto_ecdh * crypto_ecdh_init2(int group,
++ struct crypto_ec_key *own_key)
++{
++ mbedtls_ecp_group_id grp_id =
++ crypto_mbedtls_ecp_group_id_from_ike_id(group);
++ if (grp_id == MBEDTLS_ECP_DP_NONE)
++ return NULL;
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)own_key);
++ struct crypto_ecdh *ecdh = os_malloc(sizeof(*ecdh));
++ if (ecdh == NULL)
++ return NULL;
++ mbedtls_ecdh_init(&ecdh->ctx);
++ mbedtls_ecp_group_init(&ecdh->grp);
++ mbedtls_ecp_point_init(&ecdh->Q);
++ if (mbedtls_ecdh_setup(&ecdh->ctx, grp_id) == 0
++ && mbedtls_ecdh_get_params(&ecdh->ctx,ecp_kp,MBEDTLS_ECDH_OURS) == 0) {
++ /* copy grp and Q for later use
++ * (retrieving this info later is more convoluted
++ * even if mbedtls_ecdh_make_public() is considered)*/
++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */
++ mbedtls_mpi d;
++ mbedtls_mpi_init(&d);
++ if (mbedtls_ecp_export(ecp_kp, &ecdh->grp, &d, &ecdh->Q) == 0) {
++ mbedtls_mpi_free(&d);
++ return ecdh;
++ }
++ mbedtls_mpi_free(&d);
++ #else
++ if (mbedtls_ecp_group_load(&ecdh->grp, grp_id) == 0
++ && mbedtls_ecp_copy(&ecdh->Q, &ecp_kp->MBEDTLS_PRIVATE(Q)) == 0)
++ return ecdh;
++ #endif
++ }
++
++ mbedtls_ecp_point_free(&ecdh->Q);
++ mbedtls_ecp_group_free(&ecdh->grp);
++ mbedtls_ecdh_free(&ecdh->ctx);
++ os_free(ecdh);
++ return NULL;
++}
++
++struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
++{
++ mbedtls_ecp_group *grp = &ecdh->grp;
++ size_t len = CRYPTO_EC_plen(grp);
++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
++ /* len */
++ #endif
++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
++ len = inc_y ? len*2+1 : len+1;
++ #endif
++ struct wpabuf *buf = wpabuf_alloc(len);
++ if (buf == NULL)
++ return NULL;
++ inc_y = inc_y ? MBEDTLS_ECP_PF_UNCOMPRESSED : MBEDTLS_ECP_PF_COMPRESSED;
++ if (mbedtls_ecp_point_write_binary(grp, &ecdh->Q, inc_y, &len,
++ wpabuf_mhead_u8(buf), len) == 0) {
++ wpabuf_put(buf, len);
++ return buf;
++ }
++
++ wpabuf_free(buf);
++ return NULL;
++}
++
++#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
++static int crypto_mbedtls_short_weierstrass_derive_y(mbedtls_ecp_group *grp,
++ mbedtls_mpi *bn,
++ int parity_bit)
++{
++ /* y^2 = x^3 + ax + b
++ * sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) */
++ mbedtls_mpi *cy2 = (mbedtls_mpi *)
++ crypto_ec_point_compute_y_sqr((struct crypto_ec *)grp,
++ (const struct crypto_bignum *)bn); /*x*/
++ if (cy2 == NULL)
++ return -1;
++
++ /*mbedtls_mpi_free(bn);*/
++ /*(reuse bn to store result (y))*/
++
++ mbedtls_mpi exp;
++ mbedtls_mpi_init(&exp);
++ int ret = mbedtls_mpi_get_bit(&grp->P, 0) != 1 /*(p = 3 mod 4)*/
++ || mbedtls_mpi_get_bit(&grp->P, 1) != 1 /*(p = 3 mod 4)*/
++ || mbedtls_mpi_add_int(&exp, &grp->P, 1)
++ || mbedtls_mpi_shift_r(&exp, 2)
++ || mbedtls_mpi_exp_mod(bn, cy2, &exp, &grp->P, NULL)
++ || (mbedtls_mpi_get_bit(bn, 0) != parity_bit
++ && mbedtls_mpi_sub_mpi(bn, &grp->P, bn));
++ mbedtls_mpi_free(&exp);
++ mbedtls_mpi_free(cy2);
++ os_free(cy2);
++ return ret;
++}
++#endif
++
++struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
++ const u8 *key, size_t len)
++{
++ if (len == 0) /*(invalid peer key)*/
++ return NULL;
++
++ mbedtls_ecp_group *grp = &ecdh->grp;
++
++ #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
++ /* add header for mbedtls_ecdh_read_public() */
++ u8 buf[256];
++ if (sizeof(buf)-1 < len)
++ return NULL;
++ buf[0] = (u8)(len);
++ os_memcpy(buf+1, key, len);
++
++ if (inc_y) {
++ if (!(len & 1)) { /*(dpp code/tests does not include tag?!?)*/
++ if (sizeof(buf)-2 < len)
++ return NULL;
++ buf[0] = (u8)(1+len);
++ buf[1] = 0x04;
++ os_memcpy(buf+2, key, len);
++ }
++ len >>= 1; /*(repurpose len to prime_len)*/
++ }
++ else if (key[0] == 0x02 || key[0] == 0x03) { /* (inc_y == 0) */
++ --len; /*(repurpose len to prime_len)*/
++
++ /* mbedtls_ecp_point_read_binary() does not currently support
++ * MBEDTLS_ECP_PF_COMPRESSED format (buf[1] = 0x02 or 0x03)
++ * (returns MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) */
++
++ /* derive y, amend buf[] with y for UNCOMPRESSED format */
++ if (sizeof(buf)-2 < len*2 || len == 0)
++ return NULL;
++ buf[0] = (u8)(1+len*2);
++ buf[1] = 0x04;
++ mbedtls_mpi bn;
++ mbedtls_mpi_init(&bn);
++ int ret = mbedtls_mpi_read_binary(&bn, key+1, len)
++ || crypto_mbedtls_short_weierstrass_derive_y(grp, &bn,
++ key[0] & 1)
++ || mbedtls_mpi_write_binary(&bn, buf+2+len, len);
++ mbedtls_mpi_free(&bn);
++ if (ret != 0)
++ return NULL;
++ }
++
++ if (key[0] == 0) /*(repurpose len to prime_len)*/
++ len = CRYPTO_EC_plen(grp);
++
++ if (mbedtls_ecdh_read_public(&ecdh->ctx, buf, buf[0]+1))
++ return NULL;
++ }
++ #endif
++ #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
++ if (mbedtls_ecdh_read_public(&ecdh->ctx, key, len))
++ return NULL;
++ }
++ #endif
++
++ struct wpabuf *buf = wpabuf_alloc(len);
++ if (buf == NULL)
++ return NULL;
++
++ if (mbedtls_ecdh_calc_secret(&ecdh->ctx, &len,
++ wpabuf_mhead(buf), len,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) == 0) {
++ wpabuf_put(buf, len);
++ return buf;
++ }
++
++ wpabuf_clear_free(buf);
++ return NULL;
++}
++
++void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
++{
++ if (ecdh == NULL)
++ return;
++ mbedtls_ecp_point_free(&ecdh->Q);
++ mbedtls_ecp_group_free(&ecdh->grp);
++ mbedtls_ecdh_free(&ecdh->ctx);
++ os_free(ecdh);
++}
++
++size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
++{
++ return CRYPTO_EC_plen(&ecdh->grp);
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_ECDH */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC
++
++#include <mbedtls/ecp.h>
++
++struct crypto_ec *crypto_ec_init(int group)
++{
++ mbedtls_ecp_group_id grp_id =
++ crypto_mbedtls_ecp_group_id_from_ike_id(group);
++ if (grp_id == MBEDTLS_ECP_DP_NONE)
++ return NULL;
++ mbedtls_ecp_group *e = os_malloc(sizeof(*e));
++ if (e == NULL)
++ return NULL;
++ mbedtls_ecp_group_init(e);
++ if (mbedtls_ecp_group_load(e, grp_id) == 0)
++ return (struct crypto_ec *)e;
++
++ mbedtls_ecp_group_free(e);
++ os_free(e);
++ return NULL;
++}
++
++void crypto_ec_deinit(struct crypto_ec *e)
++{
++ mbedtls_ecp_group_free((mbedtls_ecp_group *)e);
++ os_free(e);
++}
++
++size_t crypto_ec_prime_len(struct crypto_ec *e)
++{
++ return CRYPTO_EC_plen(e);
++}
++
++size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
++{
++ return CRYPTO_EC_pbits(e);
++}
++
++size_t crypto_ec_order_len(struct crypto_ec *e)
++{
++ return (mbedtls_mpi_bitlen(CRYPTO_EC_N(e)) + 7) / 8;
++}
++
++const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e)
++{
++ return (const struct crypto_bignum *)CRYPTO_EC_P(e);
++}
++
++const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e)
++{
++ return (const struct crypto_bignum *)CRYPTO_EC_N(e);
++}
++
++const struct crypto_bignum *crypto_ec_get_a(struct crypto_ec *e)
++{
++ static const uint8_t secp256r1_a[] =
++ {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x01,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc};
++ static const uint8_t secp384r1_a[] =
++ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
++ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xfc};
++ static const uint8_t secp521r1_a[] =
++ {0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xfc};
++ static const uint8_t secp192r1_a[] =
++ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc};
++ static const uint8_t secp224r1_a[] =
++ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
++ 0xff,0xff,0xff,0xfe};
++
++ const uint8_t *bin = NULL;
++ size_t len = 0;
++
++ /* (mbedtls groups matching supported sswu_curve_param() IKE groups) */
++ switch (((mbedtls_ecp_group *)e)->id) {
++ #ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP256R1:
++ bin = secp256r1_a;
++ len = sizeof(secp256r1_a);
++ break;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP384R1:
++ bin = secp384r1_a;
++ len = sizeof(secp384r1_a);
++ break;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP521R1:
++ bin = secp521r1_a;
++ len = sizeof(secp521r1_a);
++ break;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP192R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP192R1:
++ bin = secp192r1_a;
++ len = sizeof(secp192r1_a);
++ break;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_SECP224R1_ENABLED
++ case MBEDTLS_ECP_DP_SECP224R1:
++ bin = secp224r1_a;
++ len = sizeof(secp224r1_a);
++ break;
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP256R1_ENABLED
++ case MBEDTLS_ECP_DP_BP256R1:
++ return (const struct crypto_bignum *)CRYPTO_EC_A(e);
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP384R1_ENABLED
++ case MBEDTLS_ECP_DP_BP384R1:
++ return (const struct crypto_bignum *)CRYPTO_EC_A(e);
++ #endif
++ #ifdef MBEDTLS_ECP_DP_BP512R1_ENABLED
++ case MBEDTLS_ECP_DP_BP512R1:
++ return (const struct crypto_bignum *)CRYPTO_EC_A(e);
++ #endif
++ #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED
++ case MBEDTLS_ECP_DP_CURVE25519:
++ return (const struct crypto_bignum *)CRYPTO_EC_A(e);
++ #endif
++ #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED
++ case MBEDTLS_ECP_DP_CURVE448:
++ return (const struct crypto_bignum *)CRYPTO_EC_A(e);
++ #endif
++ default:
++ return NULL;
++ }
++
++ /*(note: not thread-safe; returns file-scoped static storage)*/
++ if (mbedtls_mpi_read_binary(&mpi_sw_A, bin, len) == 0)
++ return (const struct crypto_bignum *)&mpi_sw_A;
++ return NULL;
++}
++
++const struct crypto_bignum *crypto_ec_get_b(struct crypto_ec *e)
++{
++ return (const struct crypto_bignum *)CRYPTO_EC_B(e);
++}
++
++const struct crypto_ec_point * crypto_ec_get_generator(struct crypto_ec *e)
++{
++ return (const struct crypto_ec_point *)CRYPTO_EC_G(e);
++}
++
++struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)
++{
++ mbedtls_ecp_point *p = os_malloc(sizeof(*p));
++ if (p != NULL)
++ mbedtls_ecp_point_init(p);
++ return (struct crypto_ec_point *)p;
++}
++
++void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
++{
++ mbedtls_ecp_point_free((mbedtls_ecp_point *)p);
++ os_free(p);
++}
++
++int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
++ struct crypto_bignum *x)
++{
++ mbedtls_mpi *px = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X);
++ return mbedtls_mpi_copy((mbedtls_mpi *)x, px)
++ ? -1
++ : 0;
++}
++
++int crypto_ec_point_to_bin(struct crypto_ec *e,
++ const struct crypto_ec_point *point, u8 *x, u8 *y)
++{
++ /* crypto.h documents crypto_ec_point_to_bin() output is big-endian */
++ size_t len = CRYPTO_EC_plen(e);
++ if (x) {
++ mbedtls_mpi *px = &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(X);
++ if (mbedtls_mpi_write_binary(px, x, len))
++ return -1;
++ }
++ if (y) {
++ #if 0 /*(should not be necessary; py mpi should be in initial state)*/
++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
++ == MBEDTLS_ECP_TYPE_MONTGOMERY) {
++ os_memset(y, 0, len);
++ return 0;
++ }
++ #endif
++ #endif
++ mbedtls_mpi *py = &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(Y);
++ if (mbedtls_mpi_write_binary(py, y, len))
++ return -1;
++ }
++ return 0;
++}
++
++struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
++ const u8 *val)
++{
++ size_t len = CRYPTO_EC_plen(e);
++ mbedtls_ecp_point *p = os_malloc(sizeof(*p));
++ u8 buf[1+MBEDTLS_MPI_MAX_SIZE*2];
++ if (p == NULL)
++ return NULL;
++ mbedtls_ecp_point_init(p);
++
++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
++ == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
++ #if 0 /* prefer alternative to MBEDTLS_PRIVATE() access */
++ mbedtls_mpi *px = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X);
++ mbedtls_mpi *py = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y);
++ mbedtls_mpi *pz = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Z);
++
++ if (mbedtls_mpi_read_binary(px, val, len) == 0
++ && mbedtls_mpi_read_binary(py, val + len, len) == 0
++ && mbedtls_mpi_lset(pz, 1) == 0)
++ return (struct crypto_ec_point *)p;
++ #else
++ buf[0] = 0x04;
++ os_memcpy(buf+1, val, len*2);
++ if (mbedtls_ecp_point_read_binary((mbedtls_ecp_group *)e, p,
++ buf, 1+len*2) == 0)
++ return (struct crypto_ec_point *)p;
++ #endif
++ }
++ #endif
++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
++ == MBEDTLS_ECP_TYPE_MONTGOMERY) {
++ /* crypto.h interface documents crypto_ec_point_from_bin()
++ * val is length: prime_len * 2 and is big-endian
++ * (Short Weierstrass is assumed by hostap)
++ * Reverse to little-endian format for Montgomery */
++ for (unsigned int i = 0; i < len; ++i)
++ buf[i] = val[len-1-i];
++ if (mbedtls_ecp_point_read_binary((mbedtls_ecp_group *)e, p,
++ buf, len) == 0)
++ return (struct crypto_ec_point *)p;
++ }
++ #endif
++
++ mbedtls_ecp_point_free(p);
++ os_free(p);
++ return NULL;
++}
++
++int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
++ const struct crypto_ec_point *b,
++ struct crypto_ec_point *c)
++{
++ /* mbedtls does not provide an mbedtls_ecp_point add function */
++ mbedtls_mpi one;
++ mbedtls_mpi_init(&one);
++ int ret = mbedtls_mpi_lset(&one, 1)
++ || mbedtls_ecp_muladd(
++ (mbedtls_ecp_group *)e, (mbedtls_ecp_point *)c,
++ &one, (const mbedtls_ecp_point *)a,
++ &one, (const mbedtls_ecp_point *)b) ? -1 : 0;
++ mbedtls_mpi_free(&one);
++ return ret;
++}
++
++int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
++ const struct crypto_bignum *b,
++ struct crypto_ec_point *res)
++{
++ return mbedtls_ecp_mul(
++ (mbedtls_ecp_group *)e, (mbedtls_ecp_point *)res,
++ (const mbedtls_mpi *)b, (const mbedtls_ecp_point *)p,
++ mbedtls_ctr_drbg_random, crypto_mbedtls_ctr_drbg()) ? -1 : 0;
++}
++
++int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
++{
++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
++ == MBEDTLS_ECP_TYPE_MONTGOMERY) {
++ /* e.g. MBEDTLS_ECP_DP_CURVE25519 and MBEDTLS_ECP_DP_CURVE448 */
++ wpa_printf(MSG_ERROR,
++ "%s not implemented for Montgomery curves",__func__);
++ return -1;
++ }
++
++ /* mbedtls does not provide an mbedtls_ecp_point invert function */
++ /* below works for Short Weierstrass; incorrect for Montgomery curves */
++ mbedtls_mpi *py = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y);
++ return mbedtls_ecp_is_zero((mbedtls_ecp_point *)p) /*point at infinity*/
++ || mbedtls_mpi_cmp_int(py, 0) == 0 /*point is its own inverse*/
++ || mbedtls_mpi_sub_abs(py, CRYPTO_EC_P(e), py) == 0 ? 0 : -1;
++}
++
++#ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
++static int
++crypto_ec_point_y_sqr_weierstrass(mbedtls_ecp_group *e, const mbedtls_mpi *x,
++ mbedtls_mpi *y2)
++{
++ /* MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS y^2 = x^3 + a x + b */
++
++ /* Short Weierstrass elliptic curve group w/o A set treated as A = -3 */
++ /* Attempt to match mbedtls/library/ecp.c:ecp_check_pubkey_sw() behavior
++ * and elsewhere in mbedtls/library/ecp.c where if A is not set, it is
++ * treated as if A = -3. */
++
++ #if 0
++ /* y^2 = x^3 + ax + b */
++ mbedtls_mpi *A = &e->A;
++ mbedtls_mpi t, A_neg3;
++ if (&e->A.p == NULL) {
++ mbedtls_mpi_init(&A_neg3);
++ if (mbedtls_mpi_lset(&A_neg3, -3) != 0) {
++ mbedtls_mpi_free(&A_neg3);
++ return -1;
++ }
++ A = &A_neg3;
++ }
++ mbedtls_mpi_init(&t);
++ int ret = /* x^3 */
++ mbedtls_mpi_lset(&t, 3)
++ || mbedtls_mpi_exp_mod(y2, x, &t, &e->P, NULL)
++ /* ax */
++ || mbedtls_mpi_mul_mpi(y2, y2, A)
++ || mbedtls_mpi_mod_mpi(&t, &t, &e->P)
++ /* ax + b */
++ || mbedtls_mpi_add_mpi(&t, &t, &e->B)
++ || mbedtls_mpi_mod_mpi(&t, &t, &e->P)
++ /* x^3 + ax + b */
++ || mbedtls_mpi_add_mpi(&t, &t, y2) /* ax + b + x^3 */
++ || mbedtls_mpi_mod_mpi(y2, &t, &e->P);
++ mbedtls_mpi_free(&t);
++ if (A == &A_neg3)
++ mbedtls_mpi_free(&A_neg3);
++ return ret; /* 0: success, non-zero: failure */
++ #else
++ /* y^2 = x^3 + ax + b = (x^2 + a)x + b */
++ return /* x^2 */
++ mbedtls_mpi_mul_mpi(y2, x, x)
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P)
++ /* x^2 + a */
++ || (e->A.MBEDTLS_PRIVATE(p)
++ ? mbedtls_mpi_add_mpi(y2, y2, &e->A)
++ : mbedtls_mpi_sub_int(y2, y2, 3))
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P)
++ /* (x^2 + a)x */
++ || mbedtls_mpi_mul_mpi(y2, y2, x)
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P)
++ /* (x^2 + a)x + b */
++ || mbedtls_mpi_add_mpi(y2, y2, &e->B)
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P);
++ #endif
++}
++#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
++
++#if 0 /* not used by hostap */
++#ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
++static int
++crypto_ec_point_y_sqr_montgomery(mbedtls_ecp_group *e, const mbedtls_mpi *x,
++ mbedtls_mpi *y2)
++{
++ /* XXX: !!! must be reviewed and audited for correctness !!! */
++
++ /* MBEDTLS_ECP_TYPE_MONTGOMERY y^2 = x^3 + a x^2 + x */
++
++ /* y^2 = x^3 + a x^2 + x = (x + a)x^2 + x */
++ mbedtls_mpi x2;
++ mbedtls_mpi_init(&x2);
++ int ret = /* x^2 */
++ mbedtls_mpi_mul_mpi(&x2, x, x)
++ || mbedtls_mpi_mod_mpi(&x2, &x2, &e->P)
++ /* x + a */
++ || mbedtls_mpi_add_mpi(y2, x, &e->A)
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P)
++ /* (x + a)x^2 */
++ || mbedtls_mpi_mul_mpi(y2, y2, &x2)
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P)
++ /* (x + a)x^2 + x */
++ || mbedtls_mpi_add_mpi(y2, y2, x)
++ || mbedtls_mpi_mod_mpi(y2, y2, &e->P);
++ mbedtls_mpi_free(&x2);
++ return ret; /* 0: success, non-zero: failure */
++}
++#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
++#endif
++
++struct crypto_bignum *
++crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
++ const struct crypto_bignum *x)
++{
++ mbedtls_mpi *y2 = os_malloc(sizeof(*y2));
++ if (y2 == NULL)
++ return NULL;
++ mbedtls_mpi_init(y2);
++
++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
++ == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS
++ && crypto_ec_point_y_sqr_weierstrass((mbedtls_ecp_group *)e,
++ (const mbedtls_mpi *)x,
++ y2) == 0)
++ return (struct crypto_bignum *)y2;
++ #endif
++ #if 0 /* not used by hostap */
++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
++ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
++ == MBEDTLS_ECP_TYPE_MONTGOMERY
++ && crypto_ec_point_y_sqr_montgomery((mbedtls_ecp_group *)e,
++ (const mbedtls_mpi *)x,
++ y2) == 0)
++ return (struct crypto_bignum *)y2;
++ #endif
++ #endif
++
++ mbedtls_mpi_free(y2);
++ os_free(y2);
++ return NULL;
++}
++
++int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
++ const struct crypto_ec_point *p)
++{
++ return mbedtls_ecp_is_zero((mbedtls_ecp_point *)p);
++}
++
++int crypto_ec_point_is_on_curve(struct crypto_ec *e,
++ const struct crypto_ec_point *p)
++{
++ #if 1
++ return mbedtls_ecp_check_pubkey((const mbedtls_ecp_group *)e,
++ (const mbedtls_ecp_point *)p) == 0;
++ #else
++ /* compute y^2 mod P and compare to y^2 mod P */
++ /*(ref: src/eap_common/eap_pwd_common.c:compute_password_element())*/
++ const mbedtls_mpi *px = &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X);
++ mbedtls_mpi *cy2 = (mbedtls_mpi *)
++ crypto_ec_point_compute_y_sqr(e, (const struct crypto_bignum *)px);
++ if (cy2 == NULL)
++ return 0;
++
++ mbedtls_mpi y2;
++ mbedtls_mpi_init(&y2);
++ const mbedtls_mpi *py = &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y);
++ int is_on_curve = mbedtls_mpi_mul_mpi(&y2, py, py) /* y^2 mod P */
++ || mbedtls_mpi_mod_mpi(&y2, &y2, CRYPTO_EC_P(e))
++ || mbedtls_mpi_cmp_mpi(&y2, cy2) != 0 ? 0 : 1;
++
++ mbedtls_mpi_free(&y2);
++ mbedtls_mpi_free(cy2);
++ os_free(cy2);
++ return is_on_curve;
++ #endif
++}
++
++int crypto_ec_point_cmp(const struct crypto_ec *e,
++ const struct crypto_ec_point *a,
++ const struct crypto_ec_point *b)
++{
++ return mbedtls_ecp_point_cmp((const mbedtls_ecp_point *)a,
++ (const mbedtls_ecp_point *)b);
++}
++
++#if !defined(CONFIG_NO_STDOUT_DEBUG)
++void crypto_ec_point_debug_print(const struct crypto_ec *e,
++ const struct crypto_ec_point *p,
++ const char *title)
++{
++ u8 x[MBEDTLS_MPI_MAX_SIZE];
++ u8 y[MBEDTLS_MPI_MAX_SIZE];
++ size_t len = CRYPTO_EC_plen(e);
++ /* crypto_ec_point_to_bin ought to take (const struct crypto_ec *e) */
++ struct crypto_ec *ee;
++ *(const struct crypto_ec **)&ee = e; /*(cast away const)*/
++ if (crypto_ec_point_to_bin(ee, p, x, y) == 0) {
++ if (title)
++ wpa_printf(MSG_DEBUG, "%s", title);
++ wpa_hexdump(MSG_DEBUG, "x:", x, len);
++ wpa_hexdump(MSG_DEBUG, "y:", y, len);
++ }
++}
++#endif
++
++
++struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
++{
++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_pk_init(ctx);
++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++ if (mbedtls_pk_parse_key(ctx, der, der_len, NULL, 0) == 0)
++ #else
++ if (mbedtls_pk_parse_key(ctx, der, der_len, NULL, 0,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) == 0)
++ #endif
++ return (struct crypto_ec_key *)ctx;
++
++ mbedtls_pk_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_HPKE
++#ifdef CONFIG_MODULE_TESTS
++/*(for crypto_module_tests.c)*/
++struct crypto_ec_key * crypto_ec_key_set_priv(int group,
++ const u8 *raw, size_t raw_len)
++{
++ mbedtls_ecp_group_id grp_id =
++ crypto_mbedtls_ecp_group_id_from_ike_id(group);
++ if (grp_id == MBEDTLS_ECP_DP_NONE)
++ return NULL;
++ const mbedtls_pk_info_t *pk_info =
++ mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
++ if (pk_info == NULL)
++ return NULL;
++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_pk_init(ctx);
++ if (mbedtls_pk_setup(ctx, pk_info) == 0
++ && mbedtls_ecp_read_key(grp_id,mbedtls_pk_ec(*ctx),raw,raw_len) == 0) {
++ return (struct crypto_ec_key *)ctx;
++ }
++
++ mbedtls_pk_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++#endif
++#endif
++
++#include <mbedtls/error.h>
++#include <mbedtls/oid.h>
++static int crypto_mbedtls_pk_parse_subpubkey_compressed(mbedtls_pk_context *ctx, const u8 *der, size_t der_len)
++{
++ /* The following is modified from:
++ * mbedtls/library/pkparse.c:mbedtls_pk_parse_subpubkey()
++ * mbedtls/library/pkparse.c:pk_get_pk_alg()
++ * mbedtls/library/pkparse.c:pk_use_ecparams()
++ */
++ mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
++ const mbedtls_pk_info_t *pk_info;
++ int ret;
++ size_t len;
++ const unsigned char *end = der+der_len;
++ unsigned char *p;
++ *(const unsigned char **)&p = der;
++
++ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
++ {
++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
++ }
++
++ end = p + len;
++
++ /*
++ if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, &alg_params ) ) != 0 )
++ return( ret );
++ */
++ mbedtls_asn1_buf alg_oid, params;
++ memset( &params, 0, sizeof(mbedtls_asn1_buf) );
++ if( ( ret = mbedtls_asn1_get_alg( &p, end, &alg_oid, &params ) ) != 0 )
++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_ALG, ret ) );
++ if( mbedtls_oid_get_pk_alg( &alg_oid, &pk_alg ) != 0 )
++ return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
++
++ if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end, &len ) ) != 0 )
++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) );
++
++ if( p + len != end )
++ return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY,
++ MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
++
++ if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL )
++ return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
++
++ if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 )
++ return( ret );
++
++ /* assume mbedtls_pk_parse_subpubkey(&der, der+der_len, ctx)
++ * has already run with ctx initialized up to pk_get_ecpubkey(),
++ * and pk_get_ecpubkey() has returned MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
++ *
++ * mbedtls mbedtls_ecp_point_read_binary()
++ * does not handle point in COMPRESSED format
++ *
++ * (validate assumption that algorithm is EC) */
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*ctx);
++ if (ecp_kp == NULL)
++ return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q);
++ mbedtls_ecp_group_id grp_id;
++
++
++ /* mbedtls/library/pkparse.c:pk_use_ecparams() */
++
++ if( params.tag == MBEDTLS_ASN1_OID )
++ {
++ if( mbedtls_oid_get_ec_grp( &params, &grp_id ) != 0 )
++ return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE );
++ }
++ else
++ {
++#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
++ /*(large code block not copied from mbedtls; unsupported)*/
++ #if 0
++ if( ( ret = pk_group_id_from_specified( &params, &grp_id ) ) != 0 )
++ return( ret );
++ #endif
++#endif
++ return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
++ }
++
++ /*
++ * grp may already be initialized; if so, make sure IDs match
++ */
++ if( ecp_kp_grp->id != MBEDTLS_ECP_DP_NONE && ecp_kp_grp->id != grp_id )
++ return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
++
++ if( ( ret = mbedtls_ecp_group_load( ecp_kp_grp, grp_id ) ) != 0 )
++ return( ret );
++
++
++ /* (validate assumption that EC point is in COMPRESSED format) */
++ len = CRYPTO_EC_plen(ecp_kp_grp);
++ if( mbedtls_ecp_get_type(ecp_kp_grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS
++ || (end - p) != 1+len
++ || (*p != 0x02 && *p != 0x03) )
++ return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
++
++ /* Instead of calling mbedtls/library/pkparse.c:pk_get_ecpubkey() to call
++ * mbedtls_ecp_point_read_binary(), manually parse point into ecp_kp_Q */
++ mbedtls_mpi *X = &ecp_kp_Q->MBEDTLS_PRIVATE(X);
++ mbedtls_mpi *Y = &ecp_kp_Q->MBEDTLS_PRIVATE(Y);
++ mbedtls_mpi *Z = &ecp_kp_Q->MBEDTLS_PRIVATE(Z);
++ ret = mbedtls_mpi_lset(Z, 1);
++ if (ret != 0)
++ return( ret );
++ ret = mbedtls_mpi_read_binary(X, p+1, len);
++ if (ret != 0)
++ return( ret );
++ /* derive Y
++ * (similar derivation of Y in crypto_mbedtls.c:crypto_ecdh_set_peerkey())*/
++ ret = mbedtls_mpi_copy(Y, X) /*(Y is used as input and output obj below)*/
++ || crypto_mbedtls_short_weierstrass_derive_y(ecp_kp_grp, Y, (*p & 1));
++ if (ret != 0)
++ return( ret );
++
++ return mbedtls_ecp_check_pubkey( ecp_kp_grp, ecp_kp_Q );
++}
++
++struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
++{
++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_pk_init(ctx);
++ /*int rc = mbedtls_pk_parse_subpubkey(&der, der+der_len, ctx);*/
++ int rc = mbedtls_pk_parse_public_key(ctx, der, der_len);
++ if (rc == 0)
++ return (struct crypto_ec_key *)ctx;
++ else if (rc == MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) {
++ /* mbedtls mbedtls_ecp_point_read_binary()
++ * does not handle point in COMPRESSED format; parse internally */
++ rc = crypto_mbedtls_pk_parse_subpubkey_compressed(ctx,der,der_len);
++ if (rc == 0)
++ return (struct crypto_ec_key *)ctx;
++ }
++
++ mbedtls_pk_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP
++
++static struct crypto_ec_key *
++crypto_ec_key_set_pub_point_for_group(mbedtls_ecp_group_id grp_id,
++ const mbedtls_ecp_point *pub,
++ const u8 *buf, size_t len)
++{
++ const mbedtls_pk_info_t *pk_info =
++ mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
++ if (pk_info == NULL)
++ return NULL;
++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_pk_init(ctx);
++ if (mbedtls_pk_setup(ctx, pk_info) == 0) {
++ /* (Is private key generation necessary for callers?)
++ * alt: gen key then overwrite Q
++ * mbedtls_ecp_gen_key(grp_id, ecp_kp,
++ * mbedtls_ctr_drbg_random,
++ * crypto_mbedtls_ctr_drbg()) == 0
++ */
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*ctx);
++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q);
++ mbedtls_mpi *ecp_kp_d = &ecp_kp->MBEDTLS_PRIVATE(d);
++ if (mbedtls_ecp_group_load(ecp_kp_grp, grp_id) == 0
++ && (pub
++ ? mbedtls_ecp_copy(ecp_kp_Q, pub) == 0
++ : mbedtls_ecp_point_read_binary(ecp_kp_grp, ecp_kp_Q,
++ buf, len) == 0)
++ && mbedtls_ecp_gen_privkey(ecp_kp_grp, ecp_kp_d,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) == 0){
++ return (struct crypto_ec_key *)ctx;
++ }
++ }
++
++ mbedtls_pk_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++
++struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *x,
++ const u8 *y, size_t len)
++{
++ mbedtls_ecp_group_id grp_id =
++ crypto_mbedtls_ecp_group_id_from_ike_id(group);
++ if (grp_id == MBEDTLS_ECP_DP_NONE)
++ return NULL;
++ if (len > MBEDTLS_MPI_MAX_SIZE)
++ return NULL;
++ u8 buf[1+MBEDTLS_MPI_MAX_SIZE*2];
++ buf[0] = 0x04; /* assume x,y for Short Weierstrass */
++ os_memcpy(buf+1, x, len);
++ os_memcpy(buf+1+len, y, len);
++
++ return crypto_ec_key_set_pub_point_for_group(grp_id,NULL,buf,1+len*2);
++}
++
++struct crypto_ec_key *
++crypto_ec_key_set_pub_point(struct crypto_ec *e,
++ const struct crypto_ec_point *pub)
++{
++ mbedtls_ecp_group_id grp_id = ((mbedtls_ecp_group *)e)->id;
++ mbedtls_ecp_point *p = (mbedtls_ecp_point *)pub;
++ return crypto_ec_key_set_pub_point_for_group(grp_id, p, NULL, 0);
++}
++
++
++struct crypto_ec_key * crypto_ec_key_gen(int group)
++{
++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL)
++ return NULL;
++ mbedtls_pk_init(ctx);
++ if (crypto_mbedtls_keypair_gen(group, ctx) == 0)
++ return (struct crypto_ec_key *)ctx;
++ mbedtls_pk_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */
++
++void crypto_ec_key_deinit(struct crypto_ec_key *key)
++{
++ mbedtls_pk_free((mbedtls_pk_context *)key);
++ os_free(key);
++}
++
++struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
++{
++ /* (similar to crypto_ec_key_get_pubkey_point(),
++ * but compressed point format and ASN.1 DER wrapping)*/
++#ifndef MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES /*(mbedtls/library/pkwrite.h)*/
++#define MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES ( 30 + 2 * MBEDTLS_ECP_MAX_BYTES )
++#endif
++ unsigned char buf[MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES];
++ int len = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)key,
++ buf, sizeof(buf));
++ if (len < 0)
++ return NULL;
++ /* Note: data is written at the end of the buffer! Use the
++ * return value to determine where you should start
++ * using the buffer */
++ unsigned char *p = buf+sizeof(buf)-len;
++
++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return NULL;
++ mbedtls_ecp_group *grp = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ /* Note: sae_pk.c expects pubkey point in compressed format,
++ * but mbedtls_pk_write_pubkey_der() writes uncompressed format.
++ * Manually translate format and update lengths in DER format */
++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
++ unsigned char *end = buf+sizeof(buf);
++ size_t n;
++ /* SubjectPublicKeyInfo SEQUENCE */
++ mbedtls_asn1_get_tag(&p, end, &n,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ /* algorithm AlgorithmIdentifier */
++ unsigned char *a = p;
++ size_t alen;
++ mbedtls_asn1_get_tag(&p, end, &alen,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ p += alen;
++ alen = (size_t)(p - a);
++ /* subjectPublicKey BIT STRING */
++ mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_BIT_STRING);
++ /* rewrite into compressed point format and rebuild ASN.1 */
++ p[1] = (buf[sizeof(buf)-1] & 1) ? 0x03 : 0x02;
++ n = 1 + 1 + (n-2)/2;
++ len = mbedtls_asn1_write_len(&p, buf, n) + (int)n;
++ len += mbedtls_asn1_write_tag(&p, buf, MBEDTLS_ASN1_BIT_STRING);
++ os_memmove(p-alen, a, alen);
++ len += alen;
++ p -= alen;
++ len += mbedtls_asn1_write_len(&p, buf, (size_t)len);
++ len += mbedtls_asn1_write_tag(&p, buf,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ }
++ #endif
++ return wpabuf_alloc_copy(p, (size_t)len);
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP
++
++struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
++ bool include_pub)
++{
++#ifndef MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES /*(mbedtls/library/pkwrite.h)*/
++#define MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES ( 29 + 3 * MBEDTLS_ECP_MAX_BYTES )
++#endif
++ unsigned char priv[MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES];
++ int privlen = mbedtls_pk_write_key_der((mbedtls_pk_context *)key,
++ priv, sizeof(priv));
++ if (privlen < 0)
++ return NULL;
++
++ struct wpabuf *wbuf;
++
++ /* Note: data is written at the end of the buffer! Use the
++ * return value to determine where you should start
++ * using the buffer */
++ /* mbedtls_pk_write_key_der() includes publicKey in DER */
++ if (include_pub)
++ wbuf = wpabuf_alloc_copy(priv+sizeof(priv)-privlen, privlen);
++ else {
++ /* calculate publicKey offset and skip from end of buffer */
++ unsigned char *p = priv+sizeof(priv)-privlen;
++ unsigned char *end = priv+sizeof(priv);
++ size_t len;
++ /* ECPrivateKey SEQUENCE */
++ mbedtls_asn1_get_tag(&p, end, &len,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ /* version INTEGER */
++ unsigned char *v = p;
++ mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
++ p += len;
++ /* privateKey OCTET STRING */
++ mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
++ p += len;
++ /* parameters ECParameters */
++ mbedtls_asn1_get_tag(&p, end, &len,
++ MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED);
++ p += len;
++
++ /* write new SEQUENCE header (we know that it fits in priv[]) */
++ len = (size_t)(p - v);
++ p = v;
++ len += mbedtls_asn1_write_len(&p, priv, len);
++ len += mbedtls_asn1_write_tag(&p, priv,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ wbuf = wpabuf_alloc_copy(p, len);
++ }
++
++ forced_memzero(priv, sizeof(priv));
++ return wbuf;
++}
++
++struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
++ int prefix)
++{
++ /*(similarities to crypto_ecdh_get_pubkey(), but different struct)*/
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return NULL;
++ mbedtls_ecp_group *grp = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ size_t len = CRYPTO_EC_plen(grp);
++ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
++ /* len */
++ #endif
++ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
++ len = len*2+1;
++ #endif
++ struct wpabuf *buf = wpabuf_alloc(len);
++ if (buf == NULL)
++ return NULL;
++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q);
++ if (mbedtls_ecp_point_write_binary(grp, ecp_kp_Q,
++ MBEDTLS_ECP_PF_UNCOMPRESSED, &len,
++ wpabuf_mhead_u8(buf), len) == 0) {
++ if (!prefix) /* Remove 0x04 prefix if requested */
++ os_memmove(wpabuf_mhead(buf),wpabuf_mhead(buf)+1,--len);
++ wpabuf_put(buf, len);
++ return buf;
++ }
++
++ wpabuf_free(buf);
++ return NULL;
++}
++
++struct crypto_ec_point *
++crypto_ec_key_get_public_key(struct crypto_ec_key *key)
++{
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return NULL;
++ mbedtls_ecp_point *p = os_malloc(sizeof(*p));
++ if (p != NULL) {
++ /*(mbedtls_ecp_export() uses &ecp_kp->MBEDTLS_PRIVATE(grp))*/
++ mbedtls_ecp_point_init(p);
++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q);
++ if (mbedtls_ecp_copy(p, ecp_kp_Q)) {
++ mbedtls_ecp_point_free(p);
++ os_free(p);
++ p = NULL;
++ }
++ }
++ return (struct crypto_ec_point *)p;
++}
++
++struct crypto_bignum *
++crypto_ec_key_get_private_key(struct crypto_ec_key *key)
++{
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return NULL;
++ mbedtls_mpi *bn = os_malloc(sizeof(*bn));
++ if (bn) {
++ /*(mbedtls_ecp_export() uses &ecp_kp->MBEDTLS_PRIVATE(grp))*/
++ mbedtls_mpi_init(bn);
++ mbedtls_mpi *ecp_kp_d = &ecp_kp->MBEDTLS_PRIVATE(d);
++ if (mbedtls_mpi_copy(bn, ecp_kp_d)) {
++ mbedtls_mpi_free(bn);
++ os_free(bn);
++ bn = NULL;
++ }
++ }
++ return (struct crypto_bignum *)bn;
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */
++
++static mbedtls_md_type_t crypto_ec_key_sign_md(size_t len)
++{
++ /* get mbedtls_md_type_t from length of hash data to be signed */
++ switch (len) {
++ case 64: return MBEDTLS_MD_SHA512;
++ case 48: return MBEDTLS_MD_SHA384;
++ case 32: return MBEDTLS_MD_SHA256;
++ case 20: return MBEDTLS_MD_SHA1;
++ case 16: return MBEDTLS_MD_MD5;
++ default: return MBEDTLS_MD_NONE;
++ }
++}
++
++struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
++ size_t len)
++{
++ #ifndef MBEDTLS_PK_SIGNATURE_MAX_SIZE /*(defined since mbedtls 2.20.0)*/
++ #if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE
++ #define MBEDTLS_PK_SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN
++ #else
++ #define MBEDTLS_PK_SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE
++ #endif
++ #endif
++ size_t sig_len = MBEDTLS_PK_SIGNATURE_MAX_SIZE;
++ struct wpabuf *buf = wpabuf_alloc(sig_len);
++ if (buf == NULL)
++ return NULL;
++ if (mbedtls_pk_sign((mbedtls_pk_context *)key,
++ crypto_ec_key_sign_md(len), data, len,
++ wpabuf_mhead_u8(buf),
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ sig_len,
++ #endif
++ &sig_len,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) == 0) {
++ wpabuf_put(buf, sig_len);
++ return buf;
++ }
++
++ wpabuf_free(buf);
++ return NULL;
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP
++struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
++ const u8 *data, size_t len)
++{
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return NULL;
++
++ size_t sig_len = MBEDTLS_ECDSA_MAX_LEN;
++ u8 buf[MBEDTLS_ECDSA_MAX_LEN];
++ if (mbedtls_ecdsa_write_signature(ecp_kp, crypto_ec_key_sign_md(len),
++ data, len, buf,
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ sig_len,
++ #endif
++ &sig_len,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg())) {
++ return NULL;
++ }
++
++ /*(mbedtls_ecdsa_write_signature() writes signature in ASN.1)*/
++ /* parse ASN.1 to get r and s and lengths */
++ u8 *p = buf, *r, *s;
++ u8 *end = p + sig_len;
++ size_t rlen, slen;
++ mbedtls_asn1_get_tag(&p, end, &rlen,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ mbedtls_asn1_get_tag(&p, end, &rlen, MBEDTLS_ASN1_INTEGER);
++ r = p;
++ p += rlen;
++ mbedtls_asn1_get_tag(&p, end, &slen, MBEDTLS_ASN1_INTEGER);
++ s = p;
++
++ /* write raw r and s into out
++ * (including removal of leading 0 if added for ASN.1 integer)
++ * note: DPP caller expects raw r, s each padded to prime len */
++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ size_t plen = CRYPTO_EC_plen(ecp_kp_grp);
++ if (rlen > plen) {
++ r += (rlen - plen);
++ rlen = plen;
++ }
++ if (slen > plen) {
++ s += (slen - plen);
++ slen = plen;
++ }
++ struct wpabuf *out = wpabuf_alloc(plen*2);
++ if (out) {
++ wpabuf_put(out, plen*2);
++ p = wpabuf_mhead_u8(out);
++ os_memset(p, 0, plen*2);
++ os_memcpy(p+plen*1-rlen, r, rlen);
++ os_memcpy(p+plen*2-slen, s, slen);
++ }
++ return out;
++}
++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */
++
++int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
++ size_t len, const u8 *sig, size_t sig_len)
++{
++ switch (mbedtls_pk_verify((mbedtls_pk_context *)key,
++ crypto_ec_key_sign_md(len), data, len,
++ sig, sig_len)) {
++ case 0:
++ /*case MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH:*//* XXX: allow? */
++ return 1;
++ case MBEDTLS_ERR_ECP_VERIFY_FAILED:
++ return 0;
++ default:
++ return -1;
++ }
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP
++int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key,
++ const u8 *data, size_t len,
++ const u8 *r, size_t r_len,
++ const u8 *s, size_t s_len)
++{
++ /* reimplement mbedtls_ecdsa_read_signature() without encoding r and s
++ * into ASN.1 just for mbedtls_ecdsa_read_signature() to decode ASN.1 */
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return -1;
++ mbedtls_ecp_group *ecp_kp_grp = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ mbedtls_ecp_point *ecp_kp_Q = &ecp_kp->MBEDTLS_PRIVATE(Q);
++
++ mbedtls_mpi mpi_r;
++ mbedtls_mpi mpi_s;
++ mbedtls_mpi_init(&mpi_r);
++ mbedtls_mpi_init(&mpi_s);
++ int ret = mbedtls_mpi_read_binary(&mpi_r, r, r_len)
++ || mbedtls_mpi_read_binary(&mpi_s, s, s_len) ? -1 : 0;
++ if (ret == 0) {
++ ret = mbedtls_ecdsa_verify(ecp_kp_grp, data, len,
++ ecp_kp_Q, &mpi_r, &mpi_s);
++ ret = ret ? ret == MBEDTLS_ERR_ECP_BAD_INPUT_DATA ? 0 : -1 : 1;
++ }
++ mbedtls_mpi_free(&mpi_r);
++ mbedtls_mpi_free(&mpi_s);
++ return ret;
++}
++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */
++
++int crypto_ec_key_group(struct crypto_ec_key *key)
++{
++ mbedtls_ecp_keypair *ecp_kp = mbedtls_pk_ec(*(mbedtls_pk_context *)key);
++ if (ecp_kp == NULL)
++ return -1;
++ mbedtls_ecp_group *ecp_group = &ecp_kp->MBEDTLS_PRIVATE(grp);
++ return crypto_mbedtls_ike_id_from_ecp_group_id(ecp_group->id);
++}
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_EC_DPP
++
++int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2)
++{
++#if 0 /*(DPP is passing two public keys; unable to use pk_check_pair())*/
++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++ return mbedtls_pk_check_pair((const mbedtls_pk_context *)key1,
++ (const mbedtls_pk_context *)key2) ? -1 : 0;
++ #else
++ return mbedtls_pk_check_pair((const mbedtls_pk_context *)key1,
++ (const mbedtls_pk_context *)key2,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()) ? -1 : 0;
++ #endif
++#else
++ mbedtls_ecp_keypair *ecp_kp1=mbedtls_pk_ec(*(mbedtls_pk_context *)key1);
++ mbedtls_ecp_keypair *ecp_kp2=mbedtls_pk_ec(*(mbedtls_pk_context *)key2);
++ if (ecp_kp1 == NULL || ecp_kp2 == NULL)
++ return -1;
++ mbedtls_ecp_group *ecp_kp1_grp = &ecp_kp1->MBEDTLS_PRIVATE(grp);
++ mbedtls_ecp_group *ecp_kp2_grp = &ecp_kp2->MBEDTLS_PRIVATE(grp);
++ mbedtls_ecp_point *ecp_kp1_Q = &ecp_kp1->MBEDTLS_PRIVATE(Q);
++ mbedtls_ecp_point *ecp_kp2_Q = &ecp_kp2->MBEDTLS_PRIVATE(Q);
++ return ecp_kp1_grp->id != ecp_kp2_grp->id
++ || mbedtls_ecp_point_cmp(ecp_kp1_Q, ecp_kp2_Q) ? -1 : 0;
++#endif
++}
++
++void crypto_ec_key_debug_print(const struct crypto_ec_key *key,
++ const char *title)
++{
++ /* TBD: what info is desirable here and in what human readable format?*/
++ /*(crypto_openssl.c prints a human-readably public key and attributes)*/
++ #if 0
++ struct mbedtls_pk_debug_item debug_item;
++ if (mbedtls_pk_debug((const mbedtls_pk_context *)key, &debug_item))
++ return;
++ /* ... */
++ #endif
++ wpa_printf(MSG_DEBUG, "%s: %s not implemented", title, __func__);
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC_DPP */
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_EC */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_CSR
++
++#include <mbedtls/x509_csr.h>
++#include <mbedtls/oid.h>
++
++struct crypto_csr * crypto_csr_init(void)
++{
++ mbedtls_x509write_csr *csr = os_malloc(sizeof(*csr));
++ if (csr != NULL)
++ mbedtls_x509write_csr_init(csr);
++ return (struct crypto_csr *)csr;
++}
++
++struct crypto_csr * crypto_csr_verify(const struct wpabuf *req)
++{
++ /* future: look for alternatives to MBEDTLS_PRIVATE() access */
++
++ /* sole caller src/common/dpp_crypto.c:dpp_validate_csr()
++ * uses (mbedtls_x509_csr *) to obtain CSR_ATTR_CHALLENGE_PASSWORD
++ * so allocate different object (mbedtls_x509_csr *) and special-case
++ * object when used in crypto_csr_get_attribute() and when free()d in
++ * crypto_csr_deinit(). */
++
++ mbedtls_x509_csr *csr = os_malloc(sizeof(*csr));
++ if (csr == NULL)
++ return NULL;
++ mbedtls_x509_csr_init(csr);
++ const mbedtls_md_info_t *md_info;
++ unsigned char digest[MBEDTLS_MD_MAX_SIZE];
++ if (mbedtls_x509_csr_parse_der(csr,wpabuf_head(req),wpabuf_len(req))==0
++ && (md_info=mbedtls_md_info_from_type(csr->MBEDTLS_PRIVATE(sig_md)))
++ != NULL
++ && mbedtls_md(md_info, csr->cri.p, csr->cri.len, digest) == 0) {
++ switch (mbedtls_pk_verify(&csr->pk,csr->MBEDTLS_PRIVATE(sig_md),
++ digest, mbedtls_md_get_size(md_info),
++ csr->MBEDTLS_PRIVATE(sig).p,
++ csr->MBEDTLS_PRIVATE(sig).len)) {
++ case 0:
++ /*case MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH:*//* XXX: allow? */
++ return (struct crypto_csr *)((uintptr_t)csr | 1uL);
++ default:
++ break;
++ }
++ }
++
++ mbedtls_x509_csr_free(csr);
++ os_free(csr);
++ return NULL;
++}
++
++void crypto_csr_deinit(struct crypto_csr *csr)
++{
++ if ((uintptr_t)csr & 1uL) {
++ csr = (struct crypto_csr *)((uintptr_t)csr & ~1uL);
++ mbedtls_x509_csr_free((mbedtls_x509_csr *)csr);
++ }
++ else
++ mbedtls_x509write_csr_free((mbedtls_x509write_csr *)csr);
++ os_free(csr);
++}
++
++int crypto_csr_set_ec_public_key(struct crypto_csr *csr,
++ struct crypto_ec_key *key)
++{
++ mbedtls_x509write_csr_set_key((mbedtls_x509write_csr *)csr,
++ (mbedtls_pk_context *)key);
++ return 0;
++}
++
++int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
++ const char *name)
++{
++ /* specialized for src/common/dpp_crypto.c */
++
++ /* sole caller src/common/dpp_crypto.c:dpp_build_csr()
++ * calls this function only once, using type == CSR_NAME_CN
++ * (If called more than once, this code would need to append
++ * components to the subject name, which we could do by
++ * appending to (mbedtls_x509write_csr *) private member
++ * mbedtls_asn1_named_data *MBEDTLS_PRIVATE(subject)) */
++
++ const char *label;
++ switch (type) {
++ case CSR_NAME_CN: label = "CN="; break;
++ case CSR_NAME_SN: label = "SN="; break;
++ case CSR_NAME_C: label = "C="; break;
++ case CSR_NAME_O: label = "O="; break;
++ case CSR_NAME_OU: label = "OU="; break;
++ default: return -1;
++ }
++
++ size_t len = strlen(name);
++ struct wpabuf *buf = wpabuf_alloc(3+len+1);
++ if (buf == NULL)
++ return -1;
++ wpabuf_put_data(buf, label, strlen(label));
++ wpabuf_put_data(buf, name, len+1); /*(include trailing '\0')*/
++ /* Note: 'name' provided is set as given and should be backslash-escaped
++ * by caller when necessary, e.g. literal ',' which are not separating
++ * components should be backslash-escaped */
++
++ int ret =
++ mbedtls_x509write_csr_set_subject_name((mbedtls_x509write_csr *)csr,
++ wpabuf_head(buf)) ? -1 : 0;
++ wpabuf_free(buf);
++ return ret;
++}
++
++/* OBJ_pkcs9_challengePassword 1 2 840 113549 1 9 7 */
++static const char OBJ_pkcs9_challengePassword[] = MBEDTLS_OID_PKCS9 "\x07";
++
++int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr,
++ int attr_type, const u8 *value, size_t len)
++{
++ /* specialized for src/common/dpp_crypto.c */
++ /* sole caller src/common/dpp_crypto.c:dpp_build_csr() passes
++ * attr == CSR_ATTR_CHALLENGE_PASSWORD
++ * attr_type == ASN1_TAG_UTF8STRING */
++
++ const char *oid;
++ size_t oid_len;
++ switch (attr) {
++ case CSR_ATTR_CHALLENGE_PASSWORD:
++ oid = OBJ_pkcs9_challengePassword;
++ oid_len = sizeof(OBJ_pkcs9_challengePassword)-1;
++ break;
++ default:
++ return -1;
++ }
++
++ #if 0 /*(incorrect; sets an extension, not an attribute)*/
++ return mbedtls_x509write_csr_set_extension((mbedtls_x509write_csr *)csr,
++ oid, oid_len,
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ 0, /*(critical flag)*/
++ #endif
++ value, len) ? -1 : 0;
++ #else
++ (void)oid;
++ (void)oid_len;
++ #endif
++
++ /* mbedtls does not currently provide way to set an attribute in a CSR:
++ * https://github.com/Mbed-TLS/mbedtls/issues/4886 */
++ wpa_printf(MSG_ERROR,
++ "mbedtls does not currently support setting challengePassword "
++ "attribute in CSR");
++ return -1;
++}
++
++const u8 * mbedtls_x509_csr_attr_oid_value(mbedtls_x509_csr *csr,
++ const char *oid, size_t oid_len,
++ size_t *vlen, int *vtype)
++{
++ /* Note: mbedtls_x509_csr_parse_der() has parsed and validated CSR,
++ * so validation checks are not repeated here
++ *
++ * It would be nicer if (mbedtls_x509_csr *) had an mbedtls_x509_buf of
++ * Attributes (or at least a pointer) since mbedtls_x509_csr_parse_der()
++ * already parsed the rest of CertificationRequestInfo, some of which is
++ * repeated here to step to Attributes. Since csr->subject_raw.p points
++ * into csr->cri.p, which points into csr->raw.p, step over version and
++ * subject of CertificationRequestInfo (SEQUENCE) */
++ unsigned char *p = csr->subject_raw.p + csr->subject_raw.len;
++ unsigned char *end = csr->cri.p + csr->cri.len, *ext;
++ size_t len;
++
++ /* step over SubjectPublicKeyInfo */
++ mbedtls_asn1_get_tag(&p, end, &len,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
++ p += len;
++
++ /* Attributes
++ * { ATTRIBUTE:IOSet } ::= SET OF { SEQUENCE { OID, value } }
++ */
++ if (mbedtls_asn1_get_tag(&p, end, &len,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
++ return NULL;
++ }
++ while (p < end) {
++ if (mbedtls_asn1_get_tag(&p, end, &len,
++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
++ return NULL;
++ }
++ ext = p;
++ p += len;
++
++ if (mbedtls_asn1_get_tag(&ext,end,&len,MBEDTLS_ASN1_OID) != 0)
++ return NULL;
++ if (oid_len != len || 0 != memcmp(ext, oid, oid_len))
++ continue;
++
++ /* found oid; return value */
++ *vtype = *ext++; /* tag */
++ return (mbedtls_asn1_get_len(&ext,end,vlen) == 0) ? ext : NULL;
++ }
++
++ return NULL;
++}
++
++const u8 * crypto_csr_get_attribute(struct crypto_csr *csr,
++ enum crypto_csr_attr attr,
++ size_t *len, int *type)
++{
++ /* specialized for src/common/dpp_crypto.c */
++ /* sole caller src/common/dpp_crypto.c:dpp_build_csr() passes
++ * attr == CSR_ATTR_CHALLENGE_PASSWORD */
++
++ const char *oid;
++ size_t oid_len;
++ switch (attr) {
++ case CSR_ATTR_CHALLENGE_PASSWORD:
++ oid = OBJ_pkcs9_challengePassword;
++ oid_len = sizeof(OBJ_pkcs9_challengePassword)-1;
++ break;
++ default:
++ return NULL;
++ }
++
++ /* see crypto_csr_verify(); expecting (mbedtls_x509_csr *) tagged |=1 */
++ if (!((uintptr_t)csr & 1uL))
++ return NULL;
++ csr = (struct crypto_csr *)((uintptr_t)csr & ~1uL);
++
++ return mbedtls_x509_csr_attr_oid_value((mbedtls_x509_csr *)csr,
++ oid, oid_len, len, type);
++}
++
++struct wpabuf * crypto_csr_sign(struct crypto_csr *csr,
++ struct crypto_ec_key *key,
++ enum crypto_hash_alg algo)
++{
++ mbedtls_md_type_t sig_md;
++ switch (algo) {
++ #ifdef MBEDTLS_SHA256_C
++ case CRYPTO_HASH_ALG_SHA256: sig_md = MBEDTLS_MD_SHA256; break;
++ #endif
++ #ifdef MBEDTLS_SHA512_C
++ case CRYPTO_HASH_ALG_SHA384: sig_md = MBEDTLS_MD_SHA384; break;
++ case CRYPTO_HASH_ALG_SHA512: sig_md = MBEDTLS_MD_SHA512; break;
++ #endif
++ default:
++ return NULL;
++ }
++ mbedtls_x509write_csr_set_md_alg((mbedtls_x509write_csr *)csr, sig_md);
++
++ #if 0
++ unsigned char key_usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE
++ | MBEDTLS_X509_KU_KEY_CERT_SIGN;
++ if (mbedtls_x509write_csr_set_key_usage((mbedtls_x509write_csr *)csr,
++ key_usage))
++ return NULL;
++ #endif
++
++ #if 0
++ unsigned char ns_cert_type = MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT
++ | MBEDTLS_X509_NS_CERT_TYPE_EMAIL;
++ if (mbedtls_x509write_csr_set_ns_cert_type((mbedtls_x509write_csr *)csr,
++ ns_cert_type))
++ return NULL;
++ #endif
++
++ #if 0
++ /* mbedtls does not currently provide way to set an attribute in a CSR:
++ * https://github.com/Mbed-TLS/mbedtls/issues/4886
++ * XXX: hwsim dpp_enterprise test fails due to this limitation.
++ *
++ * Current usage of this function is solely by dpp_build_csr(),
++ * so as a kludge, might consider custom (struct crypto_csr *)
++ * containing (mbedtls_x509write_csr *) and a list of attributes
++ * (i.e. challengePassword). Might have to totally reimplement
++ * mbedtls_x509write_csr_der(); underlying x509write_csr_der_internal()
++ * handles signing the CSR. (This is more work that appending an
++ * Attributes section to end of CSR and adjusting ASN.1 length of CSR.)
++ */
++ #endif
++
++ unsigned char buf[4096]; /* XXX: large enough? too large? */
++ int len = mbedtls_x509write_csr_der((mbedtls_x509write_csr *)csr,
++ buf, sizeof(buf),
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg());
++ if (len < 0)
++ return NULL;
++ /* Note: data is written at the end of the buffer! Use the
++ * return value to determine where you should start
++ * using the buffer */
++ return wpabuf_alloc_copy(buf+sizeof(buf)-len, (size_t)len);
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_CSR */
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_PKCS7
++
++#if 0
++#include <mbedtls/pkcs7.h> /* PKCS7 is not currently supported in mbedtls */
++#include <mbedtls/pem.h>
++#endif
++
++struct wpabuf * crypto_pkcs7_get_certificates(const struct wpabuf *pkcs7)
++{
++ /* PKCS7 is not currently supported in mbedtls */
++ return NULL;
++
++#if 0
++ /* https://github.com/naynajain/mbedtls-1 branch: development-pkcs7
++ * (??? potential future contribution to mbedtls ???) */
++
++ /* Note: PKCS7 signature *is not* verified by this function.
++ * The function interface does not provide for passing a certificate */
++
++ mbedtls_pkcs7 mpkcs7;
++ mbedtls_pkcs7_init(&mpkcs7);
++ int pkcs7_type = mbedtls_pkcs7_parse_der(wpabuf_head(pkcs7),
++ wpabuf_len(pkcs7),
++ &mpkcs7);
++ wpabuf *buf = NULL;
++ do {
++ if (pkcs7_type < 0)
++ break;
++
++ /* src/common/dpp.c:dpp_parse_cred_dot1x() interested in certs
++ * for wpa_supplicant/dpp_supplicant.c:wpas_dpp_add_network()
++ * (? are adding certificate headers and footers desired ?) */
++
++ /* development-pkcs7 branch does not currently provide
++ * additional interfaces to retrieve the parsed data */
++
++ mbedtls_x509_crt *certs =
++ &mpkcs7.MBEDTLS_PRIVATE(signed_data).MBEDTLS_PRIVATE(certs);
++ int ncerts =
++ mpkcs7.MBEDTLS_PRIVATE(signed_data).MBEDTLS_PRIVATE(no_of_certs);
++
++ /* allocate buffer for PEM (base64-encoded DER)
++ * plus header, footer, newlines, and some extra */
++ buf = wpabuf_alloc((wpabuf_len(pkcs7)+2)/3*4 + ncerts*64);
++ if (buf == NULL)
++ break;
++
++ #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
++ #define PEM_END_CRT "-----END CERTIFICATE-----\n"
++ size_t olen;
++ for (int i = 0; i < ncerts; ++i) {
++ int ret = mbedtls_pem_write_buffer(
++ PEM_BEGIN_CRT, PEM_END_CRT,
++ certs[i].raw.p, certs[i].raw.len,
++ wpabuf_mhead(buf, 0), wpabuf_tailroom(buf),
++ &olen));
++ if (ret == 0)
++ wpabuf_put(buf, olen);
++ } else {
++ if (ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
++ ret = wpabuf_resize(
++ &buf,olen-wpabuf_tailroom(buf));
++ if (ret == 0) {
++ --i;/*(adjust loop iterator for retry)*/
++ continue;
++ }
++ wpabuf_free(buf);
++ buf = NULL;
++ break;
++ }
++ }
++ } while (0);
++
++ mbedtls_pkcs7_free(&mpkcs7);
++ return buf;
++#endif
++}
++
++#endif /* CRYPTO_MBEDTLS_CRYPTO_PKCS7 */
++
++
++#ifdef MBEDTLS_ARC4_C
++#include <mbedtls/arc4.h>
++int rc4_skip(const u8 *key, size_t keylen, size_t skip,
++ u8 *data, size_t data_len)
++{
++ mbedtls_arc4_context ctx;
++ mbedtls_arc4_init(&ctx);
++ mbedtls_arc4_setup(&ctx, key, keylen);
++
++ if (skip) {
++ /*(prefer [16] on ancient hardware with smaller cache lines)*/
++ unsigned char skip_buf[64]; /*('skip' is generally small)*/
++ /*os_memset(skip_buf, 0, sizeof(skip_buf));*/ /*(necessary?)*/
++ size_t len;
++ do {
++ len = skip > sizeof(skip_buf) ? sizeof(skip_buf) : skip;
++ mbedtls_arc4_crypt(&ctx, len, skip_buf, skip_buf);
++ } while ((skip -= len));
++ }
++
++ int ret = mbedtls_arc4_crypt(&ctx, data_len, data, data);
++ mbedtls_arc4_free(&ctx);
++ return ret;
++}
++#endif
++
++
++/* duplicated in tls_mbedtls.c:tls_mbedtls_readfile()*/
++__attribute_noinline__
++static int crypto_mbedtls_readfile(const char *path, u8 **buf, size_t *n)
++{
++ #if 0 /* #ifdef MBEDTLS_FS_IO */
++ /*(includes +1 for '\0' needed by mbedtls PEM parsing funcs)*/
++ if (mbedtls_pk_load_file(path, (unsigned char **)buf, n) != 0) {
++ wpa_printf(MSG_ERROR, "error: mbedtls_pk_load_file %s", path);
++ return -1;
++ }
++ #else
++ /*(use os_readfile() so that we can use os_free()
++ *(if we use mbedtls_pk_load_file() above, macros prevent calling free()
++ * directly #if defined(OS_REJECT_C_LIB_FUNCTIONS) and calling os_free()
++ * on buf aborts in tests if buf not allocated via os_malloc())*/
++ *buf = (u8 *)os_readfile(path, n);
++ if (!*buf) {
++ wpa_printf(MSG_ERROR, "error: os_readfile %s", path);
++ return -1;
++ }
++ u8 *buf0 = os_realloc(*buf, *n+1);
++ if (!buf0) {
++ bin_clear_free(*buf, *n);
++ *buf = NULL;
++ return -1;
++ }
++ buf0[(*n)++] = '\0';
++ *buf = buf0;
++ #endif
++ return 0;
++}
++
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_RSA
++#ifdef MBEDTLS_RSA_C
++
++#include <mbedtls/pk.h>
++#include <mbedtls/rsa.h>
++
++struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key)
++{
++ /* mbedtls_pk_parse_keyfile() and mbedtls_pk_parse_public_keyfile()
++ * require #ifdef MBEDTLS_FS_IO in mbedtls library. Prefer to use
++ * crypto_mbedtls_readfile(), which wraps os_readfile() */
++ u8 *data;
++ size_t len;
++ if (crypto_mbedtls_readfile(file, &data, &len) != 0)
++ return NULL;
++
++ mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
++ if (ctx == NULL) {
++ bin_clear_free(data, len);
++ return NULL;
++ }
++ mbedtls_pk_init(ctx);
++
++ int rc;
++ rc = (private_key
++ ? mbedtls_pk_parse_key(ctx, data, len, NULL, 0
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ ,mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg()
++ #endif
++ )
++ : mbedtls_pk_parse_public_key(ctx, data, len)) == 0
++ && mbedtls_pk_can_do(ctx, MBEDTLS_PK_RSA);
++
++ bin_clear_free(data, len);
++
++ if (rc) {
++ /* use MBEDTLS_RSA_PKCS_V21 padding for RSAES-OAEP */
++ /* use MBEDTLS_MD_SHA256 for these hostap interfaces */
++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++ /*(no return value in mbedtls 2.x)*/
++ mbedtls_rsa_set_padding(mbedtls_pk_rsa(*ctx),
++ MBEDTLS_RSA_PKCS_V21,
++ MBEDTLS_MD_SHA256);
++ #else
++ if (mbedtls_rsa_set_padding(mbedtls_pk_rsa(*ctx),
++ MBEDTLS_RSA_PKCS_V21,
++ MBEDTLS_MD_SHA256) == 0)
++ #endif
++ return (struct crypto_rsa_key *)ctx;
++ }
++
++ mbedtls_pk_free(ctx);
++ os_free(ctx);
++ return NULL;
++}
++
++struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
++ const struct wpabuf *in)
++{
++ mbedtls_rsa_context *pk_rsa = mbedtls_pk_rsa(*(mbedtls_pk_context*)key);
++ size_t olen = mbedtls_rsa_get_len(pk_rsa);
++ struct wpabuf *buf = wpabuf_alloc(olen);
++ if (buf == NULL)
++ return NULL;
++
++ /* mbedtls_pk_encrypt() takes a few more hops to get to same func */
++ if (mbedtls_rsa_rsaes_oaep_encrypt(pk_rsa,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg(),
++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++ MBEDTLS_RSA_PRIVATE,
++ #endif
++ NULL, 0,
++ wpabuf_len(in), wpabuf_head(in),
++ wpabuf_put(buf, olen)) == 0) {
++ return buf;
++ }
++
++ wpabuf_clear_free(buf);
++ return NULL;
++}
++
++struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
++ const struct wpabuf *in)
++{
++ mbedtls_rsa_context *pk_rsa = mbedtls_pk_rsa(*(mbedtls_pk_context*)key);
++ size_t olen = mbedtls_rsa_get_len(pk_rsa);
++ struct wpabuf *buf = wpabuf_alloc(olen);
++ if (buf == NULL)
++ return NULL;
++
++ /* mbedtls_pk_decrypt() takes a few more hops to get to same func */
++ if (mbedtls_rsa_rsaes_oaep_decrypt(pk_rsa,
++ mbedtls_ctr_drbg_random,
++ crypto_mbedtls_ctr_drbg(),
++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++ MBEDTLS_RSA_PUBLIC,
++ #endif
++ NULL, 0, &olen, wpabuf_head(in),
++ wpabuf_mhead(buf), olen) == 0) {
++ wpabuf_put(buf, olen);
++ return buf;
++ }
++
++ wpabuf_clear_free(buf);
++ return NULL;
++}
++
++void crypto_rsa_key_free(struct crypto_rsa_key *key)
++{
++ mbedtls_pk_free((mbedtls_pk_context *)key);
++ os_free(key);
++}
++
++#endif /* MBEDTLS_RSA_C */
++#endif /* CRYPTO_MBEDTLS_CRYPTO_RSA */
++
++#ifdef CRYPTO_MBEDTLS_CRYPTO_HPKE
++
++struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id,
++ enum hpke_kdf_id kdf_id,
++ enum hpke_aead_id aead_id,
++ struct crypto_ec_key *peer_pub,
++ const u8 *info, size_t info_len,
++ const u8 *aad, size_t aad_len,
++ const u8 *pt, size_t pt_len)
++{
++ /* not yet implemented */
++ return NULL;
++}
++
++struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id,
++ enum hpke_kdf_id kdf_id,
++ enum hpke_aead_id aead_id,
++ struct crypto_ec_key *own_priv,
++ const u8 *info, size_t info_len,
++ const u8 *aad, size_t aad_len,
++ const u8 *enc_ct, size_t enc_ct_len)
++{
++ /* not yet implemented */
++ return NULL;
++}
++
++#endif
+--- /dev/null
++++ b/src/crypto/tls_mbedtls.c
+@@ -0,0 +1,3313 @@
++/*
++ * SSL/TLS interface functions for mbed TLS
++ *
++ * SPDX-FileCopyrightText: 2022 Glenn Strauss <gstrauss@gluelogic.com>
++ * SPDX-License-Identifier: BSD-3-Clause
++ *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
++ *
++ * template: src/crypto/tls_none.c
++ * reference: src/crypto/tls_*.c
++ *
++ * Known Limitations:
++ * - no TLSv1.3 (not available in mbedtls 2.x; experimental in mbedtls 3.x)
++ * - no OCSP (not yet available in mbedtls)
++ * - mbedtls does not support all certificate encodings used by hwsim tests
++ * PCKS#5 v1.5
++ * PCKS#12
++ * DH DSA
++ * - EAP-FAST, EAP-TEAP session ticket support not implemented in tls_mbedtls.c
++ * - mbedtls does not currently provide way to set an attribute in a CSR
++ * https://github.com/Mbed-TLS/mbedtls/issues/4886
++ * so tests/hwsim dpp_enterprise tests fail
++ * - DPP2 not supported
++ * PKCS#7 parsing is not supported in mbedtls
++ * See crypto_mbedtls.c:crypto_pkcs7_get_certificates() comments
++ * - DPP3 not supported
++ * hpke_base_seal() and hpke_base_seal() not implemented in crypto_mbedtls.c
++ *
++ * Status:
++ * - code written to be compatible with mbedtls 2.x and mbedtls 3.x
++ * (currently requires mbedtls >= 2.27.0 for mbedtls_mpi_random())
++ * (currently requires mbedtls >= 2.18.0 for mbedtls_ssl_tls_prf())
++ * - builds with tests/build/build-wpa_supplicant-mbedtls.config
++ * - passes all tests/ crypto module tests (incomplete coverage)
++ * ($ cd tests; make clean; make -j 4 run-tests CONFIG_TLS=mbedtls)
++ * - passes almost all tests/hwsim tests
++ * (hwsim tests skipped for missing features)
++ *
++ * RFE:
++ * - EAP-FAST, EAP-TEAP session ticket support not implemented in tls_mbedtls.c
++ * - client/server session resumption, and/or save client session ticket
++ */
++
++#include "includes.h"
++#include "common.h"
++
++#include <mbedtls/version.h>
++#include <mbedtls/ctr_drbg.h>
++#include <mbedtls/error.h>
++#include <mbedtls/oid.h>
++#include <mbedtls/pem.h>
++#include <mbedtls/platform.h> /* mbedtls_calloc() mbedtls_free() */
++#include <mbedtls/platform_util.h> /* mbedtls_platform_zeroize() */
++#include <mbedtls/ssl.h>
++#include <mbedtls/ssl_ticket.h>
++#include <mbedtls/x509.h>
++#include <mbedtls/x509_crt.h>
++
++#if MBEDTLS_VERSION_NUMBER >= 0x02040000 /* mbedtls 2.4.0 */
++#include <mbedtls/net_sockets.h>
++#else
++#include <mbedtls/net.h>
++#endif
++
++#ifndef MBEDTLS_PRIVATE
++#define MBEDTLS_PRIVATE(x) x
++#endif
++
++#if MBEDTLS_VERSION_NUMBER < 0x03020000 /* mbedtls 3.2.0 */
++#define mbedtls_ssl_get_ciphersuite_id_from_ssl(ssl) \
++ ((ssl)->MBEDTLS_PRIVATE(session) \
++ ?(ssl)->MBEDTLS_PRIVATE(session)->MBEDTLS_PRIVATE(ciphersuite) \
++ : 0)
++#define mbedtls_ssl_ciphersuite_get_name(info) \
++ (info)->MBEDTLS_PRIVATE(name)
++#endif
++
++#include "crypto.h" /* sha256_vector() */
++#include "tls.h"
++
++#ifndef SHA256_DIGEST_LENGTH
++#define SHA256_DIGEST_LENGTH 32
++#endif
++
++#ifndef MBEDTLS_EXPKEY_FIXED_SECRET_LEN
++#define MBEDTLS_EXPKEY_FIXED_SECRET_LEN 48
++#endif
++
++#ifndef MBEDTLS_EXPKEY_RAND_LEN
++#define MBEDTLS_EXPKEY_RAND_LEN 32
++#endif
++
++#if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++static mbedtls_ssl_export_keys_t tls_connection_export_keys_cb;
++#elif MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++static mbedtls_ssl_export_keys_ext_t tls_connection_export_keys_cb;
++#else /*(not implemented; return error)*/
++#define mbedtls_ssl_tls_prf(a,b,c,d,e,f,g,h) (-1)
++typedef mbedtls_tls_prf_types int;
++#endif
++
++
++/* hostapd/wpa_supplicant provides forced_memzero(),
++ * but prefer mbedtls_platform_zeroize() */
++#define forced_memzero(ptr,sz) mbedtls_platform_zeroize(ptr,sz)
++
++
++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) \
++ || defined(EAP_TEAP) || defined(EAP_SERVER_TEAP)
++#ifdef MBEDTLS_SSL_SESSION_TICKETS
++#ifdef MBEDTLS_SSL_TICKET_C
++#define TLS_MBEDTLS_SESSION_TICKETS
++#if defined(EAP_TEAP) || defined(EAP_SERVER_TEAP)
++#define TLS_MBEDTLS_EAP_TEAP
++#endif
++#if !defined(CONFIG_FIPS) /* EAP-FAST keys cannot be exported in FIPS mode */
++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
++#define TLS_MBEDTLS_EAP_FAST
++#endif
++#endif
++#endif
++#endif
++#endif
++
++
++struct tls_conf {
++ mbedtls_ssl_config conf;
++
++ unsigned int verify_peer:1;
++ unsigned int verify_depth0_only:1;
++ unsigned int check_crl:2; /*(needs :2 bits for 0, 1, 2)*/
++ unsigned int check_crl_strict:1; /*(needs :1 bit for 0, 1)*/
++ unsigned int ca_cert_probe:1;
++ unsigned int has_ca_cert:1;
++ unsigned int has_client_cert:1;
++ unsigned int has_private_key:1;
++ unsigned int suiteb128:1;
++ unsigned int suiteb192:1;
++ mbedtls_x509_crl *crl;
++ mbedtls_x509_crt ca_cert;
++ mbedtls_x509_crt client_cert;
++ mbedtls_pk_context private_key;
++
++ uint32_t refcnt;
++
++ unsigned int flags;
++ char *subject_match;
++ char *altsubject_match;
++ char *suffix_match;
++ char *domain_match;
++ char *check_cert_subject;
++ u8 ca_cert_hash[SHA256_DIGEST_LENGTH];
++
++ int *ciphersuites; /* list of ciphersuite ids for mbedtls_ssl_config */
++#if MBEDTLS_VERSION_NUMBER < 0x03010000 /* mbedtls 3.1.0 */
++ mbedtls_ecp_group_id *curves;
++#else
++ uint16_t *curves; /* list of curve ids for mbedtls_ssl_config */
++#endif
++};
++
++
++struct tls_global {
++ struct tls_conf *tls_conf;
++ char *ocsp_stapling_response;
++ mbedtls_ctr_drbg_context *ctr_drbg; /*(see crypto_mbedtls.c)*/
++ #ifdef MBEDTLS_SSL_SESSION_TICKETS
++ mbedtls_ssl_ticket_context ticket_ctx;
++ #endif
++ char *ca_cert_file;
++ struct os_reltime crl_reload_previous;
++ unsigned int crl_reload_interval;
++ uint32_t refcnt;
++ struct tls_config init_conf;
++};
++
++static struct tls_global tls_ctx_global;
++
++
++struct tls_connection {
++ struct tls_conf *tls_conf;
++ struct wpabuf *push_buf;
++ struct wpabuf *pull_buf;
++ size_t pull_buf_offset;
++
++ unsigned int established:1;
++ unsigned int resumed:1;
++ unsigned int verify_peer:1;
++ unsigned int is_server:1;
++
++ mbedtls_ssl_context ssl;
++
++ mbedtls_tls_prf_types tls_prf_type;
++ size_t expkey_keyblock_size;
++ size_t expkey_secret_len;
++ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++ unsigned char expkey_secret[MBEDTLS_EXPKEY_FIXED_SECRET_LEN];
++ #else
++ unsigned char expkey_secret[MBEDTLS_MD_MAX_SIZE];
++ #endif
++ unsigned char expkey_randbytes[MBEDTLS_EXPKEY_RAND_LEN*2];
++
++ int read_alerts, write_alerts, failed;
++
++ #ifdef TLS_MBEDTLS_SESSION_TICKETS
++ tls_session_ticket_cb session_ticket_cb;
++ void *session_ticket_cb_ctx;
++ unsigned char *clienthello_session_ticket;
++ size_t clienthello_session_ticket_len;
++ #endif
++ char *peer_subject; /* peer subject info for authenticated peer */
++ struct wpabuf *success_data;
++};
++
++
++#ifndef __has_attribute
++#define __has_attribute(x) 0
++#endif
++
++#ifndef __GNUC_PREREQ
++#define __GNUC_PREREQ(maj,min) 0
++#endif
++
++#ifndef __attribute_cold__
++#if __has_attribute(cold) \
++ || __GNUC_PREREQ(4,3)
++#define __attribute_cold__ __attribute__((__cold__))
++#else
++#define __attribute_cold__
++#endif
++#endif
++
++#ifndef __attribute_noinline__
++#if __has_attribute(noinline) \
++ || __GNUC_PREREQ(3,1)
++#define __attribute_noinline__ __attribute__((__noinline__))
++#else
++#define __attribute_noinline__
++#endif
++#endif
++
++
++__attribute_cold__
++__attribute_noinline__
++static void emsg(int level, const char * const msg)
++{
++ wpa_printf(level, "MTLS: %s", msg);
++}
++
++
++__attribute_cold__
++__attribute_noinline__
++static void emsgrc(int level, const char * const msg, int rc)
++{
++ #ifdef MBEDTLS_ERROR_C
++ /* error logging convenience function that decodes mbedtls result codes */
++ char buf[256];
++ mbedtls_strerror(rc, buf, sizeof(buf));
++ wpa_printf(level, "MTLS: %s: %s (-0x%04x)", msg, buf, -rc);
++ #else
++ wpa_printf(level, "MTLS: %s: (-0x%04x)", msg, -rc);
++ #endif
++}
++
++
++#define elog(rc, msg) emsgrc(MSG_ERROR, (msg), (rc))
++#define ilog(rc, msg) emsgrc(MSG_INFO, (msg), (rc))
++
++
++struct tls_conf * tls_conf_init(void *tls_ctx)
++{
++ struct tls_conf *tls_conf = os_zalloc(sizeof(*tls_conf));
++ if (tls_conf == NULL)
++ return NULL;
++ tls_conf->refcnt = 1;
++
++ mbedtls_ssl_config_init(&tls_conf->conf);
++ mbedtls_ssl_conf_rng(&tls_conf->conf,
++ mbedtls_ctr_drbg_random, tls_ctx_global.ctr_drbg);
++ mbedtls_x509_crt_init(&tls_conf->ca_cert);
++ mbedtls_x509_crt_init(&tls_conf->client_cert);
++ mbedtls_pk_init(&tls_conf->private_key);
++
++ return tls_conf;
++}
++
++
++void tls_conf_deinit(struct tls_conf *tls_conf)
++{
++ if (tls_conf == NULL || --tls_conf->refcnt != 0)
++ return;
++
++ mbedtls_x509_crt_free(&tls_conf->ca_cert);
++ mbedtls_x509_crt_free(&tls_conf->client_cert);
++ if (tls_conf->crl) {
++ mbedtls_x509_crl_free(tls_conf->crl);
++ os_free(tls_conf->crl);
++ }
++ mbedtls_pk_free(&tls_conf->private_key);
++ mbedtls_ssl_config_free(&tls_conf->conf);
++ os_free(tls_conf->curves);
++ os_free(tls_conf->ciphersuites);
++ os_free(tls_conf->subject_match);
++ os_free(tls_conf->altsubject_match);
++ os_free(tls_conf->suffix_match);
++ os_free(tls_conf->domain_match);
++ os_free(tls_conf->check_cert_subject);
++ os_free(tls_conf);
++}
++
++
++mbedtls_ctr_drbg_context * crypto_mbedtls_ctr_drbg(void); /*(not in header)*/
++
++__attribute_cold__
++void * tls_init(const struct tls_config *conf)
++{
++ /* RFE: review struct tls_config *conf (different from tls_conf) */
++
++ if (++tls_ctx_global.refcnt > 1)
++ return &tls_ctx_global;
++
++ tls_ctx_global.ctr_drbg = crypto_mbedtls_ctr_drbg();
++ #ifdef MBEDTLS_SSL_SESSION_TICKETS
++ mbedtls_ssl_ticket_init(&tls_ctx_global.ticket_ctx);
++ mbedtls_ssl_ticket_setup(&tls_ctx_global.ticket_ctx,
++ mbedtls_ctr_drbg_random,
++ tls_ctx_global.ctr_drbg,
++ MBEDTLS_CIPHER_AES_256_GCM,
++ 43200); /* ticket timeout: 12 hours */
++ #endif
++ /* copy struct for future use */
++ tls_ctx_global.init_conf = *conf;
++ if (conf->openssl_ciphers)
++ tls_ctx_global.init_conf.openssl_ciphers =
++ os_strdup(conf->openssl_ciphers);
++
++ tls_ctx_global.crl_reload_interval = conf->crl_reload_interval;
++ os_get_reltime(&tls_ctx_global.crl_reload_previous);
++
++ return &tls_ctx_global;
++}
++
++
++__attribute_cold__
++void tls_deinit(void *tls_ctx)
++{
++ if (tls_ctx == NULL || --tls_ctx_global.refcnt != 0)
++ return;
++
++ tls_conf_deinit(tls_ctx_global.tls_conf);
++ os_free(tls_ctx_global.ca_cert_file);
++ os_free(tls_ctx_global.ocsp_stapling_response);
++ char *openssl_ciphers; /*(allocated in tls_init())*/
++ *(const char **)&openssl_ciphers =
++ tls_ctx_global.init_conf.openssl_ciphers;
++ os_free(openssl_ciphers);
++ #ifdef MBEDTLS_SSL_SESSION_TICKETS
++ mbedtls_ssl_ticket_free(&tls_ctx_global.ticket_ctx);
++ #endif
++ os_memset(&tls_ctx_global, 0, sizeof(tls_ctx_global));
++}
++
++
++int tls_get_errors(void *tls_ctx)
++{
++ return 0;
++}
++
++
++static void tls_connection_deinit_expkey(struct tls_connection *conn)
++{
++ conn->tls_prf_type = 0; /* MBEDTLS_SSL_TLS_PRF_NONE; */
++ conn->expkey_keyblock_size = 0;
++ conn->expkey_secret_len = 0;
++ forced_memzero(conn->expkey_secret, sizeof(conn->expkey_secret));
++ forced_memzero(conn->expkey_randbytes, sizeof(conn->expkey_randbytes));
++}
++
++
++#ifdef TLS_MBEDTLS_SESSION_TICKETS
++void tls_connection_deinit_clienthello_session_ticket(struct tls_connection *conn)
++{
++ if (conn->clienthello_session_ticket) {
++ mbedtls_platform_zeroize(conn->clienthello_session_ticket,
++ conn->clienthello_session_ticket_len);
++ mbedtls_free(conn->clienthello_session_ticket);
++ conn->clienthello_session_ticket = NULL;
++ conn->clienthello_session_ticket_len = 0;
++ }
++}
++#endif
++
++
++void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
++{
++ if (conn == NULL)
++ return;
++
++ #if 0 /*(good intention, but never sent since we destroy self below)*/
++ if (conn->established)
++ mbedtls_ssl_close_notify(&conn->ssl);
++ #endif
++
++ if (conn->tls_prf_type)
++ tls_connection_deinit_expkey(conn);
++
++ #ifdef TLS_MBEDTLS_SESSION_TICKETS
++ if (conn->clienthello_session_ticket)
++ tls_connection_deinit_clienthello_session_ticket(conn);
++ #endif
++
++ os_free(conn->peer_subject);
++ wpabuf_free(conn->success_data);
++ wpabuf_free(conn->push_buf);
++ wpabuf_free(conn->pull_buf);
++ mbedtls_ssl_free(&conn->ssl);
++ tls_conf_deinit(conn->tls_conf);
++ os_free(conn);
++}
++
++
++static void tls_mbedtls_refresh_crl(void);
++static int tls_mbedtls_ssl_setup(struct tls_connection *conn);
++
++struct tls_connection * tls_connection_init(void *tls_ctx)
++{
++ struct tls_connection *conn = os_zalloc(sizeof(*conn));
++ if (conn == NULL)
++ return NULL;
++
++ mbedtls_ssl_init(&conn->ssl);
++
++ conn->tls_conf = tls_ctx_global.tls_conf; /*(inherit global conf, if set)*/
++ if (conn->tls_conf) {
++ ++conn->tls_conf->refcnt;
++ /* check for CRL refresh if inheriting from global config */
++ tls_mbedtls_refresh_crl();
++
++ conn->verify_peer = conn->tls_conf->verify_peer;
++ if (tls_mbedtls_ssl_setup(conn) != 0) {
++ tls_connection_deinit(&tls_ctx_global, conn);
++ return NULL;
++ }
++ }
++
++ return conn;
++}
++
++
++int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
++{
++ return conn ? conn->established : 0;
++}
++
++
++__attribute_noinline__
++char * tls_mbedtls_peer_serial_num(const mbedtls_x509_crt *crt, char *serial_num, size_t len)
++{
++ /* mbedtls_x509_serial_gets() inefficiently formats to hex separated by
++ * colons, so generate the hex serial number here. The func
++ * wpa_snprintf_hex_uppercase() is similarly inefficient. */
++ size_t i = 0; /* skip leading 0's per Distinguished Encoding Rules (DER) */
++ while (i < crt->serial.len && crt->serial.p[i] == 0) ++i;
++ if (i == crt->serial.len) --i;
++
++ const unsigned char *s = crt->serial.p + i;
++ const size_t e = (crt->serial.len - i) * 2;
++ if (e >= len)
++ return NULL;
++ #if 0
++ wpa_snprintf_hex_uppercase(serial_num, len, s, crt->serial.len-i);
++ #else
++ for (i = 0; i < e; i+=2, ++s) {
++ serial_num[i+0] = "0123456789ABCDEF"[(*s >> 4)];
++ serial_num[i+1] = "0123456789ABCDEF"[(*s & 0xF)];
++ }
++ serial_num[e] = '\0';
++ #endif
++ return serial_num;
++}
++
++
++char * tls_connection_peer_serial_num(void *tls_ctx,
++ struct tls_connection *conn)
++{
++ const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&conn->ssl);
++ if (crt == NULL)
++ return NULL;
++ size_t len = crt->serial.len * 2 + 1;
++ char *serial_num = os_malloc(len);
++ if (!serial_num)
++ return NULL;
++ return tls_mbedtls_peer_serial_num(crt, serial_num, len);
++}
++
++
++static void tls_pull_buf_reset(struct tls_connection *conn);
++
++int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
++{
++ /* Note: this function called from eap_peer_tls_reauth_init()
++ * for session resumption, not for connection shutdown */
++
++ if (conn == NULL)
++ return -1;
++
++ tls_pull_buf_reset(conn);
++ wpabuf_free(conn->push_buf);
++ conn->push_buf = NULL;
++ conn->established = 0;
++ conn->resumed = 0;
++ if (conn->tls_prf_type)
++ tls_connection_deinit_expkey(conn);
++
++ /* RFE: prepare for session resumption? (see doc in crypto/tls.h) */
++
++ return mbedtls_ssl_session_reset(&conn->ssl);
++}
++
++
++static int tls_wpabuf_resize_put_data(struct wpabuf **buf,
++ const unsigned char *data, size_t dlen)
++{
++ if (wpabuf_resize(buf, dlen) < 0)
++ return 0;
++ wpabuf_put_data(*buf, data, dlen);
++ return 1;
++}
++
++
++static int tls_pull_buf_append(struct tls_connection *conn,
++ const struct wpabuf *in_data)
++{
++ /*(interface does not lend itself to move semantics)*/
++ return tls_wpabuf_resize_put_data(&conn->pull_buf,
++ wpabuf_head(in_data),
++ wpabuf_len(in_data));
++}
++
++
++static void tls_pull_buf_reset(struct tls_connection *conn)
++{
++ /*(future: might consider reusing conn->pull_buf)*/
++ wpabuf_free(conn->pull_buf);
++ conn->pull_buf = NULL;
++ conn->pull_buf_offset = 0;
++}
++
++
++__attribute_cold__
++static void tls_pull_buf_discard(struct tls_connection *conn, const char *func)
++{
++ size_t discard = wpabuf_len(conn->pull_buf) - conn->pull_buf_offset;
++ if (discard)
++ wpa_printf(MSG_DEBUG,
++ "%s - %zu bytes remaining in pull_buf; discarding",
++ func, discard);
++ tls_pull_buf_reset(conn);
++}
++
++
++static int tls_pull_func(void *ptr, unsigned char *buf, size_t len)
++{
++ struct tls_connection *conn = (struct tls_connection *) ptr;
++ if (conn->pull_buf == NULL)
++ return MBEDTLS_ERR_SSL_WANT_READ;
++ const size_t dlen = wpabuf_len(conn->pull_buf) - conn->pull_buf_offset;
++ if (dlen == 0)
++ return MBEDTLS_ERR_SSL_WANT_READ;
++
++ if (len > dlen)
++ len = dlen;
++ os_memcpy(buf, wpabuf_head(conn->pull_buf)+conn->pull_buf_offset, len);
++
++ if (len == dlen) {
++ tls_pull_buf_reset(conn);
++ /*wpa_printf(MSG_DEBUG, "%s - emptied pull_buf", __func__);*/
++ }
++ else {
++ conn->pull_buf_offset += len;
++ /*wpa_printf(MSG_DEBUG, "%s - %zu bytes remaining in pull_buf",
++ __func__, dlen - len);*/
++ }
++ return (int)len;
++}
++
++
++static int tls_push_func(void *ptr, const unsigned char *buf, size_t len)
++{
++ struct tls_connection *conn = (struct tls_connection *) ptr;
++ return tls_wpabuf_resize_put_data(&conn->push_buf, buf, len)
++ ? (int)len
++ : MBEDTLS_ERR_SSL_ALLOC_FAILED;
++}
++
++
++static int
++tls_mbedtls_verify_cb (void *arg, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
++
++
++static int tls_mbedtls_ssl_setup(struct tls_connection *conn)
++{
++ #if 0
++ /* mbedtls_ssl_setup() must be called only once */
++ /* If this func might be called multiple times (e.g. via set_params),
++ * then we should set a flag in conn that ssl was initialized */
++ if (conn->ssl_is_init) {
++ mbedtls_ssl_free(&conn->ssl);
++ mbedtls_ssl_init(&conn->ssl);
++ }
++ #endif
++
++ int ret = mbedtls_ssl_setup(&conn->ssl, &conn->tls_conf->conf);
++ if (ret != 0) {
++ elog(ret, "mbedtls_ssl_setup");
++ return -1;
++ }
++
++ mbedtls_ssl_set_bio(&conn->ssl, conn, tls_push_func, tls_pull_func, NULL);
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ mbedtls_ssl_set_export_keys_cb(
++ &conn->ssl, tls_connection_export_keys_cb, conn);
++ #elif MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++ mbedtls_ssl_conf_export_keys_ext_cb(
++ &conn->tls_conf->conf, tls_connection_export_keys_cb, conn);
++ #endif
++ if (conn->verify_peer)
++ mbedtls_ssl_set_verify(&conn->ssl, tls_mbedtls_verify_cb, conn);
++
++ return 0;
++}
++
++
++static int tls_mbedtls_data_is_pem(const u8 *data)
++{
++ return (NULL != os_strstr((char *)data, "-----"));
++}
++
++
++static void tls_mbedtls_set_allowed_tls_vers(struct tls_conf *tls_conf,
++ mbedtls_ssl_config *conf)
++{
++ #if !defined(MBEDTLS_SSL_PROTO_TLS1_3)
++ tls_conf->flags |= TLS_CONN_DISABLE_TLSv1_3;
++ #endif
++
++ /* unconditionally require TLSv1.2+ for TLS_CONN_SUITEB */
++ if (tls_conf->flags & TLS_CONN_SUITEB) {
++ tls_conf->flags |= TLS_CONN_DISABLE_TLSv1_0;
++ tls_conf->flags |= TLS_CONN_DISABLE_TLSv1_1;
++ }
++
++ const unsigned int flags = tls_conf->flags;
++
++ /* attempt to map flags to min and max TLS protocol version */
++
++ int min = (flags & TLS_CONN_DISABLE_TLSv1_0)
++ ? (flags & TLS_CONN_DISABLE_TLSv1_1)
++ ? (flags & TLS_CONN_DISABLE_TLSv1_2)
++ ? (flags & TLS_CONN_DISABLE_TLSv1_3)
++ ? 4
++ : 3
++ : 2
++ : 1
++ : 0;
++
++ int max = (flags & TLS_CONN_DISABLE_TLSv1_3)
++ ? (flags & TLS_CONN_DISABLE_TLSv1_2)
++ ? (flags & TLS_CONN_DISABLE_TLSv1_1)
++ ? (flags & TLS_CONN_DISABLE_TLSv1_0)
++ ? -1
++ : 0
++ : 1
++ : 2
++ : 3;
++
++ if ((flags & TLS_CONN_ENABLE_TLSv1_2) && min > 2) min = 2;
++ if ((flags & TLS_CONN_ENABLE_TLSv1_1) && min > 1) min = 1;
++ if ((flags & TLS_CONN_ENABLE_TLSv1_0) && min > 0) min = 0;
++ if (max < min) {
++ emsg(MSG_ERROR, "invalid tls_disable_tlsv* params; ignoring");
++ return;
++ }
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ /* mbed TLS 3.0.0 removes support for protocols < TLSv1.2 */
++ if (min < 2 || max < 2) {
++ emsg(MSG_ERROR, "invalid tls_disable_tlsv* params; ignoring");
++ if (min < 2) min = 2;
++ if (max < 2) max = 2;
++ }
++ #endif
++
++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */
++ /* MBEDTLS_SSL_VERSION_TLS1_2 = 0x0303 *//*!< (D)TLS 1.2 */
++ /* MBEDTLS_SSL_VERSION_TLS1_3 = 0x0304 *//*!< (D)TLS 1.3 */
++ min = (min == 2) ? MBEDTLS_SSL_VERSION_TLS1_2 : MBEDTLS_SSL_VERSION_TLS1_3;
++ max = (max == 2) ? MBEDTLS_SSL_VERSION_TLS1_2 : MBEDTLS_SSL_VERSION_TLS1_3;
++ mbedtls_ssl_conf_min_tls_version(conf, min);
++ mbedtls_ssl_conf_max_tls_version(conf, max);
++ #else
++ #ifndef MBEDTLS_SSL_MINOR_VERSION_4
++ if (min == 3) min = 2;
++ if (max == 3) max = 2;
++ #endif
++ /* MBEDTLS_SSL_MINOR_VERSION_0 0 *//*!< SSL v3.0 */
++ /* MBEDTLS_SSL_MINOR_VERSION_1 1 *//*!< TLS v1.0 */
++ /* MBEDTLS_SSL_MINOR_VERSION_2 2 *//*!< TLS v1.1 */
++ /* MBEDTLS_SSL_MINOR_VERSION_3 3 *//*!< TLS v1.2 */
++ /* MBEDTLS_SSL_MINOR_VERSION_4 4 *//*!< TLS v1.3 */
++ mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, min+1);
++ mbedtls_ssl_conf_max_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, max+1);
++ #endif
++}
++
++
++__attribute_noinline__
++static int tls_mbedtls_readfile(const char *path, u8 **buf, size_t *n);
++
++
++static int
++tls_mbedtls_set_dhparams(struct tls_conf *tls_conf, const char *dh_file)
++{
++ size_t len;
++ u8 *data;
++ if (tls_mbedtls_readfile(dh_file, &data, &len))
++ return 0;
++
++ /* parse only if DH parameters if in PEM format */
++ if (tls_mbedtls_data_is_pem(data)
++ && NULL == os_strstr((char *)data, "-----BEGIN DH PARAMETERS-----")) {
++ if (os_strstr((char *)data, "-----BEGIN DSA PARAMETERS-----"))
++ wpa_printf(MSG_WARNING, "DSA parameters not handled (%s)", dh_file);
++ else
++ wpa_printf(MSG_WARNING, "unexpected DH param content (%s)",dh_file);
++ forced_memzero(data, len);
++ os_free(data);
++ return 0;
++ }
++
++ /* mbedtls_dhm_parse_dhm() expects "-----BEGIN DH PARAMETERS-----" if PEM */
++ mbedtls_dhm_context dhm;
++ mbedtls_dhm_init(&dhm);
++ int rc = mbedtls_dhm_parse_dhm(&dhm, data, len);
++ if (0 == rc)
++ rc = mbedtls_ssl_conf_dh_param_ctx(&tls_conf->conf, &dhm);
++ if (0 != rc)
++ elog(rc, dh_file);
++ mbedtls_dhm_free(&dhm);
++
++ forced_memzero(data, len);
++ os_free(data);
++ return (0 == rc);
++}
++
++
++/* reference: lighttpd src/mod_mbedtls.c:mod_mbedtls_ssl_append_curve()
++ * (same author: gstrauss@gluelogic.com; same license: BSD-3-Clause) */
++#if MBEDTLS_VERSION_NUMBER < 0x03010000 /* mbedtls 3.1.0 */
++static int
++tls_mbedtls_append_curve (mbedtls_ecp_group_id *ids, int nids, int idsz, const mbedtls_ecp_group_id id)
++{
++ if (1 >= idsz - (nids + 1)) {
++ emsg(MSG_ERROR, "error: too many curves during list expand");
++ return -1;
++ }
++ ids[++nids] = id;
++ return nids;
++}
++
++
++static int
++tls_mbedtls_set_curves(struct tls_conf *tls_conf, const char *curvelist)
++{
++ mbedtls_ecp_group_id ids[512];
++ int nids = -1;
++ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1);
++ const mbedtls_ecp_curve_info * const curve_info = mbedtls_ecp_curve_list();
++
++ for (const char *e = curvelist-1; e; ) {
++ const char * const n = e+1;
++ e = os_strchr(n, ':');
++ size_t len = e ? (size_t)(e - n) : os_strlen(n);
++ mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE;
++ switch (len) {
++ case 5:
++ if (0 == os_memcmp("P-521", n, 5))
++ grp_id = MBEDTLS_ECP_DP_SECP521R1;
++ else if (0 == os_memcmp("P-384", n, 5))
++ grp_id = MBEDTLS_ECP_DP_SECP384R1;
++ else if (0 == os_memcmp("P-256", n, 5))
++ grp_id = MBEDTLS_ECP_DP_SECP256R1;
++ break;
++ case 6:
++ if (0 == os_memcmp("BP-521", n, 6))
++ grp_id = MBEDTLS_ECP_DP_BP512R1;
++ else if (0 == os_memcmp("BP-384", n, 6))
++ grp_id = MBEDTLS_ECP_DP_BP384R1;
++ else if (0 == os_memcmp("BP-256", n, 6))
++ grp_id = MBEDTLS_ECP_DP_BP256R1;
++ break;
++ default:
++ break;
++ }
++ if (grp_id != MBEDTLS_ECP_DP_NONE) {
++ nids = tls_mbedtls_append_curve(ids, nids, idsz, grp_id);
++ if (-1 == nids) return 0;
++ continue;
++ }
++ /* similar to mbedtls_ecp_curve_info_from_name() */
++ const mbedtls_ecp_curve_info *info;
++ for (info = curve_info; info->grp_id != MBEDTLS_ECP_DP_NONE; ++info) {
++ if (0 == os_strncmp(info->name, n, len) && info->name[len] == '\0')
++ break;
++ }
++ if (info->grp_id == MBEDTLS_ECP_DP_NONE) {
++ wpa_printf(MSG_ERROR, "MTLS: unrecognized curve: %.*s",(int)len,n);
++ return 0;
++ }
++
++ nids = tls_mbedtls_append_curve(ids, nids, idsz, info->grp_id);
++ if (-1 == nids) return 0;
++ }
++
++ /* mod_openssl configures "prime256v1" if curve list not specified,
++ * but mbedtls provides a list of supported curves if not explicitly set */
++ if (-1 == nids) return 1; /* empty list; no-op */
++
++ ids[++nids] = MBEDTLS_ECP_DP_NONE; /* terminate list */
++ ++nids;
++
++ /* curves list must be persistent for lifetime of mbedtls_ssl_config */
++ tls_conf->curves = os_malloc(nids * sizeof(mbedtls_ecp_group_id));
++ if (tls_conf->curves == NULL)
++ return 0;
++ os_memcpy(tls_conf->curves, ids, nids * sizeof(mbedtls_ecp_group_id));
++
++ mbedtls_ssl_conf_curves(&tls_conf->conf, tls_conf->curves);
++ return 1;
++}
++#else
++static int
++tls_mbedtls_append_curve (uint16_t *ids, int nids, int idsz, const uint16_t id)
++{
++ if (1 >= idsz - (nids + 1)) {
++ emsg(MSG_ERROR, "error: too many curves during list expand");
++ return -1;
++ }
++ ids[++nids] = id;
++ return nids;
++}
++
++
++static int
++tls_mbedtls_set_curves(struct tls_conf *tls_conf, const char *curvelist)
++{
++ /* TLS Supported Groups (renamed from "EC Named Curve Registry")
++ * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
++ */
++ uint16_t ids[512];
++ int nids = -1;
++ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1);
++ const mbedtls_ecp_curve_info * const curve_info = mbedtls_ecp_curve_list();
++
++ for (const char *e = curvelist-1; e; ) {
++ const char * const n = e+1;
++ e = os_strchr(n, ':');
++ size_t len = e ? (size_t)(e - n) : os_strlen(n);
++ uint16_t tls_id = 0;
++ switch (len) {
++ case 5:
++ if (0 == os_memcmp("P-521", n, 5))
++ tls_id = 25; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_SECP521R1 */
++ else if (0 == os_memcmp("P-384", n, 5))
++ tls_id = 24; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_SECP384R1 */
++ else if (0 == os_memcmp("P-256", n, 5))
++ tls_id = 23; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_SECP256R1 */
++ break;
++ case 6:
++ if (0 == os_memcmp("BP-521", n, 6))
++ tls_id = 28; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_BP512R1 */
++ else if (0 == os_memcmp("BP-384", n, 6))
++ tls_id = 27; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_BP384R1 */
++ else if (0 == os_memcmp("BP-256", n, 6))
++ tls_id = 26; /* mbedtls_ecp_group_id MBEDTLS_ECP_DP_BP256R1 */
++ break;
++ default:
++ break;
++ }
++ if (tls_id != 0) {
++ nids = tls_mbedtls_append_curve(ids, nids, idsz, tls_id);
++ if (-1 == nids) return 0;
++ continue;
++ }
++ /* similar to mbedtls_ecp_curve_info_from_name() */
++ const mbedtls_ecp_curve_info *info;
++ for (info = curve_info; info->tls_id != 0; ++info) {
++ if (0 == os_strncmp(info->name, n, len) && info->name[len] == '\0')
++ break;
++ }
++ if (info->tls_id == 0) {
++ wpa_printf(MSG_ERROR, "MTLS: unrecognized curve: %.*s",(int)len,n);
++ return 0;
++ }
++
++ nids = tls_mbedtls_append_curve(ids, nids, idsz, info->tls_id);
++ if (-1 == nids) return 0;
++ }
++
++ /* mod_openssl configures "prime256v1" if curve list not specified,
++ * but mbedtls provides a list of supported curves if not explicitly set */
++ if (-1 == nids) return 1; /* empty list; no-op */
++
++ ids[++nids] = 0; /* terminate list */
++ ++nids;
++
++ /* curves list must be persistent for lifetime of mbedtls_ssl_config */
++ tls_conf->curves = os_malloc(nids * sizeof(uint16_t));
++ if (tls_conf->curves == NULL)
++ return 0;
++ os_memcpy(tls_conf->curves, ids, nids * sizeof(uint16_t));
++
++ mbedtls_ssl_conf_groups(&tls_conf->conf, tls_conf->curves);
++ return 1;
++}
++#endif /* MBEDTLS_VERSION_NUMBER >= 0x03010000 */ /* mbedtls 3.1.0 */
++
++
++/* data copied from lighttpd src/mod_mbedtls.c (BSD-3-Clause) */
++static const int suite_AES_256_ephemeral[] = {
++ /* All AES-256 ephemeral suites */
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8
++};
++
++/* data copied from lighttpd src/mod_mbedtls.c (BSD-3-Clause) */
++static const int suite_AES_128_ephemeral[] = {
++ /* All AES-128 ephemeral suites */
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8
++};
++
++/* data copied from lighttpd src/mod_mbedtls.c (BSD-3-Clause) */
++/* HIGH cipher list (mapped from openssl list to mbedtls) */
++static const int suite_HIGH[] = {
++ MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
++ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
++ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
++ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
++ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8,
++ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8,
++ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
++ MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_RSA_WITH_AES_256_CCM,
++ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256,
++ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8,
++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
++ MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_RSA_WITH_AES_128_CCM,
++ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8,
++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
++ MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
++ MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
++ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
++ MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
++ MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
++ MBEDTLS_TLS_PSK_WITH_AES_256_CCM,
++ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384,
++ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA,
++ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
++ MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8,
++ MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
++ MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256,
++ MBEDTLS_TLS_PSK_WITH_AES_128_CCM,
++ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256,
++ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA,
++ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
++ MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
++ MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256
++};
++
++
++__attribute_noinline__
++static int
++tls_mbedtls_append_ciphersuite (int *ids, int nids, int idsz, const int *x, int xsz)
++{
++ if (xsz >= idsz - (nids + 1)) {
++ emsg(MSG_ERROR, "error: too many ciphers during list expand");
++ return -1;
++ }
++
++ for (int i = 0; i < xsz; ++i)
++ ids[++nids] = x[i];
++
++ return nids;
++}
++
++
++static int
++tls_mbedtls_translate_ciphername(int id, char *buf, size_t buflen)
++{
++ const mbedtls_ssl_ciphersuite_t *info =
++ mbedtls_ssl_ciphersuite_from_id(id);
++ if (info == NULL)
++ return 0;
++ const char *name = mbedtls_ssl_ciphersuite_get_name(info);
++ const size_t len = os_strlen(name);
++ if (len == 7 && 0 == os_memcmp(name, "unknown", 7))
++ return 0;
++ if (len >= buflen)
++ return 0;
++ os_strlcpy(buf, name, buflen);
++
++ /* attempt to translate mbedtls string to openssl string
++ * (some heuristics; incomplete) */
++ size_t i = 0, j = 0;
++ if (buf[0] == 'T') {
++ if (os_strncmp(buf, "TLS1-3-", 7) == 0) {
++ buf[3] = '-';
++ j = 4; /* remove "1-3" from "TLS1-3-" prefix */
++ i = 7;
++ }
++ else if (os_strncmp(buf, "TLS-", 4) == 0)
++ i = 4; /* remove "TLS-" prefix */
++ }
++ for (; buf[i]; ++i) {
++ if (buf[i] == '-') {
++ if (i >= 3) {
++ if (0 == os_memcmp(buf+i-3, "AES", 3))
++ continue; /* "AES-" -> "AES" */
++ }
++ if (i >= 4) {
++ if (0 == os_memcmp(buf+i-4, "WITH", 4)) {
++ j -= 4; /* remove "WITH-" */
++ continue;
++ }
++ }
++ }
++ buf[j++] = buf[i];
++ }
++ buf[j] = '\0';
++
++ return j;
++}
++
++
++__attribute_noinline__
++static int
++tls_mbedtls_set_ciphersuites(struct tls_conf *tls_conf, int *ids, int nids)
++{
++ /* ciphersuites list must be persistent for lifetime of mbedtls_ssl_config*/
++ os_free(tls_conf->ciphersuites);
++ tls_conf->ciphersuites = os_malloc(nids * sizeof(int));
++ if (tls_conf->ciphersuites == NULL)
++ return 0;
++ os_memcpy(tls_conf->ciphersuites, ids, nids * sizeof(int));
++ mbedtls_ssl_conf_ciphersuites(&tls_conf->conf, tls_conf->ciphersuites);
++ return 1;
++}
++
++
++static int
++tls_mbedtls_set_ciphers(struct tls_conf *tls_conf, const char *ciphers)
++{
++ char buf[64];
++ int ids[512];
++ int nids = -1;
++ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1);
++ const char *next;
++ size_t blen, clen;
++ do {
++ next = os_strchr(ciphers, ':');
++ clen = next ? (size_t)(next - ciphers) : os_strlen(ciphers);
++ if (!clen)
++ continue;
++
++ /* special-case a select set of openssl group names for hwsim tests */
++ /* (review; remove excess code if tests are not run for non-OpenSSL?) */
++ if (clen == 9 && os_memcmp(ciphers, "SUITEB192", 9) == 0) {
++ static int ssl_preset_suiteb192_ciphersuites[] = {
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
++ 0
++ };
++ return tls_mbedtls_set_ciphersuites(tls_conf,
++ ssl_preset_suiteb192_ciphersuites,
++ 2);
++ }
++ if (clen == 9 && os_memcmp(ciphers, "SUITEB128", 9) == 0) {
++ static int ssl_preset_suiteb128_ciphersuites[] = {
++ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
++ 0
++ };
++ return tls_mbedtls_set_ciphersuites(tls_conf,
++ ssl_preset_suiteb128_ciphersuites,
++ 2);
++ }
++ if (clen == 7 && os_memcmp(ciphers, "DEFAULT", 7) == 0)
++ continue;
++ if (clen == 6 && os_memcmp(ciphers, "AES128", 6) == 0) {
++ nids = tls_mbedtls_append_ciphersuite(ids, nids, idsz,
++ suite_AES_128_ephemeral,
++ (int)ARRAY_SIZE(suite_AES_128_ephemeral));
++ if (nids == -1)
++ return 0;
++ continue;
++ }
++ if (clen == 6 && os_memcmp(ciphers, "AES256", 6) == 0) {
++ nids = tls_mbedtls_append_ciphersuite(ids, nids, idsz,
++ suite_AES_256_ephemeral,
++ (int)ARRAY_SIZE(suite_AES_256_ephemeral));
++ if (nids == -1)
++ return 0;
++ continue;
++ }
++ if (clen == 4 && os_memcmp(ciphers, "HIGH", 4) == 0) {
++ nids = tls_mbedtls_append_ciphersuite(ids, nids, idsz, suite_HIGH,
++ (int)ARRAY_SIZE(suite_HIGH));
++ if (nids == -1)
++ return 0;
++ continue;
++ }
++ /* ignore anonymous cipher group names (?not supported by mbedtls?) */
++ if (clen == 4 && os_memcmp(ciphers, "!ADH", 4) == 0)
++ continue;
++ if (clen == 6 && os_memcmp(ciphers, "-aECDH", 6) == 0)
++ continue;
++ if (clen == 7 && os_memcmp(ciphers, "-aECDSA", 7) == 0)
++ continue;
++
++ /* attempt to match mbedtls cipher names
++ * nb: does not support openssl group names or list manipulation syntax
++ * (alt: could copy almost 1200 lines (!!!) of lighttpd mod_mbedtls.c
++ * mod_mbedtls_ssl_conf_ciphersuites() to translate strings)
++ * note: not efficient to rewrite list for each ciphers entry,
++ * but this code is expected to run only at startup
++ */
++ const int *list = mbedtls_ssl_list_ciphersuites();
++ for (; *list; ++list) {
++ blen = tls_mbedtls_translate_ciphername(*list,buf,sizeof(buf));
++ if (!blen)
++ continue;
++
++ /* matching heuristics additional to translate_ciphername above */
++ if (blen == clen+4) {
++ char *cbc = os_strstr(buf, "CBC-");
++ if (cbc) {
++ os_memmove(cbc, cbc+4, blen-(cbc+4-buf)+1); /*(w/ '\0')*/
++ blen -= 4;
++ }
++ }
++ if (blen >= clen && os_memcmp(ciphers, buf, clen) == 0
++ && (blen == clen
++ || (blen == clen+7 && os_memcmp(buf+clen, "-SHA256", 7)))) {
++ if (1 >= idsz - (nids + 1)) {
++ emsg(MSG_ERROR,
++ "error: too many ciphers during list expand");
++ return 0;
++ }
++ ids[++nids] = *list;
++ break;
++ }
++ }
++ if (*list == 0) {
++ wpa_printf(MSG_ERROR,
++ "MTLS: unrecognized cipher: %.*s", (int)clen, ciphers);
++ return 0;
++ }
++ } while ((ciphers = next ? next+1 : NULL));
++
++ if (-1 == nids) return 1; /* empty list; no-op */
++
++ ids[++nids] = 0; /* terminate list */
++ ++nids;
++
++ return tls_mbedtls_set_ciphersuites(tls_conf, ids, nids);
++}
++
++
++__attribute_noinline__
++static int tls_mbedtls_set_item(char **config_item, const char *item)
++{
++ os_free(*config_item);
++ *config_item = NULL;
++ return item ? (*config_item = os_strdup(item)) != NULL : 1;
++}
++
++
++static int tls_connection_set_subject_match(struct tls_conf *tls_conf,
++ const struct tls_connection_params *params)
++{
++ int rc = 1;
++ rc &= tls_mbedtls_set_item(&tls_conf->subject_match,
++ params->subject_match);
++ rc &= tls_mbedtls_set_item(&tls_conf->altsubject_match,
++ params->altsubject_match);
++ rc &= tls_mbedtls_set_item(&tls_conf->suffix_match,
++ params->suffix_match);
++ rc &= tls_mbedtls_set_item(&tls_conf->domain_match,
++ params->domain_match);
++ rc &= tls_mbedtls_set_item(&tls_conf->check_cert_subject,
++ params->check_cert_subject);
++ return rc;
++}
++
++
++/* duplicated in crypto_mbedtls.c:crypto_mbedtls_readfile()*/
++__attribute_noinline__
++static int tls_mbedtls_readfile(const char *path, u8 **buf, size_t *n)
++{
++ #if 0 /* #ifdef MBEDTLS_FS_IO */
++ /*(includes +1 for '\0' needed by mbedtls PEM parsing funcs)*/
++ if (mbedtls_pk_load_file(path, (unsigned char **)buf, n) != 0) {
++ wpa_printf(MSG_ERROR, "error: mbedtls_pk_load_file %s", path);
++ return -1;
++ }
++ #else
++ /*(use os_readfile() so that we can use os_free()
++ *(if we use mbedtls_pk_load_file() above, macros prevent calling free()
++ * directly #if defined(OS_REJECT_C_LIB_FUNCTIONS) and calling os_free()
++ * on buf aborts in tests if buf not allocated via os_malloc())*/
++ *buf = (u8 *)os_readfile(path, n);
++ if (!*buf) {
++ wpa_printf(MSG_ERROR, "error: os_readfile %s", path);
++ return -1;
++ }
++ u8 *buf0 = os_realloc(*buf, *n+1);
++ if (!buf0) {
++ bin_clear_free(*buf, *n);
++ *buf = NULL;
++ return -1;
++ }
++ buf0[(*n)++] = '\0';
++ *buf = buf0;
++ #endif
++ return 0;
++}
++
++
++static int tls_mbedtls_set_crl(struct tls_conf *tls_conf, const u8 *data, size_t len)
++{
++ /* do not use mbedtls_x509_crl_parse() on PEM unless it contains CRL */
++ if (len && data[len-1] == '\0'
++ && NULL == os_strstr((const char *)data,"-----BEGIN X509 CRL-----")
++ && tls_mbedtls_data_is_pem(data))
++ return 0;
++
++ mbedtls_x509_crl crl;
++ mbedtls_x509_crl_init(&crl);
++ int rc = mbedtls_x509_crl_parse(&crl, data, len);
++ if (rc < 0) {
++ mbedtls_x509_crl_free(&crl);
++ return rc == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ? 0 : rc;
++ }
++
++ mbedtls_x509_crl *crl_new = os_malloc(sizeof(crl));
++ if (crl_new == NULL) {
++ mbedtls_x509_crl_free(&crl);
++ return MBEDTLS_ERR_X509_ALLOC_FAILED;
++ }
++ os_memcpy(crl_new, &crl, sizeof(crl));
++
++ mbedtls_x509_crl *crl_old = tls_conf->crl;
++ tls_conf->crl = crl_new;
++ if (crl_old) {
++ mbedtls_x509_crl_free(crl_old);
++ os_free(crl_old);
++ }
++ return 0;
++}
++
++
++static int tls_mbedtls_set_ca(struct tls_conf *tls_conf, u8 *data, size_t len)
++{
++ /* load crt struct onto stack and then copy into tls_conf in
++ * order to preserve existing tls_conf value if error occurs
++ *
++ * hostapd is not threaded, or else should allocate memory and swap in
++ * pointer reduce race condition. (If threaded, would also need to
++ * keep reference count of use to avoid freeing while still in use.) */
++
++ mbedtls_x509_crt crt;
++ mbedtls_x509_crt_init(&crt);
++ int rc = mbedtls_x509_crt_parse(&crt, data, len);
++ if (rc < 0) {
++ mbedtls_x509_crt_free(&crt);
++ return rc;
++ }
++
++ mbedtls_x509_crt_free(&tls_conf->ca_cert);
++ os_memcpy(&tls_conf->ca_cert, &crt, sizeof(crt));
++ return 0;
++}
++
++
++static int tls_mbedtls_set_ca_and_crl(struct tls_conf *tls_conf, const char *ca_cert_file)
++{
++ size_t len;
++ u8 *data;
++ if (tls_mbedtls_readfile(ca_cert_file, &data, &len))
++ return -1;
++
++ int rc;
++ if (0 == (rc = tls_mbedtls_set_ca(tls_conf, data, len))
++ && (!tls_mbedtls_data_is_pem(data) /*skip parse for CRL if not PEM*/
++ || 0 == (rc = tls_mbedtls_set_crl(tls_conf, data, len)))) {
++ mbedtls_ssl_conf_ca_chain(&tls_conf->conf,
++ &tls_conf->ca_cert,
++ tls_conf->crl);
++ }
++ else {
++ elog(rc, __func__);
++ emsg(MSG_ERROR, ca_cert_file);
++ }
++
++ forced_memzero(data, len);
++ os_free(data);
++ return rc;
++}
++
++
++static void tls_mbedtls_refresh_crl(void)
++{
++ /* check for CRL refresh
++ * continue even if error occurs; continue with previous cert, CRL */
++ unsigned int crl_reload_interval = tls_ctx_global.crl_reload_interval;
++ const char *ca_cert_file = tls_ctx_global.ca_cert_file;
++ if (!crl_reload_interval || !ca_cert_file)
++ return;
++
++ struct os_reltime *previous = &tls_ctx_global.crl_reload_previous;
++ struct os_reltime now;
++ if (os_get_reltime(&now) != 0
++ || !os_reltime_expired(&now, previous, crl_reload_interval))
++ return;
++
++ /* Note: modifying global state is not thread-safe
++ * if in use by existing connections
++ *
++ * src/utils/os.h does not provide a portable stat()
++ * or else it would be a good idea to check mtime and size,
++ * and avoid reloading if file has not changed */
++
++ if (tls_mbedtls_set_ca_and_crl(tls_ctx_global.tls_conf, ca_cert_file) == 0)
++ *previous = now;
++}
++
++
++static int tls_mbedtls_set_ca_cert(struct tls_conf *tls_conf,
++ const struct tls_connection_params *params)
++{
++ if (params->ca_cert) {
++ if (os_strncmp(params->ca_cert, "probe://", 8) == 0) {
++ tls_conf->ca_cert_probe = 1;
++ tls_conf->has_ca_cert = 1;
++ return 0;
++ }
++
++ if (os_strncmp(params->ca_cert, "hash://", 7) == 0) {
++ const char *pos = params->ca_cert + 7;
++ if (os_strncmp(pos, "server/sha256/", 14) != 0) {
++ emsg(MSG_ERROR, "unsupported ca_cert hash value");
++ return -1;
++ }
++ pos += 14;
++ if (os_strlen(pos) != SHA256_DIGEST_LENGTH*2) {
++ emsg(MSG_ERROR, "unexpected ca_cert hash length");
++ return -1;
++ }
++ if (hexstr2bin(pos, tls_conf->ca_cert_hash,
++ SHA256_DIGEST_LENGTH) < 0) {
++ emsg(MSG_ERROR, "invalid ca_cert hash value");
++ return -1;
++ }
++ emsg(MSG_DEBUG, "checking only server certificate match");
++ tls_conf->verify_depth0_only = 1;
++ tls_conf->has_ca_cert = 1;
++ return 0;
++ }
++
++ if (tls_mbedtls_set_ca_and_crl(tls_conf, params->ca_cert) != 0)
++ return -1;
++ }
++ if (params->ca_cert_blob) {
++ size_t len = params->ca_cert_blob_len;
++ int is_pem = tls_mbedtls_data_is_pem(params->ca_cert_blob);
++ if (len && params->ca_cert_blob[len-1] != '\0' && is_pem)
++ ++len; /*(include '\0' in len for PEM)*/
++ int ret = mbedtls_x509_crt_parse(&tls_conf->ca_cert,
++ params->ca_cert_blob, len);
++ if (ret != 0) {
++ elog(ret, "mbedtls_x509_crt_parse");
++ return -1;
++ }
++ if (is_pem) { /*(ca_cert_blob in DER format contains ca cert only)*/
++ ret = tls_mbedtls_set_crl(tls_conf, params->ca_cert_blob, len);
++ if (ret != 0) {
++ elog(ret, "mbedtls_x509_crl_parse");
++ return -1;
++ }
++ }
++ }
++
++ if (mbedtls_x509_time_is_future(&tls_conf->ca_cert.valid_from)
++ || mbedtls_x509_time_is_past(&tls_conf->ca_cert.valid_to)) {
++ emsg(MSG_WARNING, "ca_cert expired or not yet valid");
++ if (params->ca_cert)
++ emsg(MSG_WARNING, params->ca_cert);
++ }
++
++ tls_conf->has_ca_cert = 1;
++ return 0;
++}
++
++
++static int tls_mbedtls_set_certs(struct tls_conf *tls_conf,
++ const struct tls_connection_params *params)
++{
++ int ret;
++
++ if (params->ca_cert || params->ca_cert_blob) {
++ if (tls_mbedtls_set_ca_cert(tls_conf, params) != 0)
++ return -1;
++ }
++ else if (params->ca_path) {
++ emsg(MSG_INFO, "ca_path support not implemented");
++ return -1;
++ }
++
++ if (!tls_conf->has_ca_cert)
++ mbedtls_ssl_conf_authmode(&tls_conf->conf, MBEDTLS_SSL_VERIFY_NONE);
++ else {
++ /* Initial setting: REQUIRED for client, OPTIONAL for server
++ * (see also tls_connection_set_verify()) */
++ tls_conf->verify_peer = (tls_ctx_global.tls_conf == NULL);
++ int authmode = tls_conf->verify_peer
++ ? MBEDTLS_SSL_VERIFY_REQUIRED
++ : MBEDTLS_SSL_VERIFY_OPTIONAL;
++ mbedtls_ssl_conf_authmode(&tls_conf->conf, authmode);
++ mbedtls_ssl_conf_ca_chain(&tls_conf->conf,
++ &tls_conf->ca_cert,
++ tls_conf->crl);
++
++ if (!tls_connection_set_subject_match(tls_conf, params))
++ return -1;
++ }
++
++ if (params->client_cert2) /*(yes, server_cert2 in msg below)*/
++ emsg(MSG_INFO, "server_cert2 support not implemented");
++
++ if (params->client_cert) {
++ size_t len;
++ u8 *data;
++ if (tls_mbedtls_readfile(params->client_cert, &data, &len))
++ return -1;
++ ret = mbedtls_x509_crt_parse(&tls_conf->client_cert, data, len);
++ forced_memzero(data, len);
++ os_free(data);
++ }
++ if (params->client_cert_blob) {
++ size_t len = params->client_cert_blob_len;
++ if (len && params->client_cert_blob[len-1] != '\0'
++ && tls_mbedtls_data_is_pem(params->client_cert_blob))
++ ++len; /*(include '\0' in len for PEM)*/
++ ret = mbedtls_x509_crt_parse(&tls_conf->client_cert,
++ params->client_cert_blob, len);
++ }
++ if (params->client_cert || params->client_cert_blob) {
++ if (ret < 0) {
++ elog(ret, "mbedtls_x509_crt_parse");
++ if (params->client_cert)
++ emsg(MSG_ERROR, params->client_cert);
++ return -1;
++ }
++ if (mbedtls_x509_time_is_future(&tls_conf->client_cert.valid_from)
++ || mbedtls_x509_time_is_past(&tls_conf->client_cert.valid_to)) {
++ emsg(MSG_WARNING, "cert expired or not yet valid");
++ if (params->client_cert)
++ emsg(MSG_WARNING, params->client_cert);
++ }
++ tls_conf->has_client_cert = 1;
++ }
++
++ if (params->private_key || params->private_key_blob) {
++ size_t len = params->private_key_blob_len;
++ u8 *data;
++ *(const u8 **)&data = params->private_key_blob;
++ if (len && data[len-1] != '\0' && tls_mbedtls_data_is_pem(data))
++ ++len; /*(include '\0' in len for PEM)*/
++ if (params->private_key
++ && tls_mbedtls_readfile(params->private_key, &data, &len)) {
++ return -1;
++ }
++ const char *pwd = params->private_key_passwd;
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ ret = mbedtls_pk_parse_key(&tls_conf->private_key,
++ data, len,
++ (const unsigned char *)pwd,
++ pwd ? os_strlen(pwd) : 0,
++ mbedtls_ctr_drbg_random,
++ tls_ctx_global.ctr_drbg);
++ #else
++ ret = mbedtls_pk_parse_key(&tls_conf->private_key,
++ data, len,
++ (const unsigned char *)pwd,
++ pwd ? os_strlen(pwd) : 0);
++ #endif
++ if (params->private_key) {
++ forced_memzero(data, len);
++ os_free(data);
++ }
++ if (ret < 0) {
++ elog(ret, "mbedtls_pk_parse_key");
++ return -1;
++ }
++ tls_conf->has_private_key = 1;
++ }
++
++ if (tls_conf->has_client_cert && tls_conf->has_private_key) {
++ ret = mbedtls_ssl_conf_own_cert(
++ &tls_conf->conf, &tls_conf->client_cert, &tls_conf->private_key);
++ if (ret < 0) {
++ elog(ret, "mbedtls_ssl_conf_own_cert");
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++
++/* mbedtls_x509_crt_profile_suiteb plus rsa_min_bitlen 2048 */
++/* (reference: see also mbedtls_x509_crt_profile_next) */
++/* ??? should permit SHA-512, too, and additional curves ??? */
++static const mbedtls_x509_crt_profile tls_mbedtls_crt_profile_suiteb128 =
++{
++ /* Only SHA-256 and 384 */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ),
++ /* Only ECDSA */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) |
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ),
++#if defined(MBEDTLS_ECP_C)
++ /* Only NIST P-256 and P-384 */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) |
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ),
++#else
++ 0,
++#endif
++ 2048,
++};
++
++
++/* stricter than mbedtls_x509_crt_profile_suiteb */
++/* (reference: see also mbedtls_x509_crt_profile_next) */
++/* ??? should permit SHA-512, too, and additional curves ??? */
++static const mbedtls_x509_crt_profile tls_mbedtls_crt_profile_suiteb192 =
++{
++ /* Only SHA-384 */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ),
++ /* Only ECDSA */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) |
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ),
++#if defined(MBEDTLS_ECP_C)
++ /* Only NIST P-384 */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ),
++#else
++ 0,
++#endif
++ 3072,
++};
++
++
++/* stricter than mbedtls_x509_crt_profile_suiteb except allow any PK alg */
++/* (reference: see also mbedtls_x509_crt_profile_next) */
++/* ??? should permit SHA-512, too, and additional curves ??? */
++static const mbedtls_x509_crt_profile tls_mbedtls_crt_profile_suiteb192_anypk =
++{
++ /* Only SHA-384 */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ),
++ 0xFFFFFFF, /* Any PK alg */
++#if defined(MBEDTLS_ECP_C)
++ /* Only NIST P-384 */
++ MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ),
++#else
++ 0,
++#endif
++ 3072,
++};
++
++
++static int tls_mbedtls_set_params(struct tls_conf *tls_conf,
++ const struct tls_connection_params *params)
++{
++ tls_conf->flags = params->flags;
++
++ if (tls_conf->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
++ emsg(MSG_INFO, "ocsp=3 not supported");
++ return -1;
++ }
++
++ if (tls_conf->flags & TLS_CONN_REQUIRE_OCSP) {
++ emsg(MSG_INFO, "ocsp not supported");
++ return -1;
++ }
++
++ int suiteb128 = 0;
++ int suiteb192 = 0;
++ if (params->openssl_ciphers) {
++ if (os_strcmp(params->openssl_ciphers, "SUITEB192") == 0) {
++ suiteb192 = 1;
++ tls_conf->flags |= TLS_CONN_SUITEB;
++ }
++ if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
++ suiteb128 = 1;
++ tls_conf->flags |= TLS_CONN_SUITEB;
++ }
++ }
++
++ int ret = mbedtls_ssl_config_defaults(
++ &tls_conf->conf, tls_ctx_global.tls_conf ? MBEDTLS_SSL_IS_SERVER
++ : MBEDTLS_SSL_IS_CLIENT,
++ MBEDTLS_SSL_TRANSPORT_STREAM,
++ (tls_conf->flags & TLS_CONN_SUITEB) ? MBEDTLS_SSL_PRESET_SUITEB
++ : MBEDTLS_SSL_PRESET_DEFAULT);
++ if (ret != 0) {
++ elog(ret, "mbedtls_ssl_config_defaults");
++ return -1;
++ }
++
++ if (suiteb128) {
++ mbedtls_ssl_conf_cert_profile(&tls_conf->conf,
++ &tls_mbedtls_crt_profile_suiteb128);
++ mbedtls_ssl_conf_dhm_min_bitlen(&tls_conf->conf, 2048);
++ }
++ else if (suiteb192) {
++ mbedtls_ssl_conf_cert_profile(&tls_conf->conf,
++ &tls_mbedtls_crt_profile_suiteb192);
++ mbedtls_ssl_conf_dhm_min_bitlen(&tls_conf->conf, 3072);
++ }
++ else if (tls_conf->flags & TLS_CONN_SUITEB) {
++ /* treat as suiteb192 while allowing any PK algorithm */
++ mbedtls_ssl_conf_cert_profile(&tls_conf->conf,
++ &tls_mbedtls_crt_profile_suiteb192_anypk);
++ mbedtls_ssl_conf_dhm_min_bitlen(&tls_conf->conf, 3072);
++ }
++
++ tls_mbedtls_set_allowed_tls_vers(tls_conf, &tls_conf->conf);
++ ret = tls_mbedtls_set_certs(tls_conf, params);
++ if (ret != 0)
++ return -1;
++
++ if (params->dh_file
++ && !tls_mbedtls_set_dhparams(tls_conf, params->dh_file)) {
++ return -1;
++ }
++
++ if (params->openssl_ecdh_curves
++ && !tls_mbedtls_set_curves(tls_conf, params->openssl_ecdh_curves)) {
++ return -1;
++ }
++
++ if (params->openssl_ciphers) {
++ if (!tls_mbedtls_set_ciphers(tls_conf, params->openssl_ciphers))
++ return -1;
++ }
++ else if (tls_conf->flags & TLS_CONN_SUITEB) {
++ /* special-case a select set of ciphers for hwsim tests */
++ if (!tls_mbedtls_set_ciphers(tls_conf,
++ (tls_conf->flags & TLS_CONN_SUITEB_NO_ECDH)
++ ? "DHE-RSA-AES256-GCM-SHA384"
++ : "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384"))
++ return -1;
++ }
++
++ return 0;
++}
++
++
++int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
++ const struct tls_connection_params *params)
++{
++ if (conn == NULL || params == NULL)
++ return -1;
++
++ tls_conf_deinit(conn->tls_conf);
++ struct tls_conf *tls_conf = conn->tls_conf = tls_conf_init(tls_ctx);
++ if (tls_conf == NULL)
++ return -1;
++
++ if (tls_ctx_global.tls_conf) {
++ tls_conf->check_crl = tls_ctx_global.tls_conf->check_crl;
++ tls_conf->check_crl_strict = tls_ctx_global.tls_conf->check_crl_strict;
++ /*(tls_openssl.c inherits check_cert_subject from global conf)*/
++ if (tls_ctx_global.tls_conf->check_cert_subject) {
++ tls_conf->check_cert_subject =
++ os_strdup(tls_ctx_global.tls_conf->check_cert_subject);
++ if (tls_conf->check_cert_subject == NULL)
++ return -1;
++ }
++ }
++
++ if (tls_mbedtls_set_params(tls_conf, params) != 0)
++ return -1;
++ conn->verify_peer = tls_conf->verify_peer;
++
++ return tls_mbedtls_ssl_setup(conn);
++}
++
++
++#ifdef TLS_MBEDTLS_SESSION_TICKETS
++
++static int tls_mbedtls_clienthello_session_ticket_prep (struct tls_connection *conn,
++ const u8 *data, size_t len)
++{
++ if (conn->tls_conf->flags & TLS_CONN_DISABLE_SESSION_TICKET)
++ return -1;
++ if (conn->clienthello_session_ticket)
++ tls_connection_deinit_clienthello_session_ticket(conn);
++ if (len) {
++ conn->clienthello_session_ticket = mbedtls_calloc(1, len);
++ if (conn->clienthello_session_ticket == NULL)
++ return -1;
++ conn->clienthello_session_ticket_len = len;
++ os_memcpy(conn->clienthello_session_ticket, data, len);
++ }
++ return 0;
++}
++
++
++static void tls_mbedtls_clienthello_session_ticket_set (struct tls_connection *conn)
++{
++ mbedtls_ssl_session *sess = conn->ssl.MBEDTLS_PRIVATE(session_negotiate);
++ if (sess->MBEDTLS_PRIVATE(ticket)) {
++ mbedtls_platform_zeroize(sess->MBEDTLS_PRIVATE(ticket),
++ sess->MBEDTLS_PRIVATE(ticket_len));
++ mbedtls_free(sess->MBEDTLS_PRIVATE(ticket));
++ }
++ sess->MBEDTLS_PRIVATE(ticket) = conn->clienthello_session_ticket;
++ sess->MBEDTLS_PRIVATE(ticket_len) = conn->clienthello_session_ticket_len;
++ sess->MBEDTLS_PRIVATE(ticket_lifetime) = 86400;/* XXX: can hint be 0? */
++
++ conn->clienthello_session_ticket = NULL;
++ conn->clienthello_session_ticket_len = 0;
++}
++
++
++static int tls_mbedtls_ssl_ticket_write(void *p_ticket,
++ const mbedtls_ssl_session *session,
++ unsigned char *start,
++ const unsigned char *end,
++ size_t *tlen,
++ uint32_t *lifetime)
++{
++ struct tls_connection *conn = p_ticket;
++ if (conn && conn->session_ticket_cb) {
++ /* see tls_mbedtls_clienthello_session_ticket_prep() */
++ /* see tls_mbedtls_clienthello_session_ticket_set() */
++ return 0;
++ }
++
++ return mbedtls_ssl_ticket_write(&tls_ctx_global.ticket_ctx,
++ session, start, end, tlen, lifetime);
++}
++
++
++static int tls_mbedtls_ssl_ticket_parse(void *p_ticket,
++ mbedtls_ssl_session *session,
++ unsigned char *buf,
++ size_t len)
++{
++ /* XXX: TODO: not implemented in client;
++ * mbedtls_ssl_conf_session_tickets_cb() callbacks only for TLS server*/
++
++ if (len == 0)
++ return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
++
++ struct tls_connection *conn = p_ticket;
++ if (conn && conn->session_ticket_cb) {
++ /* XXX: have random and secret been initialized yet?
++ * or must keys first be exported?
++ * EAP-FAST uses all args, EAP-TEAP only uses secret */
++ struct tls_random data;
++ if (tls_connection_get_random(NULL, conn, &data) != 0)
++ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
++ int ret =
++ conn->session_ticket_cb(conn->session_ticket_cb_ctx,
++ buf, len,
++ data.client_random,
++ data.server_random,
++ conn->expkey_secret);
++ if (ret == 1) {
++ conn->resumed = 1;
++ return 0;
++ }
++ emsg(MSG_ERROR, "EAP session ticket ext not implemented");
++ return MBEDTLS_ERR_SSL_INVALID_MAC;
++ /*(non-zero return used for mbedtls debug logging)*/
++ }
++
++ /* XXX: TODO always use tls_mbedtls_ssl_ticket_parse() for callback? */
++ int rc = mbedtls_ssl_ticket_parse(&tls_ctx_global.ticket_ctx,
++ session, buf, len);
++ if (conn)
++ conn->resumed = (rc == 0);
++ return rc;
++}
++
++#endif /* TLS_MBEDTLS_SESSION_TICKETS */
++
++
++__attribute_cold__
++int tls_global_set_params(void *tls_ctx,
++ const struct tls_connection_params *params)
++{
++ /* XXX: why might global_set_params be called more than once? */
++ if (tls_ctx_global.tls_conf)
++ tls_conf_deinit(tls_ctx_global.tls_conf);
++ tls_ctx_global.tls_conf = tls_conf_init(tls_ctx);
++ if (tls_ctx_global.tls_conf == NULL)
++ return -1;
++
++ #ifdef MBEDTLS_SSL_SESSION_TICKETS
++ #ifdef MBEDTLS_SSL_TICKET_C
++ if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
++ #ifdef TLS_MBEDTLS_SESSION_TICKETS
++ mbedtls_ssl_conf_session_tickets_cb(&tls_ctx_global.tls_conf->conf,
++ tls_mbedtls_ssl_ticket_write,
++ tls_mbedtls_ssl_ticket_parse,
++ NULL);
++ #else
++ mbedtls_ssl_conf_session_tickets_cb(&tls_ctx_global.tls_conf->conf,
++ mbedtls_ssl_ticket_write,
++ mbedtls_ssl_ticket_parse,
++ &tls_ctx_global.ticket_ctx);
++ #endif
++ #endif
++ #endif
++
++ os_free(tls_ctx_global.ocsp_stapling_response);
++ tls_ctx_global.ocsp_stapling_response = NULL;
++ if (params->ocsp_stapling_response)
++ tls_ctx_global.ocsp_stapling_response =
++ os_strdup(params->ocsp_stapling_response);
++
++ os_free(tls_ctx_global.ca_cert_file);
++ tls_ctx_global.ca_cert_file = NULL;
++ if (params->ca_cert)
++ tls_ctx_global.ca_cert_file = os_strdup(params->ca_cert);
++ return tls_mbedtls_set_params(tls_ctx_global.tls_conf, params);
++}
++
++
++int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
++{
++ tls_ctx_global.tls_conf->check_crl = check_crl;
++ tls_ctx_global.tls_conf->check_crl_strict = strict; /*(time checks)*/
++ return 0;
++}
++
++
++int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
++ int verify_peer, unsigned int flags,
++ const u8 *session_ctx, size_t session_ctx_len)
++{
++ /*(EAP server-side calls this from eap_server_tls_ssl_init())*/
++ if (conn == NULL)
++ return -1;
++
++ conn->tls_conf->flags |= flags;/* TODO: reprocess flags, if necessary */
++
++ int authmode;
++ switch (verify_peer) {
++ case 2: authmode = MBEDTLS_SSL_VERIFY_OPTIONAL; break;/*(eap_teap_init())*/
++ case 1: authmode = MBEDTLS_SSL_VERIFY_REQUIRED; break;
++ default: authmode = MBEDTLS_SSL_VERIFY_NONE; break;
++ }
++ mbedtls_ssl_set_hs_authmode(&conn->ssl, authmode);
++
++ if ((conn->verify_peer = (authmode != MBEDTLS_SSL_VERIFY_NONE)))
++ mbedtls_ssl_set_verify(&conn->ssl, tls_mbedtls_verify_cb, conn);
++ else
++ mbedtls_ssl_set_verify(&conn->ssl, NULL, NULL);
++
++ return 0;
++}
++
++
++#if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++static void tls_connection_export_keys_cb(
++ void *p_expkey, mbedtls_ssl_key_export_type secret_type,
++ const unsigned char *secret, size_t secret_len,
++ const unsigned char client_random[MBEDTLS_EXPKEY_RAND_LEN],
++ const unsigned char server_random[MBEDTLS_EXPKEY_RAND_LEN],
++ mbedtls_tls_prf_types tls_prf_type)
++{
++ struct tls_connection *conn = p_expkey;
++ conn->tls_prf_type = tls_prf_type;
++ if (!tls_prf_type)
++ return;
++ if (secret_len > sizeof(conn->expkey_secret)) {
++ emsg(MSG_ERROR, "tls_connection_export_keys_cb secret too long");
++ conn->tls_prf_type = MBEDTLS_SSL_TLS_PRF_NONE; /* 0 */
++ return;
++ }
++ conn->expkey_secret_len = secret_len;
++ os_memcpy(conn->expkey_secret, secret, secret_len);
++ os_memcpy(conn->expkey_randbytes,
++ client_random, MBEDTLS_EXPKEY_RAND_LEN);
++ os_memcpy(conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN,
++ server_random, MBEDTLS_EXPKEY_RAND_LEN);
++}
++#elif MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++static int tls_connection_export_keys_cb(
++ void *p_expkey,
++ const unsigned char *ms,
++ const unsigned char *kb,
++ size_t maclen,
++ size_t keylen,
++ size_t ivlen,
++ const unsigned char client_random[MBEDTLS_EXPKEY_RAND_LEN],
++ const unsigned char server_random[MBEDTLS_EXPKEY_RAND_LEN],
++ mbedtls_tls_prf_types tls_prf_type )
++{
++ struct tls_connection *conn = p_expkey;
++ conn->tls_prf_type = tls_prf_type;
++ if (!tls_prf_type)
++ return -1; /*(return value ignored by mbedtls)*/
++ conn->expkey_keyblock_size = maclen + keylen + ivlen;
++ conn->expkey_secret_len = MBEDTLS_EXPKEY_FIXED_SECRET_LEN;
++ os_memcpy(conn->expkey_secret, ms, MBEDTLS_EXPKEY_FIXED_SECRET_LEN);
++ os_memcpy(conn->expkey_randbytes,
++ client_random, MBEDTLS_EXPKEY_RAND_LEN);
++ os_memcpy(conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN,
++ server_random, MBEDTLS_EXPKEY_RAND_LEN);
++ return 0;
++}
++#endif
++
++
++int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
++ struct tls_random *data)
++{
++ if (!conn || !conn->tls_prf_type)
++ return -1;
++ data->client_random = conn->expkey_randbytes;
++ data->client_random_len = MBEDTLS_EXPKEY_RAND_LEN;
++ data->server_random = conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN;
++ data->server_random_len = MBEDTLS_EXPKEY_RAND_LEN;
++ return 0;
++}
++
++
++int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
++ const char *label, const u8 *context,
++ size_t context_len, u8 *out, size_t out_len)
++{
++ /* (EAP-PEAP EAP-TLS EAP-TTLS) */
++ #if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++ return (conn && conn->established && conn->tls_prf_type)
++ ? mbedtls_ssl_tls_prf(conn->tls_prf_type,
++ conn->expkey_secret, conn->expkey_secret_len, label,
++ conn->expkey_randbytes,
++ sizeof(conn->expkey_randbytes), out, out_len)
++ : -1;
++ #else
++ /* not implemented here for mbedtls < 2.18.0 */
++ return -1;
++ #endif
++}
++
++
++#ifdef TLS_MBEDTLS_EAP_FAST
++
++#if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++/* keyblock size info is not exposed in mbed TLS 3.0.0 */
++/* extracted from mbedtls library/ssl_tls.c:ssl_tls12_populate_transform() */
++#include <mbedtls/ssl_ciphersuites.h>
++#include <mbedtls/cipher.h>
++static size_t tls_mbedtls_ssl_keyblock_size (mbedtls_ssl_context *ssl)
++{
++ #if !defined(MBEDTLS_USE_PSA_CRYPTO) /* XXX: (not extracted for PSA crypto) */
++ #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
++ if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3)
++ return 0; /* (calculation not extracted) */
++ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
++
++ int ciphersuite = mbedtls_ssl_get_ciphersuite_id_from_ssl(ssl);
++ const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
++ mbedtls_ssl_ciphersuite_from_id(ciphersuite);
++ if (ciphersuite_info == NULL)
++ return 0;
++
++ const mbedtls_cipher_info_t *cipher_info =
++ mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher));
++ if (cipher_info == NULL)
++ return 0;
++
++ #if MBEDTLS_VERSION_NUMBER >= 0x03010000 /* mbedtls 3.1.0 */
++ size_t keylen = mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
++ mbedtls_cipher_mode_t mode = mbedtls_cipher_info_get_mode(cipher_info);
++ #else
++ size_t keylen = cipher_info->MBEDTLS_PRIVATE(key_bitlen) / 8;
++ mbedtls_cipher_mode_t mode = cipher_info->MBEDTLS_PRIVATE(mode);
++ #endif
++ #if defined(MBEDTLS_GCM_C) || \
++ defined(MBEDTLS_CCM_C) || \
++ defined(MBEDTLS_CHACHAPOLY_C)
++ if (mode == MBEDTLS_MODE_GCM || mode == MBEDTLS_MODE_CCM)
++ return keylen + 4;
++ else if (mode == MBEDTLS_MODE_CHACHAPOLY)
++ return keylen + 12;
++ else
++ #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */
++ #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
++ {
++ const mbedtls_md_info_t *md_info =
++ mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac));
++ if (md_info == NULL)
++ return 0;
++ size_t mac_key_len = mbedtls_md_get_size(md_info);
++ size_t ivlen = mbedtls_cipher_info_get_iv_size(cipher_info);
++ return keylen + mac_key_len + ivlen;
++ }
++ #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
++ #endif /* !MBEDTLS_USE_PSA_CRYPTO *//* (not extracted for PSA crypto) */
++ return 0;
++}
++#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 *//* mbedtls 3.0.0 */
++
++
++int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
++ u8 *out, size_t out_len)
++{
++ /* XXX: has export keys callback been run? */
++ if (!conn || !conn->tls_prf_type)
++ return -1;
++
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ conn->expkey_keyblock_size = tls_mbedtls_ssl_keyblock_size(&conn->ssl);
++ if (conn->expkey_keyblock_size == 0)
++ return -1;
++ #endif
++ size_t skip = conn->expkey_keyblock_size * 2;
++ unsigned char *tmp_out = os_malloc(skip + out_len);
++ if (!tmp_out)
++ return -1;
++
++ /* server_random and then client_random */
++ unsigned char seed[MBEDTLS_EXPKEY_RAND_LEN*2];
++ os_memcpy(seed, conn->expkey_randbytes + MBEDTLS_EXPKEY_RAND_LEN,
++ MBEDTLS_EXPKEY_RAND_LEN);
++ os_memcpy(seed + MBEDTLS_EXPKEY_RAND_LEN, conn->expkey_randbytes,
++ MBEDTLS_EXPKEY_RAND_LEN);
++
++ #if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++ int ret = mbedtls_ssl_tls_prf(conn->tls_prf_type,
++ conn->expkey_secret, conn->expkey_secret_len,
++ "key expansion", seed, sizeof(seed),
++ tmp_out, skip + out_len);
++ if (ret == 0)
++ os_memcpy(out, tmp_out + skip, out_len);
++ #else
++ int ret = -1; /*(not reached if not impl; return -1 at top of func)*/
++ #endif
++
++ bin_clear_free(tmp_out, skip + out_len);
++ forced_memzero(seed, sizeof(seed));
++ return ret;
++}
++
++#endif /* TLS_MBEDTLS_EAP_FAST */
++
++
++__attribute_cold__
++static void tls_mbedtls_suiteb_handshake_alert (struct tls_connection *conn)
++{
++ /* tests/hwsim/test_suite_b.py test_suite_b_192_rsa_insufficient_dh */
++ if (!(conn->tls_conf->flags & TLS_CONN_SUITEB))
++ return;
++ if (tls_ctx_global.tls_conf) /*(is server; want issue event on client)*/
++ return;
++ #if 0
++ /*(info not available on client;
++ * mbed TLS library enforces dhm min bitlen in ServerKeyExchange)*/
++ if (MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ==
++ #if MBEDTLS_VERSION_NUMBER < 0x03020000 /* mbedtls 3.2.0 */
++ mbedtls_ssl_get_ciphersuite_id_from_ssl(&conn->ssl)
++ #else
++ mbedtls_ssl_get_ciphersuite_id(
++ mbedtls_ssl_get_ciphersuite(&conn->ssl))
++ #endif
++ && mbedtls_mpi_size(&conn->tls_conf->conf.MBEDTLS_PRIVATE(dhm_P))
++ < 384 /*(3072/8)*/)
++ #endif
++ {
++ struct tls_config *init_conf = &tls_ctx_global.init_conf;
++ if (init_conf->event_cb) {
++ union tls_event_data ev;
++ os_memset(&ev, 0, sizeof(ev));
++ ev.alert.is_local = 1;
++ ev.alert.type = "fatal";
++ /*"internal error" string for tests/hwsim/test_suiteb.py */
++ ev.alert.description = "internal error: handshake failure";
++ /*ev.alert.description = "insufficient security";*/
++ init_conf->event_cb(init_conf->cb_ctx, TLS_ALERT, &ev);
++ }
++ }
++}
++
++
++struct wpabuf * tls_connection_handshake(void *tls_ctx,
++ struct tls_connection *conn,
++ const struct wpabuf *in_data,
++ struct wpabuf **appl_data)
++{
++ if (appl_data)
++ *appl_data = NULL;
++
++ if (in_data && wpabuf_len(in_data)) {
++ /*(unsure why tls_gnutls.c discards buffer contents; skip here)*/
++ if (conn->pull_buf && 0) /* disable; appears unwise */
++ tls_pull_buf_discard(conn, __func__);
++ if (!tls_pull_buf_append(conn, in_data))
++ return NULL;
++ }
++
++ if (conn->tls_conf == NULL) {
++ struct tls_connection_params params;
++ os_memset(&params, 0, sizeof(params));
++ params.openssl_ciphers =
++ tls_ctx_global.init_conf.openssl_ciphers;
++ params.flags = tls_ctx_global.tls_conf->flags;
++ if (tls_connection_set_params(tls_ctx, conn, &params) != 0)
++ return NULL;
++ }
++
++ if (conn->verify_peer) /*(call here might be redundant; nbd)*/
++ mbedtls_ssl_set_verify(&conn->ssl, tls_mbedtls_verify_cb, conn);
++
++ #ifdef TLS_MBEDTLS_SESSION_TICKETS
++ if (conn->clienthello_session_ticket)
++ /*(starting handshake for EAP-FAST and EAP-TEAP)*/
++ tls_mbedtls_clienthello_session_ticket_set(conn);
++
++ /* (not thread-safe due to need to set userdata 'conn' for callback) */
++ /* (unable to use mbedtls_ssl_set_user_data_p() with mbedtls 3.2.0+
++ * since ticket write and parse callbacks take (mbedtls_ssl_session *)
++ * param instead of (mbedtls_ssl_context *) param) */
++ if (conn->tls_conf->flags & TLS_CONN_DISABLE_SESSION_TICKET)
++ mbedtls_ssl_conf_session_tickets_cb(&conn->tls_conf->conf,
++ NULL, NULL, NULL);
++ else
++ mbedtls_ssl_conf_session_tickets_cb(&conn->tls_conf->conf,
++ tls_mbedtls_ssl_ticket_write,
++ tls_mbedtls_ssl_ticket_parse,
++ conn);
++ #endif
++
++ #if MBEDTLS_VERSION_NUMBER >= 0x03020000 /* mbedtls 3.2.0 */
++ int ret = mbedtls_ssl_handshake(&conn->ssl);
++ #else
++ int ret = 0;
++ while (conn->ssl.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
++ ret = mbedtls_ssl_handshake_step(&conn->ssl);
++ if (ret != 0)
++ break;
++ }
++ #endif
++
++ #ifdef TLS_MBEDTLS_SESSION_TICKETS
++ mbedtls_ssl_conf_session_tickets_cb(&conn->tls_conf->conf,
++ tls_mbedtls_ssl_ticket_write,
++ tls_mbedtls_ssl_ticket_parse,
++ NULL);
++ #endif
++
++ switch (ret) {
++ case 0:
++ conn->established = 1;
++ if (conn->push_buf == NULL)
++ /* Need to return something to get final TLS ACK. */
++ conn->push_buf = wpabuf_alloc(0);
++
++ if (appl_data /*&& conn->pull_buf && wpabuf_len(conn->pull_buf)*/)
++ *appl_data = NULL; /* RFE: check for application data */
++ break;
++ case MBEDTLS_ERR_SSL_WANT_WRITE:
++ case MBEDTLS_ERR_SSL_WANT_READ:
++ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
++ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
++ if (tls_ctx_global.tls_conf /*(is server)*/
++ && conn->established && conn->push_buf == NULL)
++ /* Need to return something to trigger completion of EAP-TLS. */
++ conn->push_buf = wpabuf_alloc(0);
++ break;
++ default:
++ ++conn->failed;
++ switch (ret) {
++ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
++ case MBEDTLS_ERR_NET_CONN_RESET:
++ case MBEDTLS_ERR_NET_SEND_FAILED:
++ ++conn->write_alerts;
++ break;
++ #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.0.0 */
++ case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:
++ #else
++ case MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE:
++ #endif
++ tls_mbedtls_suiteb_handshake_alert(conn);
++ /* fall through */
++ case MBEDTLS_ERR_NET_RECV_FAILED:
++ case MBEDTLS_ERR_SSL_CONN_EOF:
++ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
++ case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
++ ++conn->read_alerts;
++ break;
++ default:
++ break;
++ }
++
++ ilog(ret, "mbedtls_ssl_handshake");
++ break;
++ }
++
++ struct wpabuf *out_data = conn->push_buf;
++ conn->push_buf = NULL;
++ return out_data;
++}
++
++
++struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
++ struct tls_connection *conn,
++ const struct wpabuf *in_data,
++ struct wpabuf **appl_data)
++{
++ conn->is_server = 1;
++ return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
++}
++
++
++struct wpabuf * tls_connection_encrypt(void *tls_ctx,
++ struct tls_connection *conn,
++ const struct wpabuf *in_data)
++{
++ int res = mbedtls_ssl_write(&conn->ssl,
++ wpabuf_head_u8(in_data), wpabuf_len(in_data));
++ if (res < 0) {
++ elog(res, "mbedtls_ssl_write");
++ return NULL;
++ }
++
++ struct wpabuf *buf = conn->push_buf;
++ conn->push_buf = NULL;
++ return buf;
++}
++
++
++struct wpabuf * tls_connection_decrypt(void *tls_ctx,
++ struct tls_connection *conn,
++ const struct wpabuf *in_data)
++{
++ int res;
++ struct wpabuf *out;
++
++ /*assert(in_data != NULL);*/
++ if (!tls_pull_buf_append(conn, in_data))
++ return NULL;
++
++ #if defined(MBEDTLS_ZLIB_SUPPORT) /* removed in mbedtls 3.x */
++ /* Add extra buffer space to handle the possibility of decrypted
++ * data being longer than input data due to TLS compression. */
++ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
++ #else /* TLS compression is disabled in mbedtls 3.x */
++ out = wpabuf_alloc(wpabuf_len(in_data));
++ #endif
++ if (out == NULL)
++ return NULL;
++
++ res = mbedtls_ssl_read(&conn->ssl, wpabuf_mhead(out), wpabuf_size(out));
++ if (res < 0) {
++ #if 1 /*(seems like a different error if wpabuf_len(in_data) == 0)*/
++ if (res == MBEDTLS_ERR_SSL_WANT_READ)
++ return out;
++ #endif
++ elog(res, "mbedtls_ssl_read");
++ wpabuf_free(out);
++ return NULL;
++ }
++ wpabuf_put(out, res);
++
++ return out;
++}
++
++
++int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
++{
++ /* XXX: might need to detect if session resumed from TLS session ticket
++ * even if not special session ticket handling for EAP-FAST, EAP-TEAP */
++ /* (?ssl->handshake->resume during session ticket validation?) */
++ return conn && conn->resumed;
++}
++
++
++#ifdef TLS_MBEDTLS_EAP_FAST
++int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
++ u8 *ciphers)
++{
++ /* ciphers is list of TLS_CIPHER_* from hostap/src/crypto/tls.h */
++ int ids[7];
++ const int idsz = (int)sizeof(ids);
++ int nids = -1, id;
++ for ( ; *ciphers != TLS_CIPHER_NONE; ++ciphers) {
++ switch (*ciphers) {
++ case TLS_CIPHER_RC4_SHA:
++ #ifdef MBEDTLS_TLS_RSA_WITH_RC4_128_SHA
++ id = MBEDTLS_TLS_RSA_WITH_RC4_128_SHA;
++ break;
++ #else
++ continue; /*(not supported in mbedtls 3.x; ignore)*/
++ #endif
++ case TLS_CIPHER_AES128_SHA:
++ id = MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA;
++ break;
++ case TLS_CIPHER_RSA_DHE_AES128_SHA:
++ id = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
++ break;
++ case TLS_CIPHER_ANON_DH_AES128_SHA:
++ continue; /*(not supported in mbedtls; ignore)*/
++ case TLS_CIPHER_RSA_DHE_AES256_SHA:
++ id = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
++ break;
++ case TLS_CIPHER_AES256_SHA:
++ id = MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA;
++ break;
++ default:
++ return -1; /* should not happen */
++ }
++ if (++nids == idsz)
++ return -1; /* should not happen */
++ ids[nids] = id;
++ }
++ if (nids < 0)
++ return 0; /* nothing to do */
++ if (++nids == idsz)
++ return -1; /* should not happen */
++ ids[nids] = 0; /* terminate list */
++ ++nids;
++
++ return tls_mbedtls_set_ciphersuites(conn->tls_conf, ids, nids) ? 0 : -1;
++}
++#endif
++
++
++int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
++ char *buf, size_t buflen)
++{
++ if (conn == NULL)
++ return -1;
++ os_strlcpy(buf, mbedtls_ssl_get_version(&conn->ssl), buflen);
++ return buf[0] != 'u' ? 0 : -1; /*(-1 if "unknown")*/
++}
++
++
++#ifdef TLS_MBEDTLS_EAP_TEAP
++u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
++{
++ if (conn == NULL)
++ return 0;
++ return (u16)mbedtls_ssl_get_ciphersuite_id_from_ssl(&conn->ssl);
++}
++#endif
++
++
++int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
++ char *buf, size_t buflen)
++{
++ if (conn == NULL)
++ return -1;
++ const int id = mbedtls_ssl_get_ciphersuite_id_from_ssl(&conn->ssl);
++ return tls_mbedtls_translate_ciphername(id, buf, buflen) ? 0 : -1;
++}
++
++
++#ifdef TLS_MBEDTLS_SESSION_TICKETS
++
++int tls_connection_enable_workaround(void *tls_ctx,
++ struct tls_connection *conn)
++{
++ /* (see comment in src/eap_peer/eap_fast.c:eap_fast_init()) */
++ /* XXX: is there a relevant setting for this in mbed TLS? */
++ /* (do we even care that much about older CBC ciphers?) */
++ return 0;
++}
++
++
++int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
++ int ext_type, const u8 *data,
++ size_t data_len)
++{
++ /* (EAP-FAST and EAP-TEAP) */
++ if (ext_type == MBEDTLS_TLS_EXT_SESSION_TICKET) /*(ext_type == 35)*/
++ return tls_mbedtls_clienthello_session_ticket_prep(conn, data,
++ data_len);
++
++ return -1;
++}
++
++#endif /* TLS_MBEDTLS_SESSION_TICKETS */
++
++
++int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
++{
++ return conn ? conn->failed : -1;
++}
++
++
++int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
++{
++ return conn ? conn->read_alerts : -1;
++}
++
++
++int tls_connection_get_write_alerts(void *tls_ctx,
++ struct tls_connection *conn)
++{
++ return conn ? conn->write_alerts : -1;
++}
++
++
++#ifdef TLS_MBEDTLS_SESSION_TICKETS
++int tls_connection_set_session_ticket_cb(
++ void *tls_ctx, struct tls_connection *conn,
++ tls_session_ticket_cb cb, void *ctx)
++{
++ if (!(conn->tls_conf->flags & TLS_CONN_DISABLE_SESSION_TICKET)) {
++ /* (EAP-FAST and EAP-TEAP) */
++ conn->session_ticket_cb = cb;
++ conn->session_ticket_cb_ctx = ctx;
++ return 0;
++ }
++ return -1;
++}
++#endif
++
++
++int tls_get_library_version(char *buf, size_t buf_len)
++{
++ #ifndef MBEDTLS_VERSION_C
++ const char * const ver = "n/a";
++ #else
++ char ver[9];
++ mbedtls_version_get_string(ver);
++ #endif
++ return os_snprintf(buf, buf_len,
++ "mbed TLS build=" MBEDTLS_VERSION_STRING " run=%s", ver);
++}
++
++
++void tls_connection_set_success_data(struct tls_connection *conn,
++ struct wpabuf *data)
++{
++ wpabuf_free(conn->success_data);
++ conn->success_data = data;
++}
++
++
++void tls_connection_set_success_data_resumed(struct tls_connection *conn)
++{
++}
++
++
++const struct wpabuf *
++tls_connection_get_success_data(struct tls_connection *conn)
++{
++ return conn->success_data;
++}
++
++
++void tls_connection_remove_session(struct tls_connection *conn)
++{
++}
++
++
++#ifdef TLS_MBEDTLS_EAP_TEAP
++int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
++{
++ #if defined(MBEDTLS_SSL_RENEGOTIATION) /* XXX: renegotiation or resumption? */
++ /* data from TLS handshake Finished message */
++ size_t verify_len = conn->ssl.MBEDTLS_PRIVATE(verify_data_len);
++ char *verify_data = (conn->is_server ^ conn->resumed)
++ ? conn->ssl.MBEDTLS_PRIVATE(peer_verify_data)
++ : conn->ssl.MBEDTLS_PRIVATE(own_verify_data);
++ if (verify_len && verify_len <= max_len) {
++ os_memcpy(buf, verify_data, verify_len);
++ return (int)verify_len;
++ }
++ #endif
++ return -1;
++}
++#endif
++
++
++__attribute_noinline__
++static void tls_mbedtls_set_peer_subject(struct tls_connection *conn, const mbedtls_x509_crt *crt)
++{
++ if (conn->peer_subject)
++ return;
++ char buf[MBEDTLS_X509_MAX_DN_NAME_SIZE*2];
++ int buflen = mbedtls_x509_dn_gets(buf, sizeof(buf), &crt->subject);
++ if (buflen >= 0 && (conn->peer_subject = os_malloc((size_t)buflen+1)))
++ os_memcpy(conn->peer_subject, buf, (size_t)buflen+1);
++}
++
++
++#ifdef TLS_MBEDTLS_EAP_TEAP
++const char * tls_connection_get_peer_subject(struct tls_connection *conn)
++{
++ if (!conn)
++ return NULL;
++ if (!conn->peer_subject) { /*(if not set during cert verify)*/
++ const mbedtls_x509_crt *peer_cert =
++ mbedtls_ssl_get_peer_cert(&conn->ssl);
++ if (peer_cert)
++ tls_mbedtls_set_peer_subject(conn, peer_cert);
++ }
++ return conn->peer_subject;
++}
++#endif
++
++
++#ifdef TLS_MBEDTLS_EAP_TEAP
++bool tls_connection_get_own_cert_used(struct tls_connection *conn)
++{
++ /* XXX: availability of cert does not necessary mean that client
++ * received certificate request from server and then sent cert.
++ * ? step handshake in tls_connection_handshake() looking for
++ * MBEDTLS_SSL_CERTIFICATE_REQUEST ? */
++ const struct tls_conf * const tls_conf = conn->tls_conf;
++ return (tls_conf->has_client_cert && tls_conf->has_private_key);
++}
++#endif
++
++
++#if defined(CONFIG_FIPS)
++#define TLS_MBEDTLS_CONFIG_FIPS
++#endif
++
++#if defined(CONFIG_SHA256)
++#define TLS_MBEDTLS_TLS_PRF_SHA256
++#endif
++
++#if defined(CONFIG_SHA384)
++#define TLS_MBEDTLS_TLS_PRF_SHA384
++#endif
++
++
++#ifndef TLS_MBEDTLS_CONFIG_FIPS
++#if defined(CONFIG_MODULE_TESTS)
++/* unused with CONFIG_TLS=mbedtls except in crypto_module_tests.c */
++#if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */ \
++ && MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.0.0 */
++/* sha1-tlsprf.c */
++#include "sha1.h"
++int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
++ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
++{
++ return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_TLS1,
++ secret, secret_len, label,
++ seed, seed_len, out, outlen) ? -1 : 0;
++}
++#else
++#include "sha1-tlsprf.c" /* pull in hostap local implementation */
++#endif
++#endif
++#endif
++
++#ifdef TLS_MBEDTLS_TLS_PRF_SHA256
++/* sha256-tlsprf.c */
++#if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++#include "sha256.h"
++int tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
++ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
++{
++ return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_SHA256,
++ secret, secret_len, label,
++ seed, seed_len, out, outlen) ? -1 : 0;
++}
++#else
++#include "sha256-tlsprf.c" /* pull in hostap local implementation */
++#endif
++#endif
++
++#ifdef TLS_MBEDTLS_TLS_PRF_SHA384
++/* sha384-tlsprf.c */
++#if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
++#include "sha384.h"
++int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
++ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
++{
++ return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_SHA384,
++ secret, secret_len, label,
++ seed, seed_len, out, outlen) ? -1 : 0;
++}
++#else
++#include "sha384-tlsprf.c" /* pull in hostap local implementation */
++#endif
++#endif
++
++
++#if MBEDTLS_VERSION_NUMBER < 0x03020000 /* mbedtls 3.2.0 */
++#define mbedtls_x509_crt_has_ext_type(crt, ext_type) \
++ ((crt)->MBEDTLS_PRIVATE(ext_types) & (ext_type))
++#endif
++
++struct mlist { const char *p; size_t n; };
++
++
++static int
++tls_mbedtls_match_altsubject(mbedtls_x509_crt *crt, const char *match)
++{
++ /* RFE: this could be pre-parsed into structured data at config time */
++ struct mlist list[256]; /*(much larger than expected)*/
++ int nlist = 0;
++ if ( os_strncmp(match, "EMAIL:", 6) != 0
++ && os_strncmp(match, "DNS:", 4) != 0
++ && os_strncmp(match, "URI:", 4) != 0 ) {
++ wpa_printf(MSG_INFO, "MTLS: Invalid altSubjectName match '%s'", match);
++ return 0;
++ }
++ for (const char *s = match, *tok; *s; s = tok ? tok+1 : "") {
++ do { } while ((tok = os_strchr(s, ';'))
++ && os_strncmp(tok+1, "EMAIL:", 6) != 0
++ && os_strncmp(tok+1, "DNS:", 4) != 0
++ && os_strncmp(tok+1, "URI:", 4) != 0);
++ list[nlist].p = s;
++ list[nlist].n = tok ? (size_t)(tok - s) : os_strlen(s);
++ if (list[nlist].n && ++nlist == sizeof(list)/sizeof(*list)) {
++ wpa_printf(MSG_INFO, "MTLS: excessive altSubjectName match '%s'",
++ match);
++ break; /* truncate huge list and continue */
++ }
++ }
++
++ if (!mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME))
++ return 0;
++
++ const mbedtls_x509_sequence *cur = &crt->subject_alt_names;
++ for (; cur != NULL; cur = cur->next) {
++ const unsigned char san_type = (unsigned char)cur->buf.tag
++ & MBEDTLS_ASN1_TAG_VALUE_MASK;
++ char t;
++ size_t step = 4;
++ switch (san_type) { /* "EMAIL:" or "DNS:" or "URI:" */
++ case MBEDTLS_X509_SAN_RFC822_NAME: step = 6; t = 'E'; break;
++ case MBEDTLS_X509_SAN_DNS_NAME: t = 'D'; break;
++ case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER: t = 'U'; break;
++ default: continue;
++ }
++
++ for (int i = 0; i < nlist; ++i) {
++ /* step over "EMAIL:" or "DNS:" or "URI:" in list[i].p */
++ /* Note: v is not '\0'-terminated, but is a known length vlen,
++ * so okay to pass to os_strncasecmp() even though not z-string */
++ if (cur->buf.len == list[i].n - step && t == *list[i].p
++ && 0 == os_strncasecmp((char *)cur->buf.p,
++ list[i].p+step, cur->buf.len)) {
++ return 1; /* match */
++ }
++ }
++ }
++ return 0; /* no match */
++}
++
++
++static int
++tls_mbedtls_match_suffix(const char *v, size_t vlen,
++ const struct mlist *list, int nlist, int full)
++{
++ /* Note: v is not '\0'-terminated, but is a known length vlen,
++ * so okay to pass to os_strncasecmp() even though not z-string */
++ for (int i = 0; i < nlist; ++i) {
++ size_t n = list[i].n;
++ if ((n == vlen || (n < vlen && v[vlen-n-1] == '.' && !full))
++ && 0 == os_strncasecmp(v+vlen-n, list[i].p, n))
++ return 1; /* match */
++ }
++ return 0; /* no match */
++}
++
++
++static int
++tls_mbedtls_match_suffixes(mbedtls_x509_crt *crt, const char *match, int full)
++{
++ /* RFE: this could be pre-parsed into structured data at config time */
++ struct mlist list[256]; /*(much larger than expected)*/
++ int nlist = 0;
++ for (const char *s = match, *tok; *s; s = tok ? tok+1 : "") {
++ tok = os_strchr(s, ';');
++ list[nlist].p = s;
++ list[nlist].n = tok ? (size_t)(tok - s) : os_strlen(s);
++ if (list[nlist].n && ++nlist == sizeof(list)/sizeof(*list)) {
++ wpa_printf(MSG_INFO, "MTLS: excessive suffix match '%s'", match);
++ break; /* truncate huge list and continue */
++ }
++ }
++
++ /* check subjectAltNames */
++ if (mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)) {
++ const mbedtls_x509_sequence *cur = &crt->subject_alt_names;
++ for (; cur != NULL; cur = cur->next) {
++ const unsigned char san_type = (unsigned char)cur->buf.tag
++ & MBEDTLS_ASN1_TAG_VALUE_MASK;
++ if (san_type == MBEDTLS_X509_SAN_DNS_NAME
++ && tls_mbedtls_match_suffix((char *)cur->buf.p,
++ cur->buf.len,
++ list, nlist, full)) {
++ return 1; /* match */
++ }
++ }
++ }
++
++ /* check subject CN */
++ const mbedtls_x509_name *name = &crt->subject;
++ for (; name != NULL; name = name->next) {
++ if (name->oid.p && MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0)
++ break;
++ }
++ if (name && tls_mbedtls_match_suffix((char *)name->val.p, name->val.len,
++ list, nlist, full)) {
++ return 1; /* match */
++ }
++
++ return 0; /* no match */
++}
++
++
++static int
++tls_mbedtls_match_dn_field(mbedtls_x509_crt *crt, const char *match)
++{
++ /* RFE: this could be pre-parsed into structured data at config time */
++ struct mlistoid { const char *p; size_t n;
++ const char *oid; size_t olen;
++ int prefix; };
++ struct mlistoid list[32]; /*(much larger than expected)*/
++ int nlist = 0;
++ for (const char *s = match, *tok, *e; *s; s = tok ? tok+1 : "") {
++ tok = os_strchr(s, '/');
++ list[nlist].oid = NULL;
++ list[nlist].olen = 0;
++ list[nlist].n = tok ? (size_t)(tok - s) : os_strlen(s);
++ e = memchr(s, '=', list[nlist].n);
++ if (e == NULL) {
++ if (list[nlist].n == 0)
++ continue; /* skip consecutive, repeated '/' */
++ if (list[nlist].n == 1 && *s == '*') {
++ /* special-case "*" to match any OID and value */
++ s = e = "=*";
++ list[nlist].n = 2;
++ list[nlist].oid = "";
++ }
++ else {
++ wpa_printf(MSG_INFO,
++ "MTLS: invalid check_cert_subject '%s' missing '='",
++ match);
++ return 0;
++ }
++ }
++ switch (e - s) {
++ case 1:
++ if (*s == 'C') {
++ list[nlist].oid = MBEDTLS_OID_AT_COUNTRY;
++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_COUNTRY)-1;
++ }
++ else if (*s == 'L') {
++ list[nlist].oid = MBEDTLS_OID_AT_LOCALITY;
++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_LOCALITY)-1;
++ }
++ else if (*s == 'O') {
++ list[nlist].oid = MBEDTLS_OID_AT_ORGANIZATION;
++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_ORGANIZATION)-1;
++ }
++ break;
++ case 2:
++ if (s[0] == 'C' && s[1] == 'N') {
++ list[nlist].oid = MBEDTLS_OID_AT_CN;
++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_CN)-1;
++ }
++ else if (s[0] == 'S' && s[1] == 'T') {
++ list[nlist].oid = MBEDTLS_OID_AT_STATE;
++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_STATE)-1;
++ }
++ else if (s[0] == 'O' && s[1] == 'U') {
++ list[nlist].oid = MBEDTLS_OID_AT_ORG_UNIT;
++ list[nlist].olen = sizeof(MBEDTLS_OID_AT_ORG_UNIT)-1;
++ }
++ break;
++ case 12:
++ if (os_memcmp(s, "emailAddress", 12) == 0) {
++ list[nlist].oid = MBEDTLS_OID_PKCS9_EMAIL;
++ list[nlist].olen = sizeof(MBEDTLS_OID_PKCS9_EMAIL)-1;
++ }
++ break;
++ default:
++ break;
++ }
++ if (list[nlist].oid == NULL) {
++ wpa_printf(MSG_INFO,
++ "MTLS: Unknown field in check_cert_subject '%s'",
++ match);
++ return 0;
++ }
++ list[nlist].n -= (size_t)(++e - s);
++ list[nlist].p = e;
++ if (list[nlist].n && e[list[nlist].n-1] == '*') {
++ --list[nlist].n;
++ list[nlist].prefix = 1;
++ }
++ /*(could easily add support for suffix matches if value begins with '*',
++ * but suffix match is not currently supported by other TLS modules)*/
++
++ if (list[nlist].n && ++nlist == sizeof(list)/sizeof(*list)) {
++ wpa_printf(MSG_INFO,
++ "MTLS: excessive check_cert_subject match '%s'",
++ match);
++ break; /* truncate huge list and continue */
++ }
++ }
++
++ /* each component in match string must match cert Subject in order listed
++ * The behavior below preserves ordering but is slightly different than
++ * the grossly inefficient contortions implemented in tls_openssl.c */
++ const mbedtls_x509_name *name = &crt->subject;
++ for (int i = 0; i < nlist; ++i) {
++ int found = 0;
++ for (; name != NULL && !found; name = name->next) {
++ if (!name->oid.p)
++ continue;
++ /* special-case "*" to match any OID and value */
++ if (list[i].olen == 0) {
++ found = 1;
++ continue;
++ }
++ /* perform equalent of !MBEDTLS_OID_CMP() with oid ptr and len */
++ if (list[i].olen != name->oid.len
++ || os_memcmp(list[i].oid, name->oid.p, name->oid.len) != 0)
++ continue;
++ /* Note: v is not '\0'-terminated, but is a known length vlen,
++ * so okay to pass to os_strncasecmp() even though not z-string */
++ if ((list[i].prefix
++ ? list[i].n <= name->val.len /* prefix match */
++ : list[i].n == name->val.len) /* full match */
++ && 0 == os_strncasecmp((char *)name->val.p,
++ list[i].p, list[i].n)) {
++ found = 1;
++ continue;
++ }
++ }
++ if (!found)
++ return 0; /* no match */
++ }
++ return 1; /* match */
++}
++
++
++__attribute_cold__
++static void
++tls_mbedtls_verify_fail_event (mbedtls_x509_crt *crt, int depth,
++ const char *errmsg, enum tls_fail_reason reason)
++{
++ struct tls_config *init_conf = &tls_ctx_global.init_conf;
++ if (init_conf->event_cb == NULL)
++ return;
++
++ struct wpabuf *certbuf = wpabuf_alloc_copy(crt->raw.p, crt->raw.len);
++ char subject[MBEDTLS_X509_MAX_DN_NAME_SIZE*2];
++ if (mbedtls_x509_dn_gets(subject, sizeof(subject), &crt->subject) < 0)
++ subject[0] = '\0';
++ union tls_event_data ev;
++ os_memset(&ev, 0, sizeof(ev));
++ ev.cert_fail.reason = reason;
++ ev.cert_fail.depth = depth;
++ ev.cert_fail.subject = subject;
++ ev.cert_fail.reason_txt = errmsg;
++ ev.cert_fail.cert = certbuf;
++
++ init_conf->event_cb(init_conf->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
++
++ wpabuf_free(certbuf);
++}
++
++
++__attribute_noinline__
++static void
++tls_mbedtls_verify_cert_event (struct tls_connection *conn,
++ mbedtls_x509_crt *crt, int depth)
++{
++ struct tls_config *init_conf = &tls_ctx_global.init_conf;
++ if (init_conf->event_cb == NULL)
++ return;
++
++ struct wpabuf *certbuf = NULL;
++ union tls_event_data ev;
++ os_memset(&ev, 0, sizeof(ev));
++
++ #ifdef MBEDTLS_SHA256_C
++ u8 hash[SHA256_DIGEST_LENGTH];
++ const u8 *addr[] = { (u8 *)crt->raw.p };
++ if (sha256_vector(1, addr, &crt->raw.len, hash) == 0) {
++ ev.peer_cert.hash = hash;
++ ev.peer_cert.hash_len = sizeof(hash);
++ }
++ #endif
++ ev.peer_cert.depth = depth;
++ char subject[MBEDTLS_X509_MAX_DN_NAME_SIZE*2];
++ if (depth == 0)
++ ev.peer_cert.subject = conn->peer_subject;
++ if (ev.peer_cert.subject == NULL) {
++ ev.peer_cert.subject = subject;
++ if (mbedtls_x509_dn_gets(subject, sizeof(subject), &crt->subject) < 0)
++ subject[0] = '\0';
++ }
++
++ char serial_num[128+1];
++ ev.peer_cert.serial_num =
++ tls_mbedtls_peer_serial_num(crt, serial_num, sizeof(serial_num));
++
++ const mbedtls_x509_sequence *cur;
++
++ cur = NULL;
++ if (mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME))
++ cur = &crt->subject_alt_names;
++ for (; cur != NULL; cur = cur->next) {
++ const unsigned char san_type = (unsigned char)cur->buf.tag
++ & MBEDTLS_ASN1_TAG_VALUE_MASK;
++ size_t prelen = 4;
++ const char *pre;
++ switch (san_type) {
++ case MBEDTLS_X509_SAN_RFC822_NAME: prelen = 6; pre = "EMAIL:";break;
++ case MBEDTLS_X509_SAN_DNS_NAME: pre = "DNS:"; break;
++ case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER: pre = "URI:"; break;
++ default: continue;
++ }
++
++ char *pos = os_malloc(prelen + cur->buf.len + 1);
++ if (pos == NULL)
++ break;
++ ev.peer_cert.altsubject[ev.peer_cert.num_altsubject] = pos;
++ os_memcpy(pos, pre, prelen);
++ /* data should be properly backslash-escaped if needed,
++ * so code below does not re-escape, but does replace CTLs */
++ /*os_memcpy(pos+prelen, cur->buf.p, cur->buf.len);*/
++ /*pos[prelen+cur->buf.len] = '\0';*/
++ pos += prelen;
++ for (size_t i = 0; i < cur->buf.len; ++i) {
++ unsigned char c = cur->buf.p[i];
++ *pos++ = (c >= 32 && c != 127) ? c : '?';
++ }
++ *pos = '\0';
++
++ if (++ev.peer_cert.num_altsubject == TLS_MAX_ALT_SUBJECT)
++ break;
++ }
++
++ cur = NULL;
++ if (mbedtls_x509_crt_has_ext_type(crt, MBEDTLS_X509_EXT_CERTIFICATE_POLICIES))
++ cur = &crt->certificate_policies;
++ for (; cur != NULL; cur = cur->next) {
++ if (cur->buf.len != 11) /* len of OID_TOD_STRICT or OID_TOD_TOFU */
++ continue;
++ /* TOD-STRICT "1.3.6.1.4.1.40808.1.3.1" */
++ /* TOD-TOFU "1.3.6.1.4.1.40808.1.3.2" */
++ #define OID_TOD_STRICT "\x2b\x06\x01\x04\x01\x82\xbe\x68\x01\x03\x01"
++ #define OID_TOD_TOFU "\x2b\x06\x01\x04\x01\x82\xbe\x68\x01\x03\x02"
++ if (os_memcmp(cur->buf.p,
++ OID_TOD_STRICT, sizeof(OID_TOD_STRICT)-1) == 0) {
++ ev.peer_cert.tod = 1; /* TOD-STRICT */
++ break;
++ }
++ if (os_memcmp(cur->buf.p,
++ OID_TOD_TOFU, sizeof(OID_TOD_TOFU)-1) == 0) {
++ ev.peer_cert.tod = 2; /* TOD-TOFU */
++ break;
++ }
++ }
++
++ struct tls_conf *tls_conf = conn->tls_conf;
++ if (tls_conf->ca_cert_probe || (tls_conf->flags & TLS_CONN_EXT_CERT_CHECK)
++ || init_conf->cert_in_cb) {
++ certbuf = wpabuf_alloc_copy(crt->raw.p, crt->raw.len);
++ ev.peer_cert.cert = certbuf;
++ }
++
++ init_conf->event_cb(init_conf->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
++
++ wpabuf_free(certbuf);
++ char **altsubject;
++ *(const char ***)&altsubject = ev.peer_cert.altsubject;
++ for (size_t i = 0; i < ev.peer_cert.num_altsubject; ++i)
++ os_free(altsubject[i]);
++}
++
++
++static int
++tls_mbedtls_verify_cb (void *arg, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
++{
++ /* XXX: N.B. verify code not carefully tested besides hwsim tests
++ *
++ * RFE: mbedtls_x509_crt_verify_info() and enhance log trace messages
++ * RFE: review and add support for additional TLS_CONN_* flags
++ * not handling OCSP (not available in mbedtls)
++ * ... */
++
++ struct tls_connection *conn = (struct tls_connection *)arg;
++ struct tls_conf *tls_conf = conn->tls_conf;
++ uint32_t flags_in = *flags;
++
++ if (depth > 8) { /*(depth 8 picked as arbitrary limit)*/
++ emsg(MSG_WARNING, "client cert chain too long");
++ *flags |= MBEDTLS_X509_BADCERT_OTHER; /* cert chain too long */
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "client cert chain too long",
++ TLS_FAIL_BAD_CERTIFICATE);
++ }
++ else if (tls_conf->verify_depth0_only) {
++ if (depth > 0)
++ *flags = 0;
++ else {
++ #ifdef MBEDTLS_SHA256_C
++ u8 hash[SHA256_DIGEST_LENGTH];
++ const u8 *addr[] = { (u8 *)crt->raw.p };
++ if (sha256_vector(1, addr, &crt->raw.len, hash) < 0
++ || os_memcmp(tls_conf->ca_cert_hash, hash, sizeof(hash)) != 0) {
++ *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "cert hash mismatch",
++ TLS_FAIL_UNTRUSTED);
++ }
++ else /* hash matches; ignore other issues *except* if revoked)*/
++ *flags &= MBEDTLS_X509_BADCERT_REVOKED;
++ #endif
++ }
++ }
++ else if (depth == 0) {
++ if (!conn->peer_subject)
++ tls_mbedtls_set_peer_subject(conn, crt);
++ /*(use same labels to tls_mbedtls_verify_fail_event() as used in
++ * other TLS modules so that hwsim tests find exact string match)*/
++ if (!conn->peer_subject) { /* error copying subject string */
++ *flags |= MBEDTLS_X509_BADCERT_OTHER;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "internal error",
++ TLS_FAIL_UNSPECIFIED);
++ }
++ /*(use os_strstr() for subject match as is done in tls_mbedtls.c
++ * to follow the same behavior, even though a suffix match would
++ * make more sense. Also, note that strstr match does not
++ * normalize whitespace (between components) for comparison)*/
++ else if (tls_conf->subject_match
++ && os_strstr(conn->peer_subject,
++ tls_conf->subject_match) == NULL) {
++ wpa_printf(MSG_WARNING,
++ "MTLS: Subject '%s' did not match with '%s'",
++ conn->peer_subject, tls_conf->subject_match);
++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "Subject mismatch",
++ TLS_FAIL_SUBJECT_MISMATCH);
++ }
++ if (tls_conf->altsubject_match
++ && !tls_mbedtls_match_altsubject(crt, tls_conf->altsubject_match)) {
++ wpa_printf(MSG_WARNING,
++ "MTLS: altSubjectName match '%s' not found",
++ tls_conf->altsubject_match);
++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "AltSubject mismatch",
++ TLS_FAIL_ALTSUBJECT_MISMATCH);
++ }
++ if (tls_conf->suffix_match
++ && !tls_mbedtls_match_suffixes(crt, tls_conf->suffix_match, 0)) {
++ wpa_printf(MSG_WARNING,
++ "MTLS: Domain suffix match '%s' not found",
++ tls_conf->suffix_match);
++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "Domain suffix mismatch",
++ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
++ }
++ if (tls_conf->domain_match
++ && !tls_mbedtls_match_suffixes(crt, tls_conf->domain_match, 1)) {
++ wpa_printf(MSG_WARNING,
++ "MTLS: Domain match '%s' not found",
++ tls_conf->domain_match);
++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "Domain mismatch",
++ TLS_FAIL_DOMAIN_MISMATCH);
++ }
++ if (tls_conf->check_cert_subject
++ && !tls_mbedtls_match_dn_field(crt, tls_conf->check_cert_subject)) {
++ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "Distinguished Name",
++ TLS_FAIL_DN_MISMATCH);
++ }
++ if (tls_conf->flags & TLS_CONN_SUITEB) {
++ /* check RSA modulus size (public key bitlen) */
++ const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(&crt->pk);
++ if ((pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS)
++ && mbedtls_pk_get_bitlen(&crt->pk) < 3072) {
++ /* hwsim suite_b RSA tests expect 3072
++ * suite_b_192_rsa_ecdhe_radius_rsa2048_client
++ * suite_b_192_rsa_dhe_radius_rsa2048_client */
++ *flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "Insufficient RSA modulus size",
++ TLS_FAIL_INSUFFICIENT_KEY_LEN);
++ }
++ }
++ if (tls_conf->check_crl && tls_conf->crl == NULL) {
++ /* see tests/hwsim test_ap_eap.py ap_wpa2_eap_tls_check_crl */
++ emsg(MSG_WARNING, "check_crl set but no CRL loaded; reject all?");
++ *flags |= MBEDTLS_X509_BADCERT_OTHER;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "check_crl set but no CRL loaded; "
++ "reject all?",
++ TLS_FAIL_BAD_CERTIFICATE);
++ }
++ }
++ else {
++ if (tls_conf->check_crl != 2) /* 2 == verify CRLs for all certs */
++ *flags &= ~MBEDTLS_X509_BADCERT_REVOKED;
++ }
++
++ if (!tls_conf->check_crl_strict) {
++ *flags &= ~MBEDTLS_X509_BADCRL_EXPIRED;
++ *flags &= ~MBEDTLS_X509_BADCRL_FUTURE;
++ }
++
++ if (tls_conf->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
++ *flags &= ~MBEDTLS_X509_BADCERT_EXPIRED;
++ *flags &= ~MBEDTLS_X509_BADCERT_FUTURE;
++ }
++
++ tls_mbedtls_verify_cert_event(conn, crt, depth);
++
++ if (*flags) {
++ if (*flags & (MBEDTLS_X509_BADCERT_NOT_TRUSTED
++ |MBEDTLS_X509_BADCERT_CN_MISMATCH
++ |MBEDTLS_X509_BADCERT_REVOKED)) {
++ emsg(MSG_WARNING, "client cert not trusted");
++ }
++ /* report event if flags set but no additional flags set above */
++ /* (could translate flags to more detailed TLS_FAIL_* if needed) */
++ if (!(*flags & ~flags_in)) {
++ enum tls_fail_reason reason = TLS_FAIL_UNSPECIFIED;
++ const char *errmsg = "cert verify fail unspecified";
++ if (*flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
++ reason = TLS_FAIL_UNTRUSTED;
++ errmsg = "certificate not trusted";
++ }
++ if (*flags & MBEDTLS_X509_BADCERT_REVOKED) {
++ reason = TLS_FAIL_REVOKED;
++ errmsg = "certificate has been revoked";
++ }
++ if (*flags & MBEDTLS_X509_BADCERT_FUTURE) {
++ reason = TLS_FAIL_NOT_YET_VALID;
++ errmsg = "certificate not yet valid";
++ }
++ if (*flags & MBEDTLS_X509_BADCERT_EXPIRED) {
++ reason = TLS_FAIL_EXPIRED;
++ errmsg = "certificate has expired";
++ }
++ if (*flags & MBEDTLS_X509_BADCERT_BAD_MD) {
++ reason = TLS_FAIL_BAD_CERTIFICATE;
++ errmsg = "certificate uses insecure algorithm";
++ }
++ tls_mbedtls_verify_fail_event(crt, depth, errmsg, reason);
++ }
++ #if 0
++ /* ??? send (again) cert events for all certs in chain ???
++ * (should already have been called for greater depths) */
++ /* tls_openssl.c:tls_verify_cb() sends cert events for all certs
++ * in chain if certificate validation fails, but sends all events
++ * with depth set to 0 (might be a bug) */
++ if (depth > 0) {
++ int pdepth = depth + 1;
++ for (mbedtls_x509_crt *pcrt; (pcrt = crt->next); ++pdepth) {
++ tls_mbedtls_verify_cert_event(conn, pcrt, pdepth);
++ }
++ }
++ #endif
++ /*(do not preserve subject if verification failed but was optional)*/
++ if (depth == 0 && conn->peer_subject) {
++ os_free(conn->peer_subject);
++ conn->peer_subject = NULL;
++ }
++ }
++ else if (depth == 0) {
++ struct tls_config *init_conf = &tls_ctx_global.init_conf;
++ if (tls_conf->ca_cert_probe) {
++ /* reject server certificate on probe-only run */
++ *flags |= MBEDTLS_X509_BADCERT_OTHER;
++ tls_mbedtls_verify_fail_event(crt, depth,
++ "server chain probe",
++ TLS_FAIL_SERVER_CHAIN_PROBE);
++ }
++ else if (init_conf->event_cb) {
++ /* ??? send event as soon as depth == 0 is verified ???
++ * What about rest of chain?
++ * Follows tls_mbedtls.c behavior: */
++ init_conf->event_cb(init_conf->cb_ctx,
++ TLS_CERT_CHAIN_SUCCESS, NULL);
++ }
++ }
++
++ return 0;
++}
+--- /dev/null
++++ b/tests/build/build-wpa_supplicant-mbedtls.config
+@@ -0,0 +1,24 @@
++CONFIG_TLS=mbedtls
++
++CONFIG_WPS=y
++CONFIG_EAP_TLS=y
++CONFIG_EAP_MSCHAPV2=y
++
++CONFIG_EAP_PSK=y
++CONFIG_EAP_GPSK=y
++CONFIG_EAP_AKA=y
++CONFIG_EAP_SIM=y
++CONFIG_EAP_SAKE=y
++CONFIG_EAP_PAX=y
++CONFIG_EAP_FAST=y
++CONFIG_EAP_IKEV2=y
++
++CONFIG_SAE=y
++CONFIG_FILS=y
++CONFIG_FILS_SK_PFS=y
++CONFIG_OWE=y
++CONFIG_DPP=y
++CONFIG_SUITEB=y
++CONFIG_SUITEB192=y
++
++CFLAGS += -Werror
+--- a/tests/hwsim/example-hostapd.config
++++ b/tests/hwsim/example-hostapd.config
+@@ -4,6 +4,7 @@ CONFIG_DRIVER_NONE=y
+ CONFIG_DRIVER_NL80211=y
+ CONFIG_RSN_PREAUTH=y
+
++#CONFIG_TLS=mbedtls
+ #CONFIG_TLS=internal
+ #CONFIG_INTERNAL_LIBTOMMATH=y
+ #CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+@@ -39,6 +40,9 @@ endif
+ ifeq ($(CONFIG_TLS), wolfssl)
+ CONFIG_EAP_PWD=y
+ endif
++ifeq ($(CONFIG_TLS), mbedtls)
++CONFIG_EAP_PWD=y
++endif
+ CONFIG_EAP_EKE=y
+ CONFIG_PKCS12=y
+ CONFIG_RADIUS_SERVER=y
+--- a/tests/hwsim/example-wpa_supplicant.config
++++ b/tests/hwsim/example-wpa_supplicant.config
+@@ -2,6 +2,7 @@
+
+ CONFIG_TLS=openssl
+ #CONFIG_TLS=wolfssl
++#CONFIG_TLS=mbedtls
+ #CONFIG_TLS=internal
+ #CONFIG_INTERNAL_LIBTOMMATH=y
+ #CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+@@ -41,6 +42,9 @@ endif
+ ifeq ($(CONFIG_TLS), wolfssl)
+ CONFIG_EAP_PWD=y
+ endif
++ifeq ($(CONFIG_TLS), mbedtls)
++CONFIG_EAP_PWD=y
++endif
+
+ CONFIG_USIM_SIMULATOR=y
+ CONFIG_SIM_SIMULATOR=y
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -1163,6 +1163,29 @@ endif
+ CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
+ endif
+
++ifeq ($(CONFIG_TLS), mbedtls)
++ifndef CONFIG_CRYPTO
++CONFIG_CRYPTO=mbedtls
++endif
++ifdef TLS_FUNCS
++OBJS += ../src/crypto/tls_mbedtls.o
++LIBS += -lmbedtls -lmbedx509
++endif
++OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
++OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
++OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
++ifdef NEED_FIPS186_2_PRF
++OBJS += ../src/crypto/fips_prf_internal.o
++SHA1OBJS += ../src/crypto/sha1-internal.o
++endif
++ifeq ($(CONFIG_CRYPTO), mbedtls)
++LIBS += -lmbedcrypto
++LIBS_p += -lmbedcrypto
++# XXX: create a config option?
++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
++endif
++endif
++
+ ifeq ($(CONFIG_TLS), gnutls)
+ ifndef CONFIG_CRYPTO
+ # default to libgcrypt
+@@ -1355,9 +1378,11 @@ endif
+
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ NEED_INTERNAL_AES_WRAP=y
+ endif
+ endif
++endif
+ ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+ # Seems to be needed at least with BoringSSL
+ NEED_INTERNAL_AES_WRAP=y
+@@ -1371,9 +1396,11 @@ endif
+
+ ifdef NEED_INTERNAL_AES_WRAP
+ ifneq ($(CONFIG_TLS), linux)
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-unwrap.o
+ endif
+ endif
++endif
+ ifdef NEED_AES_EAX
+ AESOBJS += ../src/crypto/aes-eax.o
+ NEED_AES_CTR=y
+@@ -1383,35 +1410,45 @@ AESOBJS += ../src/crypto/aes-siv.o
+ NEED_AES_CTR=y
+ endif
+ ifdef NEED_AES_CTR
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-ctr.o
+ endif
++endif
+ ifdef NEED_AES_ENCBLOCK
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-encblock.o
+ endif
++endif
+ NEED_AES_ENC=y
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-omac1.o
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_AES_WRAP
+ NEED_AES_ENC=y
+ ifdef NEED_INTERNAL_AES_WRAP
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-wrap.o
+ endif
+ endif
++endif
+ ifdef NEED_AES_CBC
+ NEED_AES_ENC=y
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ AESOBJS += ../src/crypto/aes-cbc.o
+ endif
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_AES_ENC
+ ifdef CONFIG_INTERNAL_AES
+ AESOBJS += ../src/crypto/aes-internal-enc.o
+@@ -1426,12 +1463,16 @@ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1.o
+ endif
+ endif
+ endif
+ endif
++endif
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-prf.o
++endif
+ ifdef CONFIG_INTERNAL_SHA1
+ SHA1OBJS += ../src/crypto/sha1-internal.o
+ ifdef NEED_FIPS186_2_PRF
+@@ -1443,29 +1484,37 @@ CFLAGS += -DCONFIG_NO_PBKDF2
+ else
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_T_PRF
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-tprf.o
+ endif
++endif
+ ifdef NEED_TLS_PRF
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+ endif
+ endif
++endif
+
+ ifndef CONFIG_FIPS
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ MD5OBJS += ../src/crypto/md5.o
+ endif
+ endif
+ endif
+ endif
+ endif
++endif
+ ifdef NEED_MD5
+ ifdef CONFIG_INTERNAL_MD5
+ MD5OBJS += ../src/crypto/md5-internal.o
+@@ -1520,12 +1569,17 @@ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA256OBJS += ../src/crypto/sha256.o
+ endif
+ endif
+ endif
+ endif
++endif
++
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA256OBJS += ../src/crypto/sha256-prf.o
++endif
+ ifdef CONFIG_INTERNAL_SHA256
+ SHA256OBJS += ../src/crypto/sha256-internal.o
+ endif
+@@ -1538,50 +1592,68 @@ CFLAGS += -DCONFIG_INTERNAL_SHA512
+ SHA256OBJS += ../src/crypto/sha512-internal.o
+ endif
+ ifdef NEED_TLS_PRF_SHA256
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+ endif
++endif
+ ifdef NEED_TLS_PRF_SHA384
++ifneq ($(CONFIG_TLS), mbedtls)
+ SHA256OBJS += ../src/crypto/sha384-tlsprf.o
+ endif
++endif
+ ifdef NEED_HMAC_SHA256_KDF
+ CFLAGS += -DCONFIG_HMAC_SHA256_KDF
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha256-kdf.o
+ endif
++endif
+ ifdef NEED_HMAC_SHA384_KDF
+ CFLAGS += -DCONFIG_HMAC_SHA384_KDF
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384-kdf.o
+ endif
++endif
+ ifdef NEED_HMAC_SHA512_KDF
+ CFLAGS += -DCONFIG_HMAC_SHA512_KDF
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha512-kdf.o
+ endif
++endif
+ OBJS += $(SHA256OBJS)
+ ifdef NEED_SHA384
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384.o
+ endif
+ endif
+ endif
+ endif
++endif
+ CFLAGS += -DCONFIG_SHA384
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha384-prf.o
+ endif
++endif
+ ifdef NEED_SHA512
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), linux)
+ ifneq ($(CONFIG_TLS), gnutls)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha512.o
+ endif
+ endif
+ endif
+ endif
++endif
+ CFLAGS += -DCONFIG_SHA512
++ifneq ($(CONFIG_TLS), mbedtls)
+ OBJS += ../src/crypto/sha512-prf.o
+ endif
++endif
+
+ ifdef NEED_ASN1
+ OBJS += ../src/tls/asn1.o
+@@ -1756,10 +1828,12 @@ ifdef CONFIG_FIPS
+ CFLAGS += -DCONFIG_FIPS
+ ifneq ($(CONFIG_TLS), openssl)
+ ifneq ($(CONFIG_TLS), wolfssl)
++ifneq ($(CONFIG_TLS), mbedtls)
+ $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+ endif
+ endif
+ endif
++endif
+
+ OBJS += $(SHA1OBJS) $(DESOBJS)
+
+--- a/wpa_supplicant/defconfig
++++ b/wpa_supplicant/defconfig
+@@ -10,8 +10,8 @@
+ # to override previous values of the variables.
+
+
+-# Uncomment following two lines and fix the paths if you have installed OpenSSL
+-# or GnuTLS in non-default location
++# Uncomment following two lines and fix the paths if you have installed TLS
++# libraries in a non-default location
+ #CFLAGS += -I/usr/local/openssl/include
+ #LIBS += -L/usr/local/openssl/lib
+
+@@ -20,6 +20,7 @@
+ # used to fix build issues on such systems (krb5.h not found).
+ #CFLAGS += -I/usr/include/kerberos
+
++
+ # Driver interface for generic Linux wireless extensions
+ # Note: WEXT is deprecated in the current Linux kernel version and no new
+ # functionality is added to it. nl80211-based interface is the new
+@@ -326,6 +327,7 @@ CONFIG_BACKEND=file
+ # openssl = OpenSSL (default)
+ # gnutls = GnuTLS
+ # internal = Internal TLSv1 implementation (experimental)
++# mbedtls = mbed TLS
+ # linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
+ # none = Empty template
+ #CONFIG_TLS=openssl
diff --git a/package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch b/package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch
new file mode 100644
index 00000000000..a48725264fd
--- /dev/null
+++ b/package/network/services/hostapd/patches/120-mbedtls-fips186_2_prf.patch
@@ -0,0 +1,114 @@
+From c8dba4bd750269bcc80fed3d546e2077cb4cdf0e Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <gstrauss@gluelogic.com>
+Date: Tue, 19 Jul 2022 20:02:21 -0400
+Subject: [PATCH 2/7] mbedtls: fips186_2_prf()
+
+Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
+---
+ hostapd/Makefile | 4 ---
+ src/crypto/crypto_mbedtls.c | 60 +++++++++++++++++++++++++++++++++++++
+ wpa_supplicant/Makefile | 4 ---
+ 3 files changed, 60 insertions(+), 8 deletions(-)
+
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -759,10 +759,6 @@ endif
+ OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+ HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+ SOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+-ifdef NEED_FIPS186_2_PRF
+-OBJS += ../src/crypto/fips_prf_internal.o
+-SHA1OBJS += ../src/crypto/sha1-internal.o
+-endif
+ ifeq ($(CONFIG_CRYPTO), mbedtls)
+ ifdef CONFIG_DPP
+ LIBS += -lmbedx509
+--- a/src/crypto/crypto_mbedtls.c
++++ b/src/crypto/crypto_mbedtls.c
+@@ -132,6 +132,12 @@
+ #define CRYPTO_MBEDTLS_HMAC_KDF_SHA512
+ #endif
+
++#if defined(EAP_SIM) || defined(EAP_SIM_DYNAMIC) || defined(EAP_SERVER_SIM) \
++ || defined(EAP_AKA) || defined(EAP_AKA_DYNAMIC) || defined(EAP_SERVER_AKA)
++/* EAP_SIM=y EAP_AKA=y */
++#define CRYPTO_MBEDTLS_FIPS186_2_PRF
++#endif
++
+ #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) \
+ || defined(EAP_TEAP) || defined(EAP_TEAP_DYNAMIC) || defined(EAP_SERVER_FAST)
+ #define CRYPTO_MBEDTLS_SHA1_T_PRF
+@@ -813,6 +819,60 @@ int sha1_t_prf(const u8 *key, size_t key
+
+ #endif /* CRYPTO_MBEDTLS_SHA1_T_PRF */
+
++#ifdef CRYPTO_MBEDTLS_FIPS186_2_PRF
++
++/* fips_prf_internal.c sha1-internal.c */
++
++/* used only by src/eap_common/eap_sim_common.c:eap_sim_prf()
++ * for eap_sim_derive_keys() and eap_sim_derive_keys_reauth()
++ * where xlen is 160 */
++
++int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
++{
++ /* FIPS 186-2 + change notice 1 */
++
++ mbedtls_sha1_context ctx;
++ u8 * const xkey = ctx.MBEDTLS_PRIVATE(buffer);
++ u32 * const xstate = ctx.MBEDTLS_PRIVATE(state);
++ const u32 xstate_init[] =
++ { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
++
++ mbedtls_sha1_init(&ctx);
++ os_memcpy(xkey, seed, seed_len < 64 ? seed_len : 64);
++
++ /* note: does not fill extra bytes if (xlen % 20) (SHA1_MAC_LEN) */
++ for (; xlen >= 20; xlen -= 20) {
++ /* XSEED_j = 0 */
++ /* XVAL = (XKEY + XSEED_j) mod 2^b */
++
++ /* w_i = G(t, XVAL) */
++ os_memcpy(xstate, xstate_init, sizeof(xstate_init));
++ mbedtls_internal_sha1_process(&ctx, xkey);
++
++ #if __BYTE_ORDER == __LITTLE_ENDIAN
++ xstate[0] = host_to_be32(xstate[0]);
++ xstate[1] = host_to_be32(xstate[1]);
++ xstate[2] = host_to_be32(xstate[2]);
++ xstate[3] = host_to_be32(xstate[3]);
++ xstate[4] = host_to_be32(xstate[4]);
++ #endif
++ os_memcpy(x, xstate, 20);
++ if (xlen == 20) /*(done; skip prep for next loop)*/
++ break;
++
++ /* XKEY = (1 + XKEY + w_i) mod 2^b */
++ for (u32 carry = 1, k = 20; k-- > 0; carry >>= 8)
++ xkey[k] = (carry += xkey[k] + x[k]) & 0xff;
++ x += 20;
++ /* x_j = w_0|w_1 (each pair of iterations through loop)*/
++ }
++
++ mbedtls_sha1_free(&ctx);
++ return 0;
++}
++
++#endif /* CRYPTO_MBEDTLS_FIPS186_2_PRF */
++
+ #endif /* MBEDTLS_SHA1_C */
+
+
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -1174,10 +1174,6 @@ endif
+ OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+ OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+ OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+-ifdef NEED_FIPS186_2_PRF
+-OBJS += ../src/crypto/fips_prf_internal.o
+-SHA1OBJS += ../src/crypto/sha1-internal.o
+-endif
+ ifeq ($(CONFIG_CRYPTO), mbedtls)
+ LIBS += -lmbedcrypto
+ LIBS_p += -lmbedcrypto
diff --git a/package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch b/package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch
new file mode 100644
index 00000000000..ae7620b90c1
--- /dev/null
+++ b/package/network/services/hostapd/patches/130-mbedtls-annotate-with-TEST_FAIL-for-hwsim-tests.patch
@@ -0,0 +1,421 @@
+From 31bd19e0e0254b910cccfd3ddc6a6a9222bbcfc0 Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <gstrauss@gluelogic.com>
+Date: Sun, 9 Oct 2022 05:12:17 -0400
+Subject: [PATCH 3/7] mbedtls: annotate with TEST_FAIL() for hwsim tests
+
+Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
+---
+ src/crypto/crypto_mbedtls.c | 124 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 124 insertions(+)
+
+--- a/src/crypto/crypto_mbedtls.c
++++ b/src/crypto/crypto_mbedtls.c
+@@ -280,6 +280,9 @@ __attribute_noinline__
+ static int md_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac, mbedtls_md_type_t md_type)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_md_context_t ctx;
+ mbedtls_md_init(&ctx);
+ if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0) != 0){
+@@ -343,6 +346,9 @@ __attribute_noinline__
+ static int sha384_512_vector(size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac, int is384)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ struct mbedtls_sha512_context ctx;
+ mbedtls_sha512_init(&ctx);
+ #if MBEDTLS_VERSION_MAJOR >= 3
+@@ -375,6 +381,9 @@ int sha384_vector(size_t num_elem, const
+ #include <mbedtls/sha256.h>
+ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ struct mbedtls_sha256_context ctx;
+ mbedtls_sha256_init(&ctx);
+ #if MBEDTLS_VERSION_MAJOR >= 3
+@@ -397,6 +406,9 @@ int sha256_vector(size_t num_elem, const
+ #include <mbedtls/sha1.h>
+ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ struct mbedtls_sha1_context ctx;
+ mbedtls_sha1_init(&ctx);
+ #if MBEDTLS_VERSION_MAJOR >= 3
+@@ -419,6 +431,9 @@ int sha1_vector(size_t num_elem, const u
+ #include <mbedtls/md5.h>
+ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ struct mbedtls_md5_context ctx;
+ mbedtls_md5_init(&ctx);
+ #if MBEDTLS_VERSION_MAJOR >= 3
+@@ -441,6 +456,9 @@ int md5_vector(size_t num_elem, const u8
+ #include <mbedtls/md4.h>
+ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ struct mbedtls_md4_context ctx;
+ mbedtls_md4_init(&ctx);
+ mbedtls_md4_starts_ret(&ctx);
+@@ -460,6 +478,9 @@ static int hmac_vector(const u8 *key, si
+ const u8 *addr[], const size_t *len, u8 *mac,
+ mbedtls_md_type_t md_type)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_md_context_t ctx;
+ mbedtls_md_init(&ctx);
+ if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1) != 0){
+@@ -571,6 +592,9 @@ static int hmac_kdf_expand(const u8 *prk
+ const char *label, const u8 *info, size_t info_len,
+ u8 *okm, size_t okm_len, mbedtls_md_type_t md_type)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
+ #ifdef MBEDTLS_HKDF_C
+ if (label == NULL) /* RFC 5869 HKDF-Expand when (label == NULL) */
+@@ -663,6 +687,9 @@ static int hmac_prf_bits(const u8 *key,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits, mbedtls_md_type_t md_type)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_md_context_t ctx;
+ mbedtls_md_init(&ctx);
+ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
+@@ -938,6 +965,9 @@ int pbkdf2_sha1(const char *passphrase,
+
+ static void *aes_crypt_init_mode(const u8 *key, size_t len, int mode)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ mbedtls_aes_context *aes = os_malloc(sizeof(*aes));
+ if (!aes)
+ return NULL;
+@@ -996,6 +1026,9 @@ void aes_decrypt_deinit(void *ctx)
+ /* aes-wrap.c */
+ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_nist_kw_context ctx;
+ mbedtls_nist_kw_init(&ctx);
+ size_t olen;
+@@ -1010,6 +1043,9 @@ int aes_wrap(const u8 *kek, size_t kek_l
+ /* aes-unwrap.c */
+ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_nist_kw_context ctx;
+ mbedtls_nist_kw_init(&ctx);
+ size_t olen;
+@@ -1041,6 +1077,9 @@ int omac1_aes_vector(
+ const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_cipher_type_t cipher_type;
+ switch (key_len) {
+ case 16: cipher_type = MBEDTLS_CIPHER_AES_128_ECB; break;
+@@ -1103,6 +1142,9 @@ int omac1_aes_256(const u8 *key, const u
+ /* aes-encblock.c */
+ int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_aes_context aes;
+ mbedtls_aes_init(&aes);
+ int ret = mbedtls_aes_setkey_enc(&aes, key, 128)
+@@ -1118,6 +1160,9 @@ int aes_128_encrypt_block(const u8 *key,
+ int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ unsigned char counter[MBEDTLS_AES_BLOCK_SIZE];
+ unsigned char stream_block[MBEDTLS_AES_BLOCK_SIZE];
+ os_memcpy(counter, nonce, MBEDTLS_AES_BLOCK_SIZE);/*(must be writable)*/
+@@ -1160,11 +1205,17 @@ static int aes_128_cbc_oper(const u8 *ke
+
+ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_ENCRYPT);
+ }
+
+ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return aes_128_cbc_oper(key, iv, data, data_len, MBEDTLS_AES_DECRYPT);
+ }
+
+@@ -1407,6 +1458,10 @@ int crypto_hash_finish(struct crypto_has
+ }
+ mbedtls_md_free(mctx);
+ os_free(mctx);
++
++ if (TEST_FAIL())
++ return -1;
++
+ return 0;
+ }
+
+@@ -1421,6 +1476,9 @@ int crypto_hash_finish(struct crypto_has
+
+ struct crypto_bignum *crypto_bignum_init(void)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ mbedtls_mpi *bn = os_malloc(sizeof(*bn));
+ if (bn)
+ mbedtls_mpi_init(bn);
+@@ -1429,6 +1487,9 @@ struct crypto_bignum *crypto_bignum_init
+
+ struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ mbedtls_mpi *bn = os_malloc(sizeof(*bn));
+ if (bn) {
+ mbedtls_mpi_init(bn);
+@@ -1442,6 +1503,9 @@ struct crypto_bignum *crypto_bignum_init
+
+ struct crypto_bignum *crypto_bignum_init_uint(unsigned int val)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ #if 0 /*(hostap use of this interface passes int, not uint)*/
+ val = host_to_be32(val);
+ return crypto_bignum_init_set((const u8 *)&val, sizeof(val));
+@@ -1467,6 +1531,9 @@ void crypto_bignum_deinit(struct crypto_
+ int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ size_t n = mbedtls_mpi_size((mbedtls_mpi *)a);
+ if (n < padlen)
+ n = padlen;
+@@ -1477,6 +1544,9 @@ int crypto_bignum_to_bin(const struct cr
+
+ int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ /*assert(r != m);*//* r must not be same as m for mbedtls_mpi_random()*/
+ #if MBEDTLS_VERSION_NUMBER >= 0x021B0000 /* mbedtls 2.27.0 */
+ return mbedtls_mpi_random((mbedtls_mpi *)r, 0, (mbedtls_mpi *)m,
+@@ -1513,6 +1583,9 @@ int crypto_bignum_exptmod(const struct c
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ /* (check if input params match d; d is the result) */
+ /* (a == d) is ok in current mbedtls implementation */
+ if (b == d || c == d) { /*(not ok; store result in intermediate)*/
+@@ -1540,6 +1613,9 @@ int crypto_bignum_inverse(const struct c
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return mbedtls_mpi_inv_mod((mbedtls_mpi *)c,
+ (const mbedtls_mpi *)a,
+ (const mbedtls_mpi *)b) ? -1 : 0;
+@@ -1549,6 +1625,9 @@ int crypto_bignum_sub(const struct crypt
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return mbedtls_mpi_sub_mpi((mbedtls_mpi *)c,
+ (const mbedtls_mpi *)a,
+ (const mbedtls_mpi *)b) ? -1 : 0;
+@@ -1558,6 +1637,9 @@ int crypto_bignum_div(const struct crypt
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ /*(most current use of this crypto.h interface has a == c (result),
+ * so store result in an intermediate to avoid overwritten input)*/
+ mbedtls_mpi R;
+@@ -1575,6 +1657,9 @@ int crypto_bignum_addmod(const struct cr
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return mbedtls_mpi_add_mpi((mbedtls_mpi *)d,
+ (const mbedtls_mpi *)a,
+ (const mbedtls_mpi *)b)
+@@ -1588,6 +1673,9 @@ int crypto_bignum_mulmod(const struct cr
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return mbedtls_mpi_mul_mpi((mbedtls_mpi *)d,
+ (const mbedtls_mpi *)a,
+ (const mbedtls_mpi *)b)
+@@ -1600,6 +1688,9 @@ int crypto_bignum_sqrmod(const struct cr
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ #if 1
+ return crypto_bignum_mulmod(a, a, b, c);
+ #else
+@@ -1650,6 +1741,9 @@ int crypto_bignum_is_odd(const struct cr
+ int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p)
+ {
++ if (TEST_FAIL())
++ return -2;
++
+ /* Security Note:
+ * mbedtls_mpi_exp_mod() is not documented to run in constant time,
+ * though mbedtls/library/bignum.c uses constant_time_internal.h funcs.
+@@ -1702,6 +1796,9 @@ int crypto_mod_exp(const u8 *base, size_
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result;
+ mbedtls_mpi_init(&bn_base);
+ mbedtls_mpi_init(&bn_exp);
+@@ -1769,6 +1866,9 @@ static int crypto_mbedtls_dh_init_public
+ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ #if 0 /*(crypto_dh_init() duplicated (and identical) in crypto_*.c modules)*/
+ size_t pubkey_len, pad;
+
+@@ -1810,6 +1910,9 @@ int crypto_dh_derive_secret(u8 generator
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ #if 0
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+@@ -2512,6 +2615,9 @@ const struct crypto_ec_point * crypto_ec
+
+ struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ mbedtls_ecp_point *p = os_malloc(sizeof(*p));
+ if (p != NULL)
+ mbedtls_ecp_point_init(p);
+@@ -2536,6 +2642,9 @@ int crypto_ec_point_x(struct crypto_ec *
+ int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ /* crypto.h documents crypto_ec_point_to_bin() output is big-endian */
+ size_t len = CRYPTO_EC_plen(e);
+ if (x) {
+@@ -2563,6 +2672,9 @@ int crypto_ec_point_to_bin(struct crypto
+ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ size_t len = CRYPTO_EC_plen(e);
+ mbedtls_ecp_point *p = os_malloc(sizeof(*p));
+ u8 buf[1+MBEDTLS_MPI_MAX_SIZE*2];
+@@ -2615,6 +2727,9 @@ int crypto_ec_point_add(struct crypto_ec
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ /* mbedtls does not provide an mbedtls_ecp_point add function */
+ mbedtls_mpi one;
+ mbedtls_mpi_init(&one);
+@@ -2631,6 +2746,9 @@ int crypto_ec_point_mul(struct crypto_ec
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ return mbedtls_ecp_mul(
+ (mbedtls_ecp_group *)e, (mbedtls_ecp_point *)res,
+ (const mbedtls_mpi *)b, (const mbedtls_ecp_point *)p,
+@@ -2639,6 +2757,9 @@ int crypto_ec_point_mul(struct crypto_ec
+
+ int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+ {
++ if (TEST_FAIL())
++ return -1;
++
+ if (mbedtls_ecp_get_type((mbedtls_ecp_group *)e)
+ == MBEDTLS_ECP_TYPE_MONTGOMERY) {
+ /* e.g. MBEDTLS_ECP_DP_CURVE25519 and MBEDTLS_ECP_DP_CURVE448 */
+@@ -2751,6 +2872,9 @@ struct crypto_bignum *
+ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x)
+ {
++ if (TEST_FAIL())
++ return NULL;
++
+ mbedtls_mpi *y2 = os_malloc(sizeof(*y2));
+ if (y2 == NULL)
+ return NULL;
diff --git a/package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch b/package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch
new file mode 100644
index 00000000000..0c29432d3f8
--- /dev/null
+++ b/package/network/services/hostapd/patches/135-mbedtls-fix-owe-association.patch
@@ -0,0 +1,91 @@
+The code for hostapd-mbedtls did not work when used for OWE association.
+
+When handling association requests, the buffer offsets and length assumptions were incorrect, leading to never calculating the y point, thus denying association.
+
+Also when crafting the association response, the buffer contained the trailing key-type.
+
+Fix up both issues to adhere to the specification and make hostapd-mbedtls work with the OWE security type.
+
+--- a/src/crypto/crypto_mbedtls.c
++++ b/src/crypto/crypto_mbedtls.c
+@@ -2299,25 +2299,30 @@ struct crypto_ecdh * crypto_ecdh_init2(i
+ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+ {
+ mbedtls_ecp_group *grp = &ecdh->grp;
+- size_t len = CRYPTO_EC_plen(grp);
++ size_t prime_len = CRYPTO_EC_plen(grp);
++ size_t output_len = prime_len;
++ u8 output_offset = 0;
++ u8 buf[256];
++
+ #ifdef MBEDTLS_ECP_MONTGOMERY_ENABLED
+ /* len */
+ #endif
+ #ifdef MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
+- if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
+- len = inc_y ? len*2+1 : len+1;
++ if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
++ output_len = inc_y ? prime_len * 2 + 1 : prime_len + 1;
++ output_offset = 1;
++ }
+ #endif
+- struct wpabuf *buf = wpabuf_alloc(len);
+- if (buf == NULL)
++
++ if (output_len > sizeof(buf))
+ return NULL;
++
+ inc_y = inc_y ? MBEDTLS_ECP_PF_UNCOMPRESSED : MBEDTLS_ECP_PF_COMPRESSED;
+- if (mbedtls_ecp_point_write_binary(grp, &ecdh->Q, inc_y, &len,
+- wpabuf_mhead_u8(buf), len) == 0) {
+- wpabuf_put(buf, len);
+- return buf;
++ if (mbedtls_ecp_point_write_binary(grp, &ecdh->Q, inc_y, &output_len,
++ buf, output_len) == 0) {
++ return wpabuf_alloc_copy(buf + output_offset, output_len - output_offset);
+ }
+
+- wpabuf_free(buf);
+ return NULL;
+ }
+
+@@ -2379,10 +2384,7 @@ struct wpabuf * crypto_ecdh_set_peerkey(
+ os_memcpy(buf+2, key, len);
+ }
+ len >>= 1; /*(repurpose len to prime_len)*/
+- }
+- else if (key[0] == 0x02 || key[0] == 0x03) { /* (inc_y == 0) */
+- --len; /*(repurpose len to prime_len)*/
+-
++ } else { /* (inc_y == 0) */
+ /* mbedtls_ecp_point_read_binary() does not currently support
+ * MBEDTLS_ECP_PF_COMPRESSED format (buf[1] = 0x02 or 0x03)
+ * (returns MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) */
+@@ -2390,22 +2392,21 @@ struct wpabuf * crypto_ecdh_set_peerkey(
+ /* derive y, amend buf[] with y for UNCOMPRESSED format */
+ if (sizeof(buf)-2 < len*2 || len == 0)
+ return NULL;
++
+ buf[0] = (u8)(1+len*2);
+ buf[1] = 0x04;
++ os_memcpy(buf+2, key, len);
++
+ mbedtls_mpi bn;
+ mbedtls_mpi_init(&bn);
+- int ret = mbedtls_mpi_read_binary(&bn, key+1, len)
+- || crypto_mbedtls_short_weierstrass_derive_y(grp, &bn,
+- key[0] & 1)
++ int ret = mbedtls_mpi_read_binary(&bn, key, len)
++ || crypto_mbedtls_short_weierstrass_derive_y(grp, &bn, 0)
+ || mbedtls_mpi_write_binary(&bn, buf+2+len, len);
+ mbedtls_mpi_free(&bn);
+ if (ret != 0)
+ return NULL;
+ }
+
+- if (key[0] == 0) /*(repurpose len to prime_len)*/
+- len = CRYPTO_EC_plen(grp);
+-
+ if (mbedtls_ecdh_read_public(&ecdh->ctx, buf, buf[0]+1))
+ return NULL;
+ }
diff --git a/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch b/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch
new file mode 100644
index 00000000000..e967cff427e
--- /dev/null
+++ b/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch
@@ -0,0 +1,1358 @@
+From f24933dc175e0faf44a3cce3330c256a59649ca6 Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <gstrauss@gluelogic.com>
+Date: Tue, 19 Jul 2022 23:01:17 -0400
+Subject: [PATCH 4/7] tests/Makefile make run-tests with CONFIG_TLS=...
+
+add test-crypto_module.c to run crypto_module_tests()
+
+adjust some tests/hwsim/*.py for mbed TLS (work in progress)
+
+option to build and run-tests with CONFIG_TLS=internal # (default)
+$ cd tests; make clean
+$ make run-tests
+
+option to build and run-tests with CONFIG_TLS=gnutls
+$ cd tests; make clean CONFIG_TLS=gnutls
+$ make run-tests CONFIG_TLS=gnutls
+
+option to build and run-tests with CONFIG_TLS=mbedtls
+$ cd tests; make clean CONFIG_TLS=mbedtls
+$ make run-tests CONFIG_TLS=mbedtls
+
+option to build and run-tests with CONFIG_TLS=openssl
+$ cd tests; make clean CONFIG_TLS=openssl
+$ make run-tests CONFIG_TLS=openssl
+
+option to build and run-tests with CONFIG_TLS=wolfssl
+$ cd tests; make clean CONFIG_TLS=wolfssl
+$ make run-tests CONFIG_TLS=wolfssl
+
+RFE: Makefile logic for crypto objects should be centralized
+ instead of being duplicated in hostapd/Makefile,
+ wpa_supplicant/Makefile, src/crypto/Makefile,
+ tests/Makefile, ...
+
+Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
+---
+ hostapd/Makefile | 6 +
+ src/crypto/Makefile | 129 ++++++++++++++++++++-
+ src/crypto/crypto_module_tests.c | 134 ++++++++++++++++++++++
+ src/tls/Makefile | 11 ++
+ tests/Makefile | 75 +++++++++---
+ tests/hwsim/example-hostapd.config | 11 +-
+ tests/hwsim/example-wpa_supplicant.config | 12 +-
+ tests/hwsim/test_ap_eap.py | 114 +++++++++++++-----
+ tests/hwsim/test_ap_ft.py | 4 +-
+ tests/hwsim/test_authsrv.py | 9 +-
+ tests/hwsim/test_dpp.py | 19 ++-
+ tests/hwsim/test_erp.py | 16 +--
+ tests/hwsim/test_fils.py | 5 +-
+ tests/hwsim/test_pmksa_cache.py | 4 +-
+ tests/hwsim/test_sae.py | 7 ++
+ tests/hwsim/test_suite_b.py | 3 +
+ tests/hwsim/test_wpas_ctrl.py | 2 +-
+ tests/hwsim/utils.py | 8 +-
+ tests/test-crypto_module.c | 16 +++
+ tests/test-https.c | 12 +-
+ tests/test-https_server.c | 12 +-
+ wpa_supplicant/Makefile | 6 +
+ 22 files changed, 524 insertions(+), 91 deletions(-)
+ create mode 100644 tests/test-crypto_module.c
+
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -696,6 +696,7 @@ CFLAGS += -DCONFIG_TLSV12
+ endif
+
+ ifeq ($(CONFIG_TLS), wolfssl)
++CFLAGS += -DCONFIG_TLS_WOLFSSL
+ CONFIG_CRYPTO=wolfssl
+ ifdef TLS_FUNCS
+ OBJS += ../src/crypto/tls_wolfssl.o
+@@ -716,6 +717,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), openssl)
++CFLAGS += -DCONFIG_TLS_OPENSSL
+ CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
+ CONFIG_CRYPTO=openssl
+ ifdef TLS_FUNCS
+@@ -746,6 +748,7 @@ CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONF
+ endif
+
+ ifeq ($(CONFIG_TLS), mbedtls)
++CFLAGS += -DCONFIG_TLS_MBEDTLS
+ ifndef CONFIG_CRYPTO
+ CONFIG_CRYPTO=mbedtls
+ endif
+@@ -776,6 +779,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), gnutls)
++CFLAGS += -DCONFIG_TLS_GNUTLS
+ ifndef CONFIG_CRYPTO
+ # default to libgcrypt
+ CONFIG_CRYPTO=gnutls
+@@ -806,6 +810,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), internal)
++CFLAGS += -DCONFIG_TLS_INTERNAL
+ ifndef CONFIG_CRYPTO
+ CONFIG_CRYPTO=internal
+ endif
+@@ -884,6 +889,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), linux)
++CFLAGS += -DCONFIG_TLS_INTERNAL
+ OBJS += ../src/crypto/crypto_linux.o
+ ifdef TLS_FUNCS
+ OBJS += ../src/crypto/crypto_internal-rsa.o
+--- a/src/crypto/Makefile
++++ b/src/crypto/Makefile
+@@ -1,10 +1,121 @@
+-CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+-CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+-CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+ #CFLAGS += -DALL_DH_GROUPS
+ CFLAGS += -DCONFIG_SHA256
+ CFLAGS += -DCONFIG_SHA384
++CFLAGS += -DCONFIG_HMAC_SHA256_KDF
+ CFLAGS += -DCONFIG_HMAC_SHA384_KDF
++
++# crypto_module_tests.c
++CFLAGS += -DCONFIG_MODULE_TESTS
++CFLAGS += -DCONFIG_DPP
++#CFLAGS += -DCONFIG_DPP2
++#CFLAGS += -DCONFIG_DPP3
++CFLAGS += -DCONFIG_ECC
++CFLAGS += -DCONFIG_MESH
++CFLAGS += -DEAP_PSK
++CFLAGS += -DEAP_FAST
++
++ifeq ($(CONFIG_TLS),mbedtls)
++
++# (enable features for 'cd tests; make run-tests CONFIG_TLS=mbedtls')
++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
++CFLAGS += -DCONFIG_DES
++CFLAGS += -DEAP_IKEV2
++CFLAGS += -DEAP_MSCHAPv2
++CFLAGS += -DEAP_SIM
++
++LIB_OBJS = tls_mbedtls.o crypto_mbedtls.o
++LIB_OBJS+= \
++ aes-eax.o \
++ aes-siv.o \
++ dh_groups.o \
++ milenage.o \
++ ms_funcs.o
++
++else
++ifeq ($(CONFIG_TLS),openssl)
++
++# (enable features for 'cd tests; make run-tests CONFIG_TLS=openssl')
++ifndef CONFIG_TLS_DEFAULT_CIPHERS
++CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
++endif
++CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
++CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
++CFLAGS += -DEAP_TLS_OPENSSL
++
++LIB_OBJS = tls_openssl.o fips_prf_openssl.o crypto_openssl.o
++LIB_OBJS+= \
++ aes-ctr.o \
++ aes-eax.o \
++ aes-encblock.o \
++ aes-siv.o \
++ dh_groups.o \
++ milenage.o \
++ ms_funcs.o \
++ sha1-prf.o \
++ sha1-tlsprf.o \
++ sha1-tprf.o \
++ sha256-kdf.o \
++ sha256-prf.o \
++ sha256-tlsprf.o
++
++else
++ifeq ($(CONFIG_TLS),wolfssl)
++
++# (wolfssl libraries must be built with ./configure --enable-wpas)
++# (enable features for 'cd tests; make run-tests CONFIG_TLS=wolfssl')
++CFLAGS += -DWOLFSSL_DER_LOAD
++CFLAGS += -DCONFIG_DES
++
++LIB_OBJS = tls_wolfssl.o fips_prf_wolfssl.o crypto_wolfssl.o
++LIB_OBJS+= \
++ aes-ctr.o \
++ aes-eax.o \
++ aes-encblock.o \
++ aes-siv.o \
++ dh_groups.o \
++ milenage.o \
++ ms_funcs.o \
++ sha1-prf.o \
++ sha1-tlsprf.o \
++ sha1-tprf.o \
++ sha256-kdf.o \
++ sha256-prf.o \
++ sha256-tlsprf.o
++
++else
++ifeq ($(CONFIG_TLS),gnutls)
++
++# (enable features for 'cd tests; make run-tests CONFIG_TLS=gnutls')
++LIB_OBJS = tls_gnutls.o crypto_gnutls.o
++LIB_OBJS+= \
++ aes-cbc.o \
++ aes-ctr.o \
++ aes-eax.o \
++ aes-encblock.o \
++ aes-omac1.o \
++ aes-siv.o \
++ aes-unwrap.o \
++ aes-wrap.o \
++ dh_group5.o \
++ dh_groups.o \
++ milenage.o \
++ ms_funcs.o \
++ rc4.o \
++ sha1-pbkdf2.o \
++ sha1-prf.o \
++ fips_prf_internal.o \
++ sha1-internal.o \
++ sha1-tlsprf.o \
++ sha1-tprf.o \
++ sha256-kdf.o \
++ sha256-prf.o \
++ sha256-tlsprf.o
++
++else
++
++CFLAGS += -DCONFIG_CRYPTO_INTERNAL
++CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
++CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+ CFLAGS += -DCONFIG_INTERNAL_SHA384
+
+ LIB_OBJS= \
+@@ -13,7 +124,6 @@ LIB_OBJS= \
+ aes-ctr.o \
+ aes-eax.o \
+ aes-encblock.o \
+- aes-gcm.o \
+ aes-internal.o \
+ aes-internal-dec.o \
+ aes-internal-enc.o \
+@@ -37,6 +147,7 @@ LIB_OBJS= \
+ sha1-tlsprf.o \
+ sha1-tprf.o \
+ sha256.o \
++ sha256-kdf.o \
+ sha256-prf.o \
+ sha256-tlsprf.o \
+ sha256-internal.o \
+@@ -53,6 +164,16 @@ LIB_OBJS += crypto_internal-modexp.o
+ LIB_OBJS += crypto_internal-rsa.o
+ LIB_OBJS += tls_internal.o
+ LIB_OBJS += fips_prf_internal.o
++
++endif
++endif
++endif
++endif
++
++
++# (used by wlantest/{bip,gcmp,rx_mgmt}.c and tests/test-aes.c)
++LIB_OBJS += aes-gcm.o
++
+ ifndef TEST_FUZZ
+ LIB_OBJS += random.o
+ endif
+--- a/src/crypto/crypto_module_tests.c
++++ b/src/crypto/crypto_module_tests.c
+@@ -2469,6 +2469,139 @@ static int test_hpke(void)
+ }
+
+
++static int test_ecc(void)
++{
++#ifdef CONFIG_ECC
++#ifndef CONFIG_TLS_INTERNAL
++#ifndef CONFIG_TLS_GNUTLS
++#if defined(CONFIG_TLS_MBEDTLS) \
++ || defined(CONFIG_TLS_OPENSSL) \
++ || defined(CONFIG_TLS_WOLFSSL)
++ wpa_printf(MSG_INFO, "Testing ECC");
++ /* Note: some tests below are valid on supported Short Weierstrass
++ * curves, but not on Montgomery curves (e.g. IKE groups 31 and 32)
++ * (e.g. deriving and comparing y^2 test below not valid on Montgomery)
++ */
++#ifdef CONFIG_TLS_MBEDTLS
++ const int grps[] = {19, 20, 21, 25, 26, 28};
++#endif
++#ifdef CONFIG_TLS_OPENSSL
++ const int grps[] = {19, 20, 21, 26};
++#endif
++#ifdef CONFIG_TLS_WOLFSSL
++ const int grps[] = {19, 20, 21, 26};
++#endif
++ uint32_t i;
++ struct crypto_ec *e = NULL;
++ struct crypto_ec_point *p = NULL, *q = NULL;
++ struct crypto_bignum *x = NULL, *y = NULL;
++#ifdef CONFIG_DPP
++ u8 bin[4096];
++#endif
++ for (i = 0; i < ARRAY_SIZE(grps); ++i) {
++ e = crypto_ec_init(grps[i]);
++ if (e == NULL
++ || crypto_ec_prime_len(e) == 0
++ || crypto_ec_prime_len_bits(e) == 0
++ || crypto_ec_order_len(e) == 0
++ || crypto_ec_get_prime(e) == NULL
++ || crypto_ec_get_order(e) == NULL
++ || crypto_ec_get_a(e) == NULL
++ || crypto_ec_get_b(e) == NULL
++ || crypto_ec_get_generator(e) == NULL) {
++ break;
++ }
++#ifdef CONFIG_DPP
++ struct crypto_ec_key *key = crypto_ec_key_gen(grps[i]);
++ if (key == NULL)
++ break;
++ p = crypto_ec_key_get_public_key(key);
++ q = crypto_ec_key_get_public_key(key);
++ crypto_ec_key_deinit(key);
++ if (p == NULL || q == NULL)
++ break;
++ if (!crypto_ec_point_is_on_curve(e, p))
++ break;
++
++ /* inverted point should not match original;
++ * double-invert should match */
++ if (crypto_ec_point_invert(e, q) != 0
++ || crypto_ec_point_cmp(e, p, q) == 0
++ || crypto_ec_point_invert(e, q) != 0
++ || crypto_ec_point_cmp(e, p, q) != 0) {
++ break;
++ }
++
++ /* crypto_ec_point_to_bin() and crypto_ec_point_from_bin()
++ * imbalanced interfaces? */
++ size_t prime_len = crypto_ec_prime_len(e);
++ if (prime_len * 2 > sizeof(bin))
++ break;
++ if (crypto_ec_point_to_bin(e, p, bin, bin+prime_len) != 0)
++ break;
++ struct crypto_ec_point *tmp = crypto_ec_point_from_bin(e, bin);
++ if (tmp == NULL)
++ break;
++ if (crypto_ec_point_cmp(e, p, tmp) != 0) {
++ crypto_ec_point_deinit(tmp, 0);
++ break;
++ }
++ crypto_ec_point_deinit(tmp, 0);
++
++ x = crypto_bignum_init();
++ y = crypto_bignum_init_set(bin+prime_len, prime_len);
++ if (x == NULL || y == NULL || crypto_ec_point_x(e, p, x) != 0)
++ break;
++ struct crypto_bignum *y2 = crypto_ec_point_compute_y_sqr(e, x);
++ if (y2 == NULL)
++ break;
++ if (crypto_bignum_sqrmod(y, crypto_ec_get_prime(e), y) != 0
++ || crypto_bignum_cmp(y, y2) != 0) {
++ crypto_bignum_deinit(y2, 0);
++ break;
++ }
++ crypto_bignum_deinit(y2, 0);
++ crypto_bignum_deinit(x, 0);
++ crypto_bignum_deinit(y, 0);
++ x = NULL;
++ y = NULL;
++
++ x = crypto_bignum_init();
++ if (x == NULL)
++ break;
++ if (crypto_bignum_rand(x, crypto_ec_get_prime(e)) != 0)
++ break;
++ crypto_bignum_deinit(x, 0);
++ x = NULL;
++
++ crypto_ec_point_deinit(p, 0);
++ p = NULL;
++ crypto_ec_point_deinit(q, 0);
++ q = NULL;
++#endif /* CONFIG_DPP */
++ crypto_ec_deinit(e);
++ e = NULL;
++ }
++ if (i != ARRAY_SIZE(grps)) {
++ crypto_bignum_deinit(x, 0);
++ crypto_bignum_deinit(y, 0);
++ crypto_ec_point_deinit(p, 0);
++ crypto_ec_point_deinit(q, 0);
++ crypto_ec_deinit(e);
++ wpa_printf(MSG_INFO,
++ "ECC test case failed tls_id:%d", grps[i]);
++ return -1;
++ }
++
++ wpa_printf(MSG_INFO, "ECC test cases passed");
++#endif
++#endif /* !CONFIG_TLS_GNUTLS */
++#endif /* !CONFIG_TLS_INTERNAL */
++#endif /* CONFIG_ECC */
++ return 0;
++}
++
++
+ static int test_ms_funcs(void)
+ {
+ #ifndef CONFIG_FIPS
+@@ -2590,6 +2723,7 @@ int crypto_module_tests(void)
+ test_fips186_2_prf() ||
+ test_extract_expand_hkdf() ||
+ test_hpke() ||
++ test_ecc() ||
+ test_ms_funcs())
+ ret = -1;
+
+--- a/src/tls/Makefile
++++ b/src/tls/Makefile
+@@ -1,3 +1,10 @@
++LIB_OBJS= asn1.o
++
++ifneq ($(CONFIG_TLS),gnutls)
++ifneq ($(CONFIG_TLS),mbedtls)
++ifneq ($(CONFIG_TLS),openssl)
++ifneq ($(CONFIG_TLS),wolfssl)
++
+ CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ CFLAGS += -DCONFIG_TLSV11
+@@ -21,5 +28,9 @@ LIB_OBJS= \
+ tlsv1_server_read.o \
+ tlsv1_server_write.o \
+ x509v3.o
++endif
++endif
++endif
++endif
+
+ include ../lib.rules
+--- a/tests/Makefile
++++ b/tests/Makefile
+@@ -1,8 +1,10 @@
+-ALL=test-base64 test-md4 test-milenage \
+- test-rsa-sig-ver \
+- test-sha1 \
+- test-https test-https_server \
+- test-sha256 test-aes test-x509v3 test-list test-rc4
++RUN_TESTS= \
++ test-list \
++ test-md4 test-rc4 test-sha1 test-sha256 \
++ test-milenage test-aes \
++ test-crypto_module
++
++ALL=$(RUN_TESTS) test-base64 test-https test-https_server
+
+ include ../src/build.rules
+
+@@ -24,13 +26,27 @@ CFLAGS += -DCONFIG_IEEE80211R_AP
+ CFLAGS += -DCONFIG_IEEE80211R
+ CFLAGS += -DCONFIG_TDLS
+
++# test-crypto_module
++CFLAGS += -DCONFIG_MODULE_TESTS
++CFLAGS += -DCONFIG_DPP
++#CFLAGS += -DCONFIG_DPP2
++#CFLAGS += -DCONFIG_DPP3
++CFLAGS += -DCONFIG_ECC
++CFLAGS += -DCONFIG_HMAC_SHA256_KDF
++CFLAGS += -DCONFIG_HMAC_SHA384_KDF
++CFLAGS += -DCONFIG_MESH
++CFLAGS += -DCONFIG_SHA256
++CFLAGS += -DCONFIG_SHA384
++CFLAGS += -DEAP_PSK
++CFLAGS += -DEAP_FAST
++
+ CFLAGS += -I../src
+ CFLAGS += -I../src/utils
+
+ SLIBS = ../src/utils/libutils.a
+
+-DLIBS = ../src/crypto/libcrypto.a \
+- ../src/tls/libtls.a
++DLIBS = ../src/tls/libtls.a \
++ ../src/crypto/libcrypto.a
+
+ _OBJS_VAR := LLIBS
+ include ../src/objs.mk
+@@ -42,12 +58,43 @@ include ../src/objs.mk
+ LIBS = $(SLIBS) $(DLIBS)
+ LLIBS = -Wl,--start-group $(DLIBS) -Wl,--end-group $(SLIBS)
+
++ifeq ($(CONFIG_TLS),mbedtls)
++CFLAGS += -DCONFIG_TLS_MBEDTLS
++LLIBS += -lmbedtls -lmbedx509 -lmbedcrypto
++else
++ifeq ($(CONFIG_TLS),openssl)
++CFLAGS += -DCONFIG_TLS_OPENSSL
++LLIBS += -lssl -lcrypto
++else
++ifeq ($(CONFIG_TLS),gnutls)
++CFLAGS += -DCONFIG_TLS_GNUTLS
++LLIBS += -lgnutls -lgpg-error -lgcrypt
++else
++ifeq ($(CONFIG_TLS),wolfssl)
++CFLAGS += -DCONFIG_TLS_WOLFSSL
++LLIBS += -lwolfssl -lm
++else
++CFLAGS += -DCONFIG_TLS_INTERNAL
++CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
++ALL += test-rsa-sig-ver
++ALL += test-x509v3
++clean-config_tls_internal:
++ rm -f test_x509v3_nist.out.*
++ rm -f test_x509v3_nist2.out.*
++endif
++endif
++endif
++endif
++
+ # glibc < 2.17 needs -lrt for clock_gettime()
+ LLIBS += -lrt
+
+ test-aes: $(call BUILDOBJ,test-aes.o) $(LIBS)
+ $(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
+
++test-crypto_module: $(call BUILDOBJ,test-crypto_module.o) $(LIBS)
++ $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
++
+ test-base64: $(call BUILDOBJ,test-base64.o) $(LIBS)
+ $(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
+
+@@ -83,17 +130,11 @@ test-x509v3: $(call BUILDOBJ,test-x509v3
+
+
+ run-tests: $(ALL)
+- ./test-aes
+- ./test-list
+- ./test-md4
+- ./test-milenage
+- ./test-rsa-sig-ver
+- ./test-sha1
+- ./test-sha256
++ @set -ex; for i in $(RUN_TESTS); do ./$$i; done
+ @echo
+ @echo All tests completed successfully.
+
+-clean: common-clean
++clean: common-clean clean-config_tls_internal
+ rm -f *~
+- rm -f test_x509v3_nist.out.*
+- rm -f test_x509v3_nist2.out.*
++
++.PHONY: run-tests clean-config_tls_internal
+--- a/tests/hwsim/example-hostapd.config
++++ b/tests/hwsim/example-hostapd.config
+@@ -34,15 +34,7 @@ CONFIG_EAP_TNC=y
+ CFLAGS += -DTNC_CONFIG_FILE=\"tnc/tnc_config\"
+ LIBS += -rdynamic
+ CONFIG_EAP_UNAUTH_TLS=y
+-ifeq ($(CONFIG_TLS), openssl)
+-CONFIG_EAP_PWD=y
+-endif
+-ifeq ($(CONFIG_TLS), wolfssl)
+-CONFIG_EAP_PWD=y
+-endif
+-ifeq ($(CONFIG_TLS), mbedtls)
+-CONFIG_EAP_PWD=y
+-endif
++CONFIG_EAP_PWD=$(if $(filter openssl wolfssl mbedtls,$(CONFIG_TLS)),y,)
+ CONFIG_EAP_EKE=y
+ CONFIG_PKCS12=y
+ CONFIG_RADIUS_SERVER=y
+@@ -89,6 +81,7 @@ CFLAGS += -DCONFIG_RADIUS_TEST
+ CONFIG_MODULE_TESTS=y
+
+ CONFIG_SUITEB=y
++CONFIG_SUITEB192=$(if $(filter openssl mbedtls,$(CONFIG_TLS)),y,)
+
+ # AddressSanitizer (ASan) can be enabled by uncommenting the following lines.
+ # This can be used as a more efficient memory error detector than valgrind
+--- a/tests/hwsim/example-wpa_supplicant.config
++++ b/tests/hwsim/example-wpa_supplicant.config
+@@ -35,16 +35,7 @@ LIBS += -rdynamic
+ CONFIG_EAP_FAST=y
+ CONFIG_EAP_TEAP=y
+ CONFIG_EAP_IKEV2=y
+-
+-ifeq ($(CONFIG_TLS), openssl)
+-CONFIG_EAP_PWD=y
+-endif
+-ifeq ($(CONFIG_TLS), wolfssl)
+-CONFIG_EAP_PWD=y
+-endif
+-ifeq ($(CONFIG_TLS), mbedtls)
+-CONFIG_EAP_PWD=y
+-endif
++CONFIG_EAP_PWD=$(if $(filter openssl wolfssl mbedtls,$(CONFIG_TLS)),y,)
+
+ CONFIG_USIM_SIMULATOR=y
+ CONFIG_SIM_SIMULATOR=y
+@@ -137,6 +128,7 @@ CONFIG_TESTING_OPTIONS=y
+ CONFIG_MODULE_TESTS=y
+
+ CONFIG_SUITEB=y
++CONFIG_SUITEB192=$(if $(filter openssl mbedtls,$(CONFIG_TLS)),y,)
+
+ # AddressSanitizer (ASan) can be enabled by uncommenting the following lines.
+ # This can be used as a more efficient memory error detector than valgrind
+--- a/tests/hwsim/test_ap_eap.py
++++ b/tests/hwsim/test_ap_eap.py
+@@ -42,20 +42,42 @@ def check_eap_capa(dev, method):
+ res = dev.get_capability("eap")
+ if method not in res:
+ raise HwsimSkip("EAP method %s not supported in the build" % method)
++ if method == "FAST" or method == "TEAP":
++ tls = dev.request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("EAP-%s not supported with this TLS library: " % method + tls)
+
+ def check_subject_match_support(dev):
+ tls = dev.request("GET tls_library")
+- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
++ if tls.startswith("OpenSSL"):
++ return
++ elif tls.startswith("wolfSSL"):
++ return
++ elif tls.startswith("mbed TLS"):
++ return
++ else:
+ raise HwsimSkip("subject_match not supported with this TLS library: " + tls)
+
+ def check_check_cert_subject_support(dev):
+ tls = dev.request("GET tls_library")
+- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
++ if tls.startswith("OpenSSL"):
++ return
++ elif tls.startswith("wolfSSL"):
++ return
++ elif tls.startswith("mbed TLS"):
++ return
++ else:
+ raise HwsimSkip("check_cert_subject not supported with this TLS library: " + tls)
+
+ def check_altsubject_match_support(dev):
+ tls = dev.request("GET tls_library")
+- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
++ if tls.startswith("OpenSSL"):
++ return
++ elif tls.startswith("wolfSSL"):
++ return
++ elif tls.startswith("mbed TLS"):
++ return
++ else:
+ raise HwsimSkip("altsubject_match not supported with this TLS library: " + tls)
+
+ def check_domain_match(dev):
+@@ -70,7 +92,13 @@ def check_domain_suffix_match(dev):
+
+ def check_domain_match_full(dev):
+ tls = dev.request("GET tls_library")
+- if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
++ if tls.startswith("OpenSSL"):
++ return
++ elif tls.startswith("wolfSSL"):
++ return
++ elif tls.startswith("mbed TLS"):
++ return
++ else:
+ raise HwsimSkip("domain_suffix_match requires full match with this TLS library: " + tls)
+
+ def check_cert_probe_support(dev):
+@@ -79,8 +107,15 @@ def check_cert_probe_support(dev):
+ raise HwsimSkip("Certificate probing not supported with this TLS library: " + tls)
+
+ def check_ext_cert_check_support(dev):
++ if not openssl_imported:
++ raise HwsimSkip("OpenSSL python method not available")
++
+ tls = dev.request("GET tls_library")
+- if not tls.startswith("OpenSSL"):
++ if tls.startswith("OpenSSL"):
++ return
++ elif tls.startswith("mbed TLS"):
++ return
++ else:
+ raise HwsimSkip("ext_cert_check not supported with this TLS library: " + tls)
+
+ def check_ocsp_support(dev):
+@@ -91,14 +126,18 @@ def check_ocsp_support(dev):
+ # raise HwsimSkip("OCSP not supported with this TLS library: " + tls)
+ #if tls.startswith("wolfSSL"):
+ # raise HwsimSkip("OCSP not supported with this TLS library: " + tls)
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("OCSP not supported with this TLS library: " + tls)
+
+ def check_pkcs5_v15_support(dev):
+ tls = dev.request("GET tls_library")
+- if "BoringSSL" in tls or "GnuTLS" in tls:
++ if "BoringSSL" in tls or "GnuTLS" in tls or "mbed TLS" in tls:
+ raise HwsimSkip("PKCS#5 v1.5 not supported with this TLS library: " + tls)
+
+ def check_tls13_support(dev):
+ tls = dev.request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("TLS v1.3 not supported")
+ if "run=OpenSSL 1.1.1" not in tls and "run=OpenSSL 3.0" not in tls and "wolfSSL" not in tls:
+ raise HwsimSkip("TLS v1.3 not supported")
+
+@@ -118,11 +157,15 @@ def check_pkcs12_support(dev):
+ # raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls)
+ if tls.startswith("wolfSSL"):
+ raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls)
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls)
+
+ def check_dh_dsa_support(dev):
+ tls = dev.request("GET tls_library")
+ if tls.startswith("internal"):
+ raise HwsimSkip("DH DSA not supported with this TLS library: " + tls)
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("DH DSA not supported with this TLS library: " + tls)
+
+ def check_ec_support(dev):
+ tls = dev.request("GET tls_library")
+@@ -1595,7 +1638,7 @@ def test_ap_wpa2_eap_ttls_pap_subject_ma
+ eap_connect(dev[0], hapd, "TTLS", "pap user",
+ anonymous_identity="ttls", password="password",
+ ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+- subject_match="/C=FI/O=w1.fi/CN=server.w1.fi",
++ check_cert_subject="/C=FI/O=w1.fi/CN=server.w1.fi",
+ altsubject_match="EMAIL:noone@example.com;DNS:server.w1.fi;URI:http://example.com/")
+ eap_reauth(dev[0], "TTLS")
+
+@@ -2830,6 +2873,7 @@ def test_ap_wpa2_eap_tls_neg_domain_matc
+
+ def test_ap_wpa2_eap_tls_neg_subject_match(dev, apdev):
+ """WPA2-Enterprise negative test - subject mismatch"""
++ check_subject_match_support(dev[0])
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hostapd.add_ap(apdev[0], params)
+ dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+@@ -2890,6 +2934,7 @@ def test_ap_wpa2_eap_tls_neg_subject_mat
+
+ def test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev):
+ """WPA2-Enterprise negative test - altsubject mismatch"""
++ check_altsubject_match_support(dev[0])
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hostapd.add_ap(apdev[0], params)
+
+@@ -3430,7 +3475,7 @@ def test_ap_wpa2_eap_ikev2_oom(dev, apde
+ dev[0].request("REMOVE_NETWORK all")
+
+ tls = dev[0].request("GET tls_library")
+- if not tls.startswith("wolfSSL"):
++ if not tls.startswith("wolfSSL") and not tls.startswith("mbed TLS"):
+ tests = [(1, "os_get_random;dh_init")]
+ else:
+ tests = [(1, "crypto_dh_init;dh_init")]
+@@ -4744,7 +4789,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca
+ params["private_key"] = "auth_serv/iCA-server/server.key"
+ hostapd.add_ap(apdev[0], params)
+ tls = dev[0].request("GET tls_library")
+- if "GnuTLS" in tls or "wolfSSL" in tls:
++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls:
+ ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
+ client_cert = "auth_serv/iCA-user/user_and_ica.pem"
+ else:
+@@ -4810,6 +4855,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca
+ run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, "-sha1")
+
+ def run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, md):
++ check_ocsp_support(dev[0])
+ params = int_eap_server_params()
+ params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+ params["server_cert"] = "auth_serv/iCA-server/server.pem"
+@@ -4819,7 +4865,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_
+ try:
+ hostapd.add_ap(apdev[0], params)
+ tls = dev[0].request("GET tls_library")
+- if "GnuTLS" in tls or "wolfSSL" in tls:
++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls:
+ ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
+ client_cert = "auth_serv/iCA-user/user_and_ica.pem"
+ else:
+@@ -4855,7 +4901,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_
+ try:
+ hostapd.add_ap(apdev[0], params)
+ tls = dev[0].request("GET tls_library")
+- if "GnuTLS" in tls or "wolfSSL" in tls:
++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls:
+ ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
+ client_cert = "auth_serv/iCA-user/user_and_ica.pem"
+ else:
+@@ -4905,7 +4951,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca
+ try:
+ hostapd.add_ap(apdev[0], params)
+ tls = dev[0].request("GET tls_library")
+- if "GnuTLS" in tls or "wolfSSL" in tls:
++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls:
+ ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
+ client_cert = "auth_serv/iCA-user/user_and_ica.pem"
+ else:
+@@ -4972,7 +5018,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca
+
+ hostapd.add_ap(apdev[0], params)
+ tls = dev[0].request("GET tls_library")
+- if "GnuTLS" in tls or "wolfSSL" in tls:
++ if "GnuTLS" in tls or "wolfSSL" in tls or "mbed TLS" in tls:
+ ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
+ client_cert = "auth_serv/iCA-user/user_and_ica.pem"
+ else:
+@@ -5230,6 +5276,7 @@ def test_ap_wpa2_eap_ttls_server_cert_ek
+
+ def test_ap_wpa2_eap_ttls_server_pkcs12(dev, apdev):
+ """WPA2-Enterprise using EAP-TTLS and server PKCS#12 file"""
++ check_pkcs12_support(dev[0])
+ skip_with_fips(dev[0])
+ params = int_eap_server_params()
+ del params["server_cert"]
+@@ -5242,6 +5289,7 @@ def test_ap_wpa2_eap_ttls_server_pkcs12(
+
+ def test_ap_wpa2_eap_ttls_server_pkcs12_extra(dev, apdev):
+ """EAP-TTLS and server PKCS#12 file with extra certs"""
++ check_pkcs12_support(dev[0])
+ skip_with_fips(dev[0])
+ params = int_eap_server_params()
+ del params["server_cert"]
+@@ -5264,6 +5312,7 @@ def test_ap_wpa2_eap_ttls_dh_params_serv
+
+ def test_ap_wpa2_eap_ttls_dh_params_dsa_server(dev, apdev):
+ """WPA2-Enterprise using EAP-TTLS and alternative server dhparams (DSA)"""
++ check_dh_dsa_support(dev[0])
+ params = int_eap_server_params()
+ params["dh_file"] = "auth_serv/dsaparam.pem"
+ hapd = hostapd.add_ap(apdev[0], params)
+@@ -5575,8 +5624,8 @@ def test_ap_wpa2_eap_non_ascii_identity2
+ def test_openssl_cipher_suite_config_wpas(dev, apdev):
+ """OpenSSL cipher suite configuration on wpa_supplicant"""
+ tls = dev[0].request("GET tls_library")
+- if not tls.startswith("OpenSSL"):
+- raise HwsimSkip("TLS library is not OpenSSL: " + tls)
++ if not tls.startswith("OpenSSL") and not tls.startswith("mbed TLS"):
++ raise HwsimSkip("TLS library is not OpenSSL or mbed TLS: " + tls)
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hapd = hostapd.add_ap(apdev[0], params)
+ eap_connect(dev[0], hapd, "TTLS", "pap user",
+@@ -5602,14 +5651,14 @@ def test_openssl_cipher_suite_config_wpa
+ def test_openssl_cipher_suite_config_hapd(dev, apdev):
+ """OpenSSL cipher suite configuration on hostapd"""
+ tls = dev[0].request("GET tls_library")
+- if not tls.startswith("OpenSSL"):
+- raise HwsimSkip("wpa_supplicant TLS library is not OpenSSL: " + tls)
++ if not tls.startswith("OpenSSL") and not tls.startswith("mbed TLS"):
++ raise HwsimSkip("wpa_supplicant TLS library is not OpenSSL or mbed TLS: " + tls)
+ params = int_eap_server_params()
+ params['openssl_ciphers'] = "AES256"
+ hapd = hostapd.add_ap(apdev[0], params)
+ tls = hapd.request("GET tls_library")
+- if not tls.startswith("OpenSSL"):
+- raise HwsimSkip("hostapd TLS library is not OpenSSL: " + tls)
++ if not tls.startswith("OpenSSL") and not tls.startswith("mbed TLS"):
++ raise HwsimSkip("hostapd TLS library is not OpenSSL or mbed TLS: " + tls)
+ eap_connect(dev[0], hapd, "TTLS", "pap user",
+ anonymous_identity="ttls", password="password",
+ ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
+@@ -6051,13 +6100,17 @@ def test_ap_wpa2_eap_tls_versions(dev, a
+ check_tls_ver(dev[0], hapd,
+ "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1",
+ "TLSv1.2")
+- elif tls.startswith("internal"):
++ elif tls.startswith("internal") or tls.startswith("mbed TLS"):
+ check_tls_ver(dev[0], hapd,
+ "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", "TLSv1.2")
+- check_tls_ver(dev[1], hapd,
+- "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=0 tls_disable_tlsv1_2=1", "TLSv1.1")
+- check_tls_ver(dev[2], hapd,
+- "tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1")
++ if tls.startswith("mbed TLS"):
++ check_tls_ver(dev[2], hapd,
++ "tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1.0")
++ else:
++ check_tls_ver(dev[1], hapd,
++ "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=0 tls_disable_tlsv1_2=1", "TLSv1.1")
++ check_tls_ver(dev[2], hapd,
++ "tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1")
+ if "run=OpenSSL 1.1.1" in tls or "run=OpenSSL 3.0" in tls:
+ check_tls_ver(dev[0], hapd,
+ "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1 tls_disable_tlsv1_3=0", "TLSv1.3")
+@@ -6079,6 +6132,11 @@ def test_ap_wpa2_eap_tls_versions_server
+ tests = [("TLSv1", "[ENABLE-TLSv1.0][DISABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"),
+ ("TLSv1.1", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"),
+ ("TLSv1.2", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][ENABLE-TLSv1.2][DISABLE-TLSv1.3]")]
++ tls = dev[0].request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ tests = [#("TLSv1.0", "[ENABLE-TLSv1.0][DISABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"),
++ #("TLSv1.1", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][DISABLE-TLSv1.2][DISABLE-TLSv1.3]"),
++ ("TLSv1.2", "[ENABLE-TLSv1.0][ENABLE-TLSv1.1][ENABLE-TLSv1.2][DISABLE-TLSv1.3]")]
+ for exp, flags in tests:
+ hapd.disable()
+ hapd.set("tls_flags", flags)
+@@ -7138,6 +7196,7 @@ def test_ap_wpa2_eap_assoc_rsn(dev, apde
+ def test_eap_tls_ext_cert_check(dev, apdev):
+ """EAP-TLS and external server certification validation"""
+ # With internal server certificate chain validation
++ check_ext_cert_check_support(dev[0])
+ id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+ identity="tls user",
+ ca_cert="auth_serv/ca.pem",
+@@ -7150,6 +7209,7 @@ def test_eap_tls_ext_cert_check(dev, apd
+ def test_eap_ttls_ext_cert_check(dev, apdev):
+ """EAP-TTLS and external server certification validation"""
+ # Without internal server certificate chain validation
++ check_ext_cert_check_support(dev[0])
+ id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+ identity="pap user", anonymous_identity="ttls",
+ password="password", phase2="auth=PAP",
+@@ -7160,6 +7220,7 @@ def test_eap_ttls_ext_cert_check(dev, ap
+ def test_eap_peap_ext_cert_check(dev, apdev):
+ """EAP-PEAP and external server certification validation"""
+ # With internal server certificate chain validation
++ check_ext_cert_check_support(dev[0])
+ id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP",
+ identity="user", anonymous_identity="peap",
+ ca_cert="auth_serv/ca.pem",
+@@ -7170,6 +7231,7 @@ def test_eap_peap_ext_cert_check(dev, ap
+
+ def test_eap_fast_ext_cert_check(dev, apdev):
+ """EAP-FAST and external server certification validation"""
++ check_ext_cert_check_support(dev[0])
+ check_eap_capa(dev[0], "FAST")
+ # With internal server certificate chain validation
+ dev[0].request("SET blob fast_pac_auth_ext ")
+@@ -7184,10 +7246,6 @@ def test_eap_fast_ext_cert_check(dev, ap
+ run_ext_cert_check(dev, apdev, id)
+
+ def run_ext_cert_check(dev, apdev, net_id):
+- check_ext_cert_check_support(dev[0])
+- if not openssl_imported:
+- raise HwsimSkip("OpenSSL python method not available")
+-
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+--- a/tests/hwsim/test_ap_ft.py
++++ b/tests/hwsim/test_ap_ft.py
+@@ -2474,11 +2474,11 @@ def test_ap_ft_ap_oom5(dev, apdev):
+ # This will fail to roam
+ dev[0].roam(bssid1, check_bssid=False)
+
+- with fail_test(hapd1, 1, "sha256_prf_bits;wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"):
++ with fail_test(hapd1, 1, "sha256_prf;wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"):
+ # This will fail to roam
+ dev[0].roam(bssid1, check_bssid=False)
+
+- with fail_test(hapd1, 3, "wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"):
++ with fail_test(hapd1, 2, "wpa_pmk_r1_to_ptk;wpa_ft_process_auth_req"):
+ # This will fail to roam
+ dev[0].roam(bssid1, check_bssid=False)
+
+--- a/tests/hwsim/test_authsrv.py
++++ b/tests/hwsim/test_authsrv.py
+@@ -156,9 +156,12 @@ def test_authsrv_oom(dev, apdev):
+ if "FAIL" not in authsrv.request("ENABLE"):
+ raise Exception("ENABLE succeeded during OOM")
+
+- with alloc_fail(authsrv, 1, "tls_init;authsrv_init"):
+- if "FAIL" not in authsrv.request("ENABLE"):
+- raise Exception("ENABLE succeeded during OOM")
++ # tls_mbedtls.c:tls_init() does not alloc memory (no alloc fail trigger)
++ tls = dev[0].request("GET tls_library")
++ if not tls.startswith("mbed TLS"):
++ with alloc_fail(authsrv, 1, "tls_init;authsrv_init"):
++ if "FAIL" not in authsrv.request("ENABLE"):
++ raise Exception("ENABLE succeeded during OOM")
+
+ for count in range(1, 3):
+ with alloc_fail(authsrv, count, "eap_sim_db_init;authsrv_init"):
+--- a/tests/hwsim/test_dpp.py
++++ b/tests/hwsim/test_dpp.py
+@@ -39,7 +39,8 @@ def check_dpp_capab(dev, brainpool=False
+ raise HwsimSkip("DPP not supported")
+ if brainpool:
+ tls = dev.request("GET tls_library")
+- if (not tls.startswith("OpenSSL") or "run=BoringSSL" in tls) and not tls.startswith("wolfSSL"):
++ if (not tls.startswith("OpenSSL") or "run=BoringSSL" in tls) and not tls.startswith("wolfSSL") \
++ and not tls.startswith("mbed TLS"):
+ raise HwsimSkip("Crypto library does not support Brainpool curves: " + tls)
+ capa = dev.request("GET_CAPABILITY dpp")
+ ver = 1
+@@ -3892,6 +3893,9 @@ def test_dpp_proto_auth_req_no_i_proto_k
+
+ def test_dpp_proto_auth_req_invalid_i_proto_key(dev, apdev):
+ """DPP protocol testing - invalid I-proto key in Auth Req"""
++ tls = dev[0].request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key; no response")
+ run_dpp_proto_auth_req_missing(dev, 66, "Invalid Initiator Protocol Key")
+
+ def test_dpp_proto_auth_req_no_i_nonce(dev, apdev):
+@@ -3987,7 +3991,12 @@ def test_dpp_proto_auth_resp_no_r_proto_
+
+ def test_dpp_proto_auth_resp_invalid_r_proto_key(dev, apdev):
+ """DPP protocol testing - invalid R-Proto Key in Auth Resp"""
+- run_dpp_proto_auth_resp_missing(dev, 67, "Invalid Responder Protocol Key")
++ tls = dev[0].request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ # mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key
++ run_dpp_proto_auth_resp_missing(dev, 67, "Failed to derive ECDH shared secret")
++ else:
++ run_dpp_proto_auth_resp_missing(dev, 67, "Invalid Responder Protocol Key")
+
+ def test_dpp_proto_auth_resp_no_r_nonce(dev, apdev):
+ """DPP protocol testing - no R-nonce in Auth Resp"""
+@@ -4349,11 +4358,17 @@ def test_dpp_proto_pkex_exchange_resp_in
+
+ def test_dpp_proto_pkex_cr_req_invalid_bootstrap_key(dev, apdev):
+ """DPP protocol testing - invalid Bootstrap Key in PKEX Commit-Reveal Request"""
++ tls = dev[0].request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key; no response")
+ run_dpp_proto_pkex_req_missing(dev, 47,
+ "Peer bootstrapping key is invalid")
+
+ def test_dpp_proto_pkex_cr_resp_invalid_bootstrap_key(dev, apdev):
+ """DPP protocol testing - invalid Bootstrap Key in PKEX Commit-Reveal Response"""
++ tls = dev[0].request("GET tls_library")
++ if tls.startswith("mbed TLS"):
++ raise HwsimSkip("mbed TLS crypto_ecdh_set_peerkey() properly detects invalid key; no response")
+ run_dpp_proto_pkex_resp_missing(dev, 48,
+ "Peer bootstrapping key is invalid")
+
+--- a/tests/hwsim/test_erp.py
++++ b/tests/hwsim/test_erp.py
+@@ -12,7 +12,7 @@ import time
+
+ import hostapd
+ from utils import *
+-from test_ap_eap import int_eap_server_params, check_tls13_support
++from test_ap_eap import int_eap_server_params, check_tls13_support, check_eap_capa
+ from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
+
+ def test_erp_initiate_reauth_start(dev, apdev):
+@@ -276,6 +276,7 @@ def test_erp_radius_eap_methods(dev, apd
+ params['erp_domain'] = 'example.com'
+ params['disable_pmksa_caching'] = '1'
+ hapd = hostapd.add_ap(apdev[0], params)
++ tls = dev[0].request("GET tls_library")
+
+ erp_test(dev[0], hapd, eap="AKA", identity="0232010000000000@example.com",
+ password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
+@@ -289,7 +290,7 @@ def test_erp_radius_eap_methods(dev, apd
+ password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
+ erp_test(dev[0], hapd, eap="EKE", identity="erp-eke@example.com",
+ password="hello")
+- if "FAST" in eap_methods:
++ if "FAST" in eap_methods and check_eap_capa(dev[0], "FAST"):
+ erp_test(dev[0], hapd, eap="FAST", identity="erp-fast@example.com",
+ password="password", ca_cert="auth_serv/ca.pem",
+ phase2="auth=GTC",
+@@ -301,13 +302,14 @@ def test_erp_radius_eap_methods(dev, apd
+ password="password")
+ erp_test(dev[0], hapd, eap="PAX", identity="erp-pax@example.com",
+ password_hex="0123456789abcdef0123456789abcdef")
+- if "MSCHAPV2" in eap_methods:
++ if "MSCHAPV2" in eap_methods and check_eap_capa(dev[0], "MSCHAPV2"):
+ erp_test(dev[0], hapd, eap="PEAP", identity="erp-peap@example.com",
+ password="password", ca_cert="auth_serv/ca.pem",
+ phase2="auth=MSCHAPV2")
+- erp_test(dev[0], hapd, eap="TEAP", identity="erp-teap@example.com",
+- password="password", ca_cert="auth_serv/ca.pem",
+- phase2="auth=MSCHAPV2", pac_file="blob://teap_pac")
++ if check_eap_capa(dev[0], "TEAP"):
++ erp_test(dev[0], hapd, eap="TEAP", identity="erp-teap@example.com",
++ password="password", ca_cert="auth_serv/ca.pem",
++ phase2="auth=MSCHAPV2", pac_file="blob://teap_pac")
+ erp_test(dev[0], hapd, eap="PSK", identity="erp-psk@example.com",
+ password_hex="0123456789abcdef0123456789abcdef")
+ if "PWD" in eap_methods:
+@@ -640,7 +642,7 @@ def test_erp_local_errors(dev, apdev):
+ dev[0].request("REMOVE_NETWORK all")
+ dev[0].wait_disconnected()
+
+- for count in range(1, 6):
++ for count in range(1, 4):
+ dev[0].request("ERP_FLUSH")
+ with fail_test(dev[0], count, "hmac_sha256_kdf;eap_peer_erp_init"):
+ dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+--- a/tests/hwsim/test_fils.py
++++ b/tests/hwsim/test_fils.py
+@@ -1422,7 +1422,10 @@ def run_fils_sk_pfs(dev, apdev, group, p
+ check_erp_capa(dev[0])
+
+ tls = dev[0].request("GET tls_library")
+- if not tls.startswith("wolfSSL"):
++ if tls.startswith("mbed TLS"):
++ if int(group) == 27:
++ raise HwsimSkip("Brainpool EC group 27 not supported by mbed TLS")
++ elif not tls.startswith("wolfSSL"):
+ if int(group) in [25]:
+ if not (tls.startswith("OpenSSL") and ("build=OpenSSL 1.0.2" in tls or "build=OpenSSL 1.1" in tls or "build=OpenSSL 3.0" in tls) and ("run=OpenSSL 1.0.2" in tls or "run=OpenSSL 1.1" in tls or "run=OpenSSL 3.0" in tls)):
+ raise HwsimSkip("EC group not supported")
+--- a/tests/hwsim/test_pmksa_cache.py
++++ b/tests/hwsim/test_pmksa_cache.py
+@@ -955,7 +955,7 @@ def test_pmksa_cache_preauth_wpas_oom(de
+ eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
+ password_hex="0123456789abcdef0123456789abcdef",
+ bssid=apdev[0]['bssid'])
+- for i in range(1, 11):
++ for i in range(1, 10):
+ with alloc_fail(dev[0], i, "rsn_preauth_init"):
+ res = dev[0].request("PREAUTH f2:11:22:33:44:55").strip()
+ logger.info("Iteration %d - PREAUTH command results: %s" % (i, res))
+@@ -963,7 +963,7 @@ def test_pmksa_cache_preauth_wpas_oom(de
+ state = dev[0].request('GET_ALLOC_FAIL')
+ if state.startswith('0:'):
+ break
+- time.sleep(0.05)
++ time.sleep(0.10)
+
+ def test_pmksa_cache_ctrl(dev, apdev):
+ """PMKSA cache control interface operations"""
+--- a/tests/hwsim/test_sae.py
++++ b/tests/hwsim/test_sae.py
+@@ -177,6 +177,11 @@ def test_sae_groups(dev, apdev):
+ if tls.startswith("OpenSSL") and "run=OpenSSL 1." in tls:
+ logger.info("Add Brainpool EC groups since OpenSSL is new enough")
+ sae_groups += [27, 28, 29, 30]
++ if tls.startswith("mbed TLS"):
++ # secp224k1 and secp224r1 (26) have prime p = 1 mod 4, and mbedtls
++ # does not have code to derive y from compressed format for those curves
++ sae_groups = [19, 25, 20, 21, 1, 2, 5, 14, 15, 16, 22, 23, 24]
++ sae_groups += [27, 28, 29, 30]
+ heavy_groups = [14, 15, 16]
+ suitable_groups = [15, 16, 17, 18, 19, 20, 21]
+ groups = [str(g) for g in sae_groups]
+@@ -2193,6 +2198,8 @@ def run_sae_pwe_group(dev, apdev, group)
+ logger.info("Add Brainpool EC groups since OpenSSL is new enough")
+ elif tls.startswith("wolfSSL"):
+ logger.info("Make sure Brainpool EC groups were enabled when compiling wolfSSL")
++ elif tls.startswith("mbed TLS"):
++ logger.info("Make sure Brainpool EC groups were enabled when compiling mbed TLS")
+ else:
+ raise HwsimSkip("Brainpool curve not supported")
+ start_sae_pwe_ap(apdev[0], group, 2)
+--- a/tests/hwsim/test_suite_b.py
++++ b/tests/hwsim/test_suite_b.py
+@@ -27,6 +27,8 @@ def check_suite_b_tls_lib(dev, dhe=False
+ return
+ if tls.startswith("wolfSSL"):
+ return
++ if tls.startswith("mbed TLS"):
++ return
+ if not tls.startswith("OpenSSL"):
+ raise HwsimSkip("TLS library not supported for Suite B: " + tls)
+ supported = False
+@@ -520,6 +522,7 @@ def test_suite_b_192_rsa_insufficient_dh
+
+ dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192",
+ ieee80211w="2",
++ openssl_ciphers="DHE-RSA-AES256-GCM-SHA384",
+ phase1="tls_suiteb=1",
+ eap="TLS", identity="tls user",
+ ca_cert="auth_serv/rsa3072-ca.pem",
+--- a/tests/hwsim/test_wpas_ctrl.py
++++ b/tests/hwsim/test_wpas_ctrl.py
+@@ -1842,7 +1842,7 @@ def _test_wpas_ctrl_oom(dev):
+ tls = dev[0].request("GET tls_library")
+ if not tls.startswith("internal"):
+ tests.append(('NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG', 'FAIL',
+- 4, 'wpas_ctrl_nfc_get_handover_sel_p2p'))
++ 3, 'wpas_ctrl_nfc_get_handover_sel_p2p'))
+ for cmd, exp, count, func in tests:
+ with alloc_fail(dev[0], count, func):
+ res = dev[0].request(cmd)
+--- a/tests/hwsim/utils.py
++++ b/tests/hwsim/utils.py
+@@ -141,7 +141,13 @@ def check_imsi_privacy_support(dev):
+
+ def check_tls_tod(dev):
+ tls = dev.request("GET tls_library")
+- if not tls.startswith("OpenSSL") and not tls.startswith("internal"):
++ if tls.startswith("OpenSSL"):
++ return
++ elif tls.startswith("internal"):
++ return
++ elif tls.startswith("mbed TLS"):
++ return
++ else:
+ raise HwsimSkip("TLS TOD-TOFU/STRICT not supported with this TLS library: " + tls)
+
+ def vht_supported():
+--- /dev/null
++++ b/tests/test-crypto_module.c
+@@ -0,0 +1,16 @@
++/*
++ * crypto module tests - test program
++ * Copyright (c) 2022, Glenn Strauss <gstrauss@gluelogic.com>
++ *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
++ */
++
++#include "utils/includes.h"
++#include "utils/module_tests.h"
++#include "crypto/crypto_module_tests.c"
++
++int main(int argc, char *argv[])
++{
++ return crypto_module_tests();
++}
+--- a/tests/test-https.c
++++ b/tests/test-https.c
+@@ -75,7 +75,7 @@ static int https_client(int s, const cha
+ struct tls_connection *conn;
+ struct wpabuf *in, *out, *appl;
+ int res = -1;
+- int need_more_data;
++ int need_more_data = 0;
+
+ os_memset(&conf, 0, sizeof(conf));
+ conf.event_cb = https_tls_event_cb;
+@@ -93,8 +93,12 @@ static int https_client(int s, const cha
+
+ for (;;) {
+ appl = NULL;
++#ifdef CONFIG_TLS_INTERNAL_SERVER
+ out = tls_connection_handshake2(tls, conn, in, &appl,
+ &need_more_data);
++#else
++ out = tls_connection_handshake(tls, conn, in, &appl);
++#endif
+ wpabuf_free(in);
+ in = NULL;
+ if (out == NULL) {
+@@ -152,11 +156,15 @@ static int https_client(int s, const cha
+
+ wpa_printf(MSG_INFO, "Reading HTTP response");
+ for (;;) {
+- int need_more_data;
++ int need_more_data = 0;
+ in = https_recv(s);
+ if (in == NULL)
+ goto done;
++#ifdef CONFIG_TLS_INTERNAL_SERVER
+ out = tls_connection_decrypt2(tls, conn, in, &need_more_data);
++#else
++ out = tls_connection_decrypt(tls, conn, in);
++#endif
+ if (need_more_data)
+ wpa_printf(MSG_DEBUG, "HTTP: Need more data");
+ wpabuf_free(in);
+--- a/tests/test-https_server.c
++++ b/tests/test-https_server.c
+@@ -67,10 +67,12 @@ static struct wpabuf * https_recv(int s,
+ }
+
+
++#ifdef CONFIG_TLS_INTERNAL_SERVER
+ static void https_tls_log_cb(void *ctx, const char *msg)
+ {
+ wpa_printf(MSG_DEBUG, "TLS: %s", msg);
+ }
++#endif
+
+
+ static int https_server(int s)
+@@ -79,7 +81,7 @@ static int https_server(int s)
+ void *tls;
+ struct tls_connection_params params;
+ struct tls_connection *conn;
+- struct wpabuf *in, *out, *appl;
++ struct wpabuf *in = NULL, *out = NULL, *appl = NULL;
+ int res = -1;
+
+ os_memset(&conf, 0, sizeof(conf));
+@@ -106,7 +108,9 @@ static int https_server(int s)
+ return -1;
+ }
+
++#ifdef CONFIG_TLS_INTERNAL_SERVER
+ tls_connection_set_log_cb(conn, https_tls_log_cb, NULL);
++#endif
+
+ for (;;) {
+ in = https_recv(s, 5000);
+@@ -147,12 +151,16 @@ static int https_server(int s)
+
+ wpa_printf(MSG_INFO, "Reading HTTP request");
+ for (;;) {
+- int need_more_data;
++ int need_more_data = 0;
+
+ in = https_recv(s, 5000);
+ if (!in)
+ goto done;
++#ifdef CONFIG_TLS_INTERNAL_SERVER
+ out = tls_connection_decrypt2(tls, conn, in, &need_more_data);
++#else
++ out = tls_connection_decrypt(tls, conn, in);
++#endif
+ wpabuf_free(in);
+ in = NULL;
+ if (need_more_data) {
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -1122,6 +1122,7 @@ CFLAGS += -DCONFIG_TLSV12
+ endif
+
+ ifeq ($(CONFIG_TLS), wolfssl)
++CFLAGS += -DCONFIG_TLS_WOLFSSL
+ ifdef TLS_FUNCS
+ CFLAGS += -DWOLFSSL_DER_LOAD
+ OBJS += ../src/crypto/tls_wolfssl.o
+@@ -1137,6 +1138,7 @@ LIBS_p += -lwolfssl -lm
+ endif
+
+ ifeq ($(CONFIG_TLS), openssl)
++CFLAGS += -DCONFIG_TLS_OPENSSL
+ CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
+ ifdef TLS_FUNCS
+ CFLAGS += -DEAP_TLS_OPENSSL
+@@ -1164,6 +1166,7 @@ CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONF
+ endif
+
+ ifeq ($(CONFIG_TLS), mbedtls)
++CFLAGS += -DCONFIG_TLS_MBEDTLS
+ ifndef CONFIG_CRYPTO
+ CONFIG_CRYPTO=mbedtls
+ endif
+@@ -1183,6 +1186,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), gnutls)
++CFLAGS += -DCONFIG_TLS_GNUTLS
+ ifndef CONFIG_CRYPTO
+ # default to libgcrypt
+ CONFIG_CRYPTO=gnutls
+@@ -1213,6 +1217,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), internal)
++CFLAGS += -DCONFIG_TLS_INTERNAL
+ ifndef CONFIG_CRYPTO
+ CONFIG_CRYPTO=internal
+ endif
+@@ -1293,6 +1298,7 @@ endif
+ endif
+
+ ifeq ($(CONFIG_TLS), linux)
++CFLAGS += -DCONFIG_TLS_INTERNAL
+ OBJS += ../src/crypto/crypto_linux.o
+ OBJS_p += ../src/crypto/crypto_linux.o
+ ifdef TLS_FUNCS
diff --git a/package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch b/package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch
new file mode 100644
index 00000000000..c8c3ff33f42
--- /dev/null
+++ b/package/network/services/hostapd/patches/150-add-NULL-checks-encountered-during-tests-hwsim.patch
@@ -0,0 +1,45 @@
+From 33afce36c54b0cad38643629ded10ff5d727f077 Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <gstrauss@gluelogic.com>
+Date: Fri, 12 Aug 2022 05:34:47 -0400
+Subject: [PATCH 5/7] add NULL checks (encountered during tests/hwsim)
+
+sae_derive_commit_element_ecc NULL pwe_ecc check
+dpp_gen_keypair() NULL curve check
+
+Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
+---
+ src/common/dpp_crypto.c | 6 ++++++
+ src/common/sae.c | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/src/common/dpp_crypto.c
++++ b/src/common/dpp_crypto.c
+@@ -269,6 +269,12 @@ int dpp_get_pubkey_hash(struct crypto_ec
+
+ struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve)
+ {
++ if (curve == NULL) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: %s curve must be initialized", __func__);
++ return NULL;
++ }
++
+ struct crypto_ec_key *key;
+
+ wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -1278,6 +1278,13 @@ void sae_deinit_pt(struct sae_pt *pt)
+ static int sae_derive_commit_element_ecc(struct sae_data *sae,
+ struct crypto_bignum *mask)
+ {
++ if (sae->tmp->pwe_ecc == NULL) {
++ wpa_printf(MSG_DEBUG,
++ "SAE: %s sae->tmp->pwe_ecc must be initialized",
++ __func__);
++ return -1;
++ }
++
+ /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+ if (!sae->tmp->own_commit_element_ecc) {
+ sae->tmp->own_commit_element_ecc =
diff --git a/package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch b/package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch
new file mode 100644
index 00000000000..db4fcfe2357
--- /dev/null
+++ b/package/network/services/hostapd/patches/160-dpp_pkex-EC-point-mul-w-value-prime.patch
@@ -0,0 +1,26 @@
+From 54211caa2e0e5163aefef390daf88a971367a702 Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <gstrauss@gluelogic.com>
+Date: Tue, 4 Oct 2022 17:09:24 -0400
+Subject: [PATCH 6/7] dpp_pkex: EC point mul w/ value < prime
+
+crypto_ec_point_mul() with mbedtls requires point
+be multiplied by a multiplicand with value < prime
+
+Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
+---
+ src/common/dpp_crypto.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/src/common/dpp_crypto.c
++++ b/src/common/dpp_crypto.c
+@@ -1588,7 +1588,9 @@ dpp_pkex_derive_Qr(const struct dpp_curv
+ Pr = crypto_ec_key_get_public_key(Pr_key);
+ Qr = crypto_ec_point_init(ec);
+ hash_bn = crypto_bignum_init_set(hash, curve->hash_len);
+- if (!Pr || !Qr || !hash_bn || crypto_ec_point_mul(ec, Pr, hash_bn, Qr))
++ if (!Pr || !Qr || !hash_bn ||
++ crypto_bignum_mod(hash_bn, crypto_ec_get_prime(ec), hash_bn) ||
++ crypto_ec_point_mul(ec, Pr, hash_bn, Qr))
+ goto fail;
+
+ if (crypto_ec_point_is_at_infinity(ec, Qr)) {
diff --git a/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch b/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch
new file mode 100644
index 00000000000..b0151b071f6
--- /dev/null
+++ b/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch
@@ -0,0 +1,141 @@
+From d4c4ef302f98fd6bce173b8636e7e350d8b44981 Mon Sep 17 00:00:00 2001
+From: P Praneesh <ppranees@codeaurora.org>
+Date: Fri, 19 Mar 2021 12:17:27 +0530
+Subject: [PATCH] hostapd: update cfs0 and cfs1 for 160MHz
+
+As per standard Draft P802.11ax_D8.0,( Table 26-9—Setting
+of the VHT Channel Width and VHT NSS at an HE STA
+transmitting the OM Control subfield ), center frequency of
+160MHz should be published in HT information subset 2 of
+HT information when EXT NSS BW field is enabled.
+
+If the supported number of NSS in 160MHz is at least max NSS
+support, then center_freq_seg0 indicates the center frequency of 80MHz and
+center_freq_seg1 indicates the center frequency of 160MHz.
+
+If the supported number of NSS in 160MHz is less than max NSS
+support, then center_freq_seg0 indicates the center frequency of 80MHz and
+center_freq_seg1 is 0. The center frequency of 160MHz is published in HT
+operation information element instead.
+
+Signed-off-by: P Praneesh <ppranees@codeaurora.org>
+---
+ hostapd/config_file.c | 2 ++
+ src/ap/ieee802_11_ht.c | 7 +++++++
+ src/ap/ieee802_11_vht.c | 16 ++++++++++++++++
+ src/common/hw_features_common.c | 1 +
+ src/common/ieee802_11_defs.h | 1 +
+ 5 files changed, 27 insertions(+)
+
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -1153,6 +1153,8 @@ static int hostapd_config_vht_capab(stru
+ conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
+ if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
+ conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
++ if (os_strstr(capab, "[EXT-NSS-BW-SUPP]"))
++ conf->vht_capab |= VHT_CAP_EXTENDED_NSS_BW_SUPPORT;
+ return 0;
+ }
+ #endif /* CONFIG_IEEE80211AC */
+--- a/src/ap/ieee802_11_ht.c
++++ b/src/ap/ieee802_11_ht.c
+@@ -82,7 +82,9 @@ u8 * hostapd_eid_ht_capabilities(struct
+ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
+ {
+ struct ieee80211_ht_operation *oper;
++ le32 vht_capabilities_info;
+ u8 *pos = eid;
++ u8 chwidth;
+
+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n ||
+ is_6ghz_op_class(hapd->iconf->op_class))
+@@ -103,6 +105,13 @@ u8 * hostapd_eid_ht_operation(struct hos
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+ HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
+
++ vht_capabilities_info = host_to_le32(hapd->iface->current_mode->vht_capab);
++ chwidth = hostapd_get_oper_chwidth(hapd->iconf);
++ if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT
++ && ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) {
++ oper->operation_mode = host_to_le16(hapd->iconf->vht_oper_centr_freq_seg0_idx << 5);
++ }
++
+ pos += sizeof(*oper);
+
+ return pos;
+--- a/src/ap/ieee802_11_vht.c
++++ b/src/ap/ieee802_11_vht.c
+@@ -25,6 +25,7 @@ u8 * hostapd_eid_vht_capabilities(struct
+ struct ieee80211_vht_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ u8 *pos = eid;
++ u8 chwidth;
+
+ if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
+ return eid;
+@@ -62,6 +63,17 @@ u8 * hostapd_eid_vht_capabilities(struct
+ host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ }
+
++ chwidth = hostapd_get_oper_chwidth(hapd->iconf);
++ if (((host_to_le32(mode->vht_capab)) & VHT_CAP_EXTENDED_NSS_BW_SUPPORT)
++ && ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) {
++ cap->vht_capabilities_info |= VHT_CAP_EXTENDED_NSS_BW_SUPPORT;
++ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ));
++ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ));
++ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_MASK));
++ } else {
++ cap->vht_capabilities_info &= ~VHT_CAP_EXTENDED_NSS_BW_SUPPORT_MASK;
++ }
++
+ /* Supported MCS set comes from hw */
+ os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
+
+@@ -74,6 +86,7 @@ u8 * hostapd_eid_vht_capabilities(struct
+ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
+ {
+ struct ieee80211_vht_operation *oper;
++ le32 vht_capabilities_info;
+ u8 *pos = eid;
+ enum oper_chan_width oper_chwidth =
+ hostapd_get_oper_chwidth(hapd->iconf);
+@@ -106,6 +119,7 @@ u8 * hostapd_eid_vht_operation(struct ho
+ oper->vht_op_info_chan_center_freq_seg1_idx = seg1;
+
+ oper->vht_op_info_chwidth = oper_chwidth;
++ vht_capabilities_info = host_to_le32(hapd->iface->current_mode->vht_capab);
+ if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
+ /*
+ * Convert 160 MHz channel width to new style as interop
+@@ -119,6 +133,9 @@ u8 * hostapd_eid_vht_operation(struct ho
+ oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
+ else
+ oper->vht_op_info_chan_center_freq_seg0_idx += 8;
++
++ if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT)
++ oper->vht_op_info_chan_center_freq_seg1_idx = 0;
+ } else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
+ /*
+ * Convert 80+80 MHz channel width to new style as interop
+--- a/src/common/hw_features_common.c
++++ b/src/common/hw_features_common.c
+@@ -811,6 +811,7 @@ int ieee80211ac_cap_check(u32 hw, u32 co
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+ VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+ VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
++ VHT_CAP_CHECK(VHT_CAP_EXTENDED_NSS_BW_SUPPORT);
+
+ #undef VHT_CAP_CHECK
+ #undef VHT_CAP_CHECK_MAX
+--- a/src/common/ieee802_11_defs.h
++++ b/src/common/ieee802_11_defs.h
+@@ -1349,6 +1349,8 @@ struct ieee80211_ampe_ie {
+ #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27))
+ #define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
+ #define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
++#define VHT_CAP_EXTENDED_NSS_BW_SUPPORT ((u32) BIT(30))
++#define VHT_CAP_EXTENDED_NSS_BW_SUPPORT_MASK ((u32) BIT(30) | BIT(31))
+
+ #define VHT_OPMODE_CHANNEL_WIDTH_MASK ((u8) BIT(0) | BIT(1))
+ #define VHT_OPMODE_CHANNEL_RxNSS_MASK ((u8) BIT(4) | BIT(5) | \
diff --git a/package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch b/package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch
new file mode 100644
index 00000000000..4929c581ce2
--- /dev/null
+++ b/package/network/services/hostapd/patches/180-driver_nl80211-fix-setting-QoS-map-on-secondary-BSSs.patch
@@ -0,0 +1,20 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 14 Sep 2023 10:53:50 +0200
+Subject: [PATCH] driver_nl80211: fix setting QoS map on secondary BSSs
+
+The setting is per-BSS, not per PHY
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -11341,7 +11341,7 @@ static int nl80211_set_qos_map(void *pri
+ wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
+ qos_map_set, qos_map_set_len);
+
+- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
++ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_QOS_MAP)) ||
+ nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
diff --git a/package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch b/package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch
new file mode 100644
index 00000000000..adfb21fb471
--- /dev/null
+++ b/package/network/services/hostapd/patches/181-driver_nl80211-update-drv-ifindex-on-removing-the-fi.patch
@@ -0,0 +1,18 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 14 Sep 2023 11:28:03 +0200
+Subject: [PATCH] driver_nl80211: update drv->ifindex on removing the first
+ BSS
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -8867,6 +8867,7 @@ static int wpa_driver_nl80211_if_remove(
+ if (drv->first_bss->next) {
+ drv->first_bss = drv->first_bss->next;
+ drv->ctx = drv->first_bss->ctx;
++ drv->ifindex = drv->first_bss->ifindex;
+ os_free(bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
diff --git a/package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch b/package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch
new file mode 100644
index 00000000000..395c6459542
--- /dev/null
+++ b/package/network/services/hostapd/patches/182-nl80211-move-nl80211_put_freq_params-call-outside-of.patch
@@ -0,0 +1,34 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 18 Sep 2023 16:47:41 +0200
+Subject: [PATCH] nl80211: move nl80211_put_freq_params call outside of
+ 802.11ax #ifdef
+
+The relevance of this call is not specific to 802.11ax, so it should be done
+even with CONFIG_IEEE80211AX disabled.
+
+Fixes: b3921db426ea ("nl80211: Add frequency info in start AP command")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -5226,6 +5226,9 @@ static int wpa_driver_nl80211_set_ap(voi
+ nla_nest_end(msg, ftm);
+ }
+
++ if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
++ goto fail;
++
+ #ifdef CONFIG_IEEE80211AX
+ if (params->he_spr_ctrl) {
+ struct nlattr *spr;
+@@ -5260,9 +5263,6 @@ static int wpa_driver_nl80211_set_ap(voi
+ nla_nest_end(msg, spr);
+ }
+
+- if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
+- goto fail;
+-
+ if (params->freq && params->freq->he_enabled) {
+ struct nlattr *bss_color;
+
diff --git a/package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch b/package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch
new file mode 100644
index 00000000000..fe81318385f
--- /dev/null
+++ b/package/network/services/hostapd/patches/183-hostapd-cancel-channel_list_update_timeout-in-hostap.patch
@@ -0,0 +1,28 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 20 Sep 2023 13:41:10 +0200
+Subject: [PATCH] hostapd: cancel channel_list_update_timeout in
+ hostapd_cleanup_iface_partial
+
+Fixes a crash when disabling an interface during channel list update
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -569,6 +569,7 @@ static void sta_track_deinit(struct host
+ void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+ {
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
++ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ #ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+ #endif /* NEED_AP_MLME */
+@@ -598,7 +599,6 @@ void hostapd_cleanup_iface_partial(struc
+ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+ {
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+- eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ NULL);
+
diff --git a/package/network/services/hostapd/patches/200-multicall.patch b/package/network/services/hostapd/patches/200-multicall.patch
index 8dce2608719..e3ed00f2ded 100644
--- a/package/network/services/hostapd/patches/200-multicall.patch
+++ b/package/network/services/hostapd/patches/200-multicall.patch
@@ -18,7 +18,7 @@
OBJS += ../src/ap/vlan_init.o
OBJS += ../src/ap/vlan_ifconfig.o
OBJS += ../src/ap/vlan.o
-@@ -349,10 +351,14 @@ CFLAGS += -DCONFIG_MBO
+@@ -357,10 +359,14 @@ CFLAGS += -DCONFIG_MBO
OBJS += ../src/ap/mbo_ap.o
endif
@@ -36,7 +36,7 @@
LIBS += $(DRV_AP_LIBS)
ifdef CONFIG_L2_PACKET
-@@ -1277,6 +1283,12 @@ install: $(addprefix $(DESTDIR)$(BINDIR)
+@@ -1380,6 +1386,12 @@ install: $(addprefix $(DESTDIR)$(BINDIR)
_OBJS_VAR := OBJS
include ../src/objs.mk
@@ -49,7 +49,7 @@
hostapd: $(OBJS)
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
@$(E) " LD " $@
-@@ -1351,6 +1363,12 @@ include ../src/objs.mk
+@@ -1460,6 +1472,12 @@ include ../src/objs.mk
_OBJS_VAR := SOBJS
include ../src/objs.mk
@@ -64,15 +64,15 @@
@$(E) " LD " $@
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
-@@ -17,6 +17,7 @@ endif
+@@ -10,6 +10,7 @@ ALL += dbus/fi.w1.wpa_supplicant1.servic
EXTRA_TARGETS=dynamic_eap_methods
CONFIG_FILE=.config
+-include $(if $(MULTICALL),../hostapd/.config)
include ../src/build.rules
- ifdef LIBS
-@@ -359,7 +360,9 @@ endif
+ ifdef CONFIG_BUILD_PASN_SO
+@@ -382,7 +383,9 @@ endif
ifdef CONFIG_IBSS_RSN
NEED_RSN_AUTHENTICATOR=y
CFLAGS += -DCONFIG_IBSS_RSN
@@ -82,7 +82,7 @@
OBJS += ibss_rsn.o
endif
-@@ -897,6 +900,10 @@ ifdef CONFIG_DYNAMIC_EAP_METHODS
+@@ -924,6 +927,10 @@ ifdef CONFIG_DYNAMIC_EAP_METHODS
CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
LIBS += -ldl -rdynamic
endif
@@ -93,7 +93,7 @@
endif
ifdef CONFIG_AP
-@@ -904,9 +911,11 @@ NEED_EAP_COMMON=y
+@@ -931,9 +938,11 @@ NEED_EAP_COMMON=y
NEED_RSN_AUTHENTICATOR=y
CFLAGS += -DCONFIG_AP
OBJS += ap.o
@@ -105,7 +105,7 @@
OBJS += ../src/ap/hostapd.o
OBJS += ../src/ap/wpa_auth_glue.o
OBJS += ../src/ap/utils.o
-@@ -986,6 +995,12 @@ endif
+@@ -1022,6 +1031,12 @@ endif
ifdef CONFIG_HS20
OBJS += ../src/ap/hs20.o
endif
@@ -118,7 +118,7 @@
endif
ifdef CONFIG_MBO
-@@ -994,7 +1009,9 @@ CFLAGS += -DCONFIG_MBO
+@@ -1030,7 +1045,9 @@ CFLAGS += -DCONFIG_MBO
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -128,7 +128,7 @@
NEED_AES_WRAP=y
OBJS += ../src/ap/wpa_auth.o
OBJS += ../src/ap/wpa_auth_ie.o
-@@ -1889,6 +1906,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv)
+@@ -2010,6 +2027,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv)
_OBJS_VAR := OBJS
include ../src/objs.mk
@@ -141,7 +141,7 @@
wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
@$(E) " LD " $@
-@@ -2021,6 +2044,12 @@ eap_gpsk.so: $(SRC_EAP_GPSK)
+@@ -2142,6 +2165,12 @@ eap_gpsk.so: $(SRC_EAP_GPSK)
$(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
@$(E) " sed" $<
@@ -156,7 +156,7 @@
wpa_cli.exe: wpa_cli
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
-@@ -6025,8 +6025,8 @@ union wpa_event_data {
+@@ -6667,8 +6667,8 @@ union wpa_event_data {
* Driver wrapper code should call this function whenever an event is received
* from the driver.
*/
@@ -167,7 +167,7 @@
/**
* wpa_supplicant_event_global - Report a driver event for wpa_supplicant
-@@ -6038,7 +6038,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -6680,7 +6680,7 @@ void wpa_supplicant_event(void *ctx, enu
* Same as wpa_supplicant_event(), but we search for the interface in
* wpa_global.
*/
@@ -178,7 +178,7 @@
/*
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
-@@ -1836,8 +1836,8 @@ err:
+@@ -2184,8 +2184,8 @@ err:
#endif /* CONFIG_OWE */
@@ -189,7 +189,7 @@
{
struct hostapd_data *hapd = ctx;
#ifndef CONFIG_NO_STDOUT_DEBUG
-@@ -2082,7 +2082,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -2489,7 +2489,7 @@ void wpa_supplicant_event(void *ctx, enu
}
@@ -200,7 +200,7 @@
struct hapd_interfaces *interfaces = ctx;
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
-@@ -1038,8 +1038,8 @@ static void wpa_priv_send_ft_response(st
+@@ -1039,8 +1039,8 @@ static void wpa_priv_send_ft_response(st
}
@@ -211,7 +211,7 @@
{
struct wpa_priv_interface *iface = ctx;
-@@ -1102,7 +1102,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -1103,7 +1103,7 @@ void wpa_supplicant_event(void *ctx, enu
}
@@ -220,7 +220,7 @@
union wpa_event_data *data)
{
struct wpa_priv_global *global = ctx;
-@@ -1215,6 +1215,8 @@ int main(int argc, char *argv[])
+@@ -1217,6 +1217,8 @@ int main(int argc, char *argv[])
if (os_program_init())
return -1;
@@ -231,7 +231,7 @@
os_memset(&global, 0, sizeof(global));
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
-@@ -4665,8 +4665,8 @@ static void wpas_event_unprot_beacon(str
+@@ -5353,8 +5353,8 @@ static void wpas_link_reconfig(struct wp
}
@@ -242,7 +242,7 @@
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
-@@ -5511,7 +5511,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -6272,7 +6272,7 @@ void wpa_supplicant_event(void *ctx, enu
}
@@ -253,7 +253,7 @@
struct wpa_supplicant *wpa_s;
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -6819,7 +6819,6 @@ struct wpa_interface * wpa_supplicant_ma
+@@ -7462,7 +7462,6 @@ struct wpa_interface * wpa_supplicant_ma
return NULL;
}
@@ -261,7 +261,7 @@
/**
* wpa_supplicant_match_existing - Match existing interfaces
* @global: Pointer to global data from wpa_supplicant_init()
-@@ -6854,6 +6853,11 @@ static int wpa_supplicant_match_existing
+@@ -7497,6 +7496,11 @@ static int wpa_supplicant_match_existing
#endif /* CONFIG_MATCH_IFACE */
@@ -273,7 +273,7 @@
/**
* wpa_supplicant_add_iface - Add a new network interface
-@@ -7110,6 +7114,8 @@ struct wpa_global * wpa_supplicant_init(
+@@ -7753,6 +7757,8 @@ struct wpa_global * wpa_supplicant_init(
#ifndef CONFIG_NO_WPA_MSG
wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
#endif /* CONFIG_NO_WPA_MSG */
@@ -284,7 +284,7 @@
wpa_debug_open_file(params->wpa_debug_file_path);
--- a/hostapd/main.c
+++ b/hostapd/main.c
-@@ -590,6 +590,11 @@ fail:
+@@ -698,6 +698,11 @@ fail:
return -1;
}
@@ -296,14 +296,14 @@
#ifdef CONFIG_WPS
static int gen_uuid(const char *txt_addr)
-@@ -683,6 +688,8 @@ int main(int argc, char *argv[])
+@@ -791,6 +796,8 @@ int main(int argc, char *argv[])
return -1;
#endif /* CONFIG_DPP */
+ wpa_supplicant_event = hostapd_wpa_event;
+ wpa_supplicant_event_global = hostapd_wpa_event_global;
for (;;) {
- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
+ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q");
if (c < 0)
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -320,7 +320,7 @@
{
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
-@@ -30,7 +30,12 @@
+@@ -31,7 +31,12 @@
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
#include "wpas_glue.h"
@@ -333,7 +333,7 @@
const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
-@@ -1291,6 +1296,10 @@ static void usage(void)
+@@ -1303,6 +1308,10 @@ static void usage(void)
"option several times.\n");
}
@@ -344,7 +344,7 @@
int main(int argc, char *argv[])
{
-@@ -1311,6 +1320,8 @@ int main(int argc, char *argv[])
+@@ -1323,6 +1332,8 @@ int main(int argc, char *argv[])
if (os_program_init())
return -1;
diff --git a/package/network/services/hostapd/patches/300-noscan.patch b/package/network/services/hostapd/patches/300-noscan.patch
index 93b09342838..3b5f4325de0 100644
--- a/package/network/services/hostapd/patches/300-noscan.patch
+++ b/package/network/services/hostapd/patches/300-noscan.patch
@@ -1,6 +1,6 @@
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
-@@ -3459,6 +3459,10 @@ static int hostapd_config_fill(struct ho
+@@ -3448,6 +3448,10 @@ static int hostapd_config_fill(struct ho
if (bss->ocv && !bss->ieee80211w)
bss->ieee80211w = 1;
#endif /* CONFIG_OCV */
@@ -13,7 +13,7 @@
} else if (os_strcmp(buf, "ht_capab") == 0) {
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
-@@ -1009,6 +1009,8 @@ struct hostapd_config {
+@@ -1075,6 +1075,8 @@ struct hostapd_config {
int ht_op_mode_fixed;
u16 ht_capab;
@@ -24,7 +24,7 @@
int no_pri_sec_switch;
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
-@@ -517,7 +517,8 @@ static int ieee80211n_check_40mhz(struct
+@@ -546,7 +546,8 @@ static int ieee80211n_check_40mhz(struct
int ret;
/* Check that HT40 is used and PRI / SEC switch is allowed */
@@ -36,7 +36,7 @@
hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
-@@ -230,6 +230,9 @@ void hostapd_2040_coex_action(struct hos
+@@ -239,6 +239,9 @@ void hostapd_2040_coex_action(struct hos
return;
}
@@ -46,7 +46,7 @@
if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
wpa_printf(MSG_DEBUG,
"Ignore too short 20/40 BSS Coexistence Management frame");
-@@ -390,6 +393,9 @@ void ht40_intolerant_add(struct hostapd_
+@@ -399,6 +402,9 @@ void ht40_intolerant_add(struct hostapd_
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return;
diff --git a/package/network/services/hostapd/patches/301-mesh-noscan.patch b/package/network/services/hostapd/patches/301-mesh-noscan.patch
index 0d783294419..ceb6d0c161f 100644
--- a/package/network/services/hostapd/patches/301-mesh-noscan.patch
+++ b/package/network/services/hostapd/patches/301-mesh-noscan.patch
@@ -1,6 +1,6 @@
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
-@@ -2532,6 +2532,7 @@ static const struct parse_data ssid_fiel
+@@ -2600,6 +2600,7 @@ static const struct parse_data ssid_fiel
#else /* CONFIG_MESH */
{ INT_RANGE(mode, 0, 4) },
#endif /* CONFIG_MESH */
@@ -10,7 +10,7 @@
{ STR(id_str) },
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
-@@ -768,6 +768,7 @@ static void wpa_config_write_network(FIL
+@@ -775,6 +775,7 @@ static void wpa_config_write_network(FIL
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
@@ -20,44 +20,56 @@
INT(enable_edmg);
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
-@@ -474,6 +474,8 @@ static int wpa_supplicant_mesh_init(stru
+@@ -506,6 +506,8 @@ static int wpa_supplicant_mesh_init(stru
frequency);
goto out_free;
}
-+ if (ssid->noscan)
-+ conf->noscan = 1;
++ if (conf->noscan)
++ ssid->noscan = 1;
if (ssid->mesh_basic_rates == NULL) {
/*
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -2384,12 +2384,12 @@ void ibss_mesh_setup_freq(struct wpa_sup
+@@ -2710,7 +2710,7 @@ static bool ibss_mesh_can_use_vht(struct
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode)
+ {
+- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
++ if (mode->mode != HOSTAPD_MODE_IEEE80211A && !(ssid->noscan))
+ return false;
+
+ if (!drv_supports_vht(wpa_s, ssid))
+@@ -2783,7 +2783,7 @@ static void ibss_mesh_select_40mhz(struc
+ int i, res;
+ unsigned int j;
+ static const int ht40plus[] = {
+- 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 165, 173,
++ 1, 2, 3, 4, 5, 6, 7, 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 165, 173,
+ 184, 192
+ };
+ int ht40 = -1;
+@@ -3033,7 +3033,7 @@ void ibss_mesh_setup_freq(struct wpa_sup
int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
enum hostapd_hw_mode hw_mode;
struct hostapd_hw_modes *mode = NULL;
-- int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
-+ int ht40plus[] = { 1, 2, 3, 4, 5, 6, 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
- int vht80[] = { 36, 52, 100, 116, 132, 149 };
- struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
+- int i, obss_scan = 1;
++ int i, obss_scan = !(ssid->noscan);
u8 channel;
-- int i, chan_idx, ht40 = -1, res, obss_scan = 1;
-+ int i, chan_idx, ht40 = -1, res, obss_scan = !(ssid->noscan);
- unsigned int j, k;
- struct hostapd_freq_params vht_freq;
- int chwidth, seg0, seg1;
-@@ -2473,7 +2473,7 @@ void ibss_mesh_setup_freq(struct wpa_sup
- #endif /* CONFIG_HE_OVERRIDES */
-
+ bool is_6ghz;
+ bool dfs_enabled = wpa_s->conf->country[0] && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_RADAR);
+@@ -3080,6 +3080,8 @@ void ibss_mesh_setup_freq(struct wpa_sup
+ freq->he_enabled = ibss_mesh_can_use_he(wpa_s, ssid, mode,
+ ieee80211_mode);
+ freq->channel = channel;
++ if (mode->mode == HOSTAPD_MODE_IEEE80211G && ssid->noscan)
++ ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan, dfs_enabled);
/* Setup higher BW only for 5 GHz */
-- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
-+ if (mode->mode != HOSTAPD_MODE_IEEE80211A && !(ssid->noscan))
- return;
-
- for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A) {
+ ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan, dfs_enabled);
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
-@@ -971,6 +971,8 @@ struct wpa_ssid {
+@@ -1035,6 +1035,8 @@ struct wpa_ssid {
*/
int no_auto_peer;
diff --git a/package/network/services/hostapd/patches/310-rescan_immediately.patch b/package/network/services/hostapd/patches/310-rescan_immediately.patch
index 7f5e2070696..6e0244bca29 100644
--- a/package/network/services/hostapd/patches/310-rescan_immediately.patch
+++ b/package/network/services/hostapd/patches/310-rescan_immediately.patch
@@ -1,6 +1,6 @@
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -5154,7 +5154,7 @@ wpa_supplicant_alloc(struct wpa_supplica
+@@ -5769,7 +5769,7 @@ wpa_supplicant_alloc(struct wpa_supplica
if (wpa_s == NULL)
return NULL;
wpa_s->scan_req = INITIAL_SCAN_REQ;
diff --git a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch
index 9ced08801ee..c11c9572169 100644
--- a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch
+++ b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch
@@ -1,8 +1,8 @@
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
-@@ -4973,7 +4973,7 @@ static int nl80211_set_channel(struct i8
- freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
- freq->bandwidth, freq->center_freq1, freq->center_freq2);
+@@ -5407,7 +5407,7 @@ static int nl80211_set_channel(struct i8
+ freq->he_enabled, freq->eht_enabled, freq->bandwidth,
+ freq->center_freq1, freq->center_freq2);
- msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ msg = nl80211_bss_msg(bss, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
diff --git a/package/network/services/hostapd/patches/340-reload_freq_change.patch b/package/network/services/hostapd/patches/340-reload_freq_change.patch
deleted file mode 100644
index 3d51a47a1ed..00000000000
--- a/package/network/services/hostapd/patches/340-reload_freq_change.patch
+++ /dev/null
@@ -1,75 +0,0 @@
---- a/src/ap/hostapd.c
-+++ b/src/ap/hostapd.c
-@@ -115,6 +115,28 @@ static void hostapd_reload_bss(struct ho
- #endif /* CONFIG_NO_RADIUS */
-
- ssid = &hapd->conf->ssid;
-+
-+ hostapd_set_freq(hapd, hapd->iconf->hw_mode, hapd->iface->freq,
-+ hapd->iconf->channel,
-+ hapd->iconf->enable_edmg,
-+ hapd->iconf->edmg_channel,
-+ hapd->iconf->ieee80211n,
-+ hapd->iconf->ieee80211ac,
-+ hapd->iconf->ieee80211ax,
-+ hapd->iconf->secondary_channel,
-+ hostapd_get_oper_chwidth(hapd->iconf),
-+ hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf),
-+ hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf));
-+
-+ if (hapd->iface->current_mode) {
-+ if (hostapd_prepare_rates(hapd->iface, hapd->iface->current_mode)) {
-+ wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
-+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
-+ HOSTAPD_LEVEL_WARNING,
-+ "Failed to prepare rates table.");
-+ }
-+ }
-+
- if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
- ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
- /*
-@@ -216,6 +238,7 @@ int hostapd_reload_config(struct hostapd
- struct hostapd_data *hapd = iface->bss[0];
- struct hostapd_config *newconf, *oldconf;
- size_t j;
-+ int i;
-
- if (iface->config_fname == NULL) {
- /* Only in-memory config in use - assume it has been updated */
-@@ -266,24 +289,20 @@ int hostapd_reload_config(struct hostapd
- }
- iface->conf = newconf;
-
-+ for (i = 0; i < iface->num_hw_features; i++) {
-+ struct hostapd_hw_modes *mode = &iface->hw_features[i];
-+ if (mode->mode == iface->conf->hw_mode) {
-+ iface->current_mode = mode;
-+ break;
-+ }
-+ }
-+
-+ if (iface->conf->channel)
-+ iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
-+
- for (j = 0; j < iface->num_bss; j++) {
- hapd = iface->bss[j];
- hapd->iconf = newconf;
-- hapd->iconf->channel = oldconf->channel;
-- hapd->iconf->acs = oldconf->acs;
-- hapd->iconf->secondary_channel = oldconf->secondary_channel;
-- hapd->iconf->ieee80211n = oldconf->ieee80211n;
-- hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
-- hapd->iconf->ht_capab = oldconf->ht_capab;
-- hapd->iconf->vht_capab = oldconf->vht_capab;
-- hostapd_set_oper_chwidth(hapd->iconf,
-- hostapd_get_oper_chwidth(oldconf));
-- hostapd_set_oper_centr_freq_seg0_idx(
-- hapd->iconf,
-- hostapd_get_oper_centr_freq_seg0_idx(oldconf));
-- hostapd_set_oper_centr_freq_seg1_idx(
-- hapd->iconf,
-- hostapd_get_oper_centr_freq_seg1_idx(oldconf));
- hapd->conf = newconf->bss[j];
- hostapd_reload_bss(hapd);
- }
diff --git a/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch b/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch
index 73f81f65e6f..8784452876b 100644
--- a/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch
+++ b/package/network/services/hostapd/patches/341-mesh-ctrl-iface-channel-switch.patch
@@ -1,6 +1,6 @@
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
-@@ -1513,15 +1513,35 @@ int ap_switch_channel(struct wpa_supplic
+@@ -1825,15 +1825,35 @@ int ap_switch_channel(struct wpa_supplic
#ifdef CONFIG_CTRL_IFACE
diff --git a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch
index 1f9b74e97ee..647ca2cbf97 100644
--- a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch
+++ b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch
@@ -1,54 +1,35 @@
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
-@@ -2918,10 +2918,15 @@ static int wpa_driver_nl80211_del_beacon
- struct nl_msg *msg;
- struct wpa_driver_nl80211_data *drv = bss->drv;
+@@ -3008,12 +3008,12 @@ static int wpa_driver_nl80211_del_beacon
+ return 0;
-+ if (!bss->beacon_set)
-+ return 0;
-+
-+ bss->beacon_set = 0;
-+
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
- drv->ifindex);
+ bss->ifindex);
+ link->beacon_set = 0;
+ link->freq = 0;
+
nl80211_put_wiphy_data_ap(bss);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_BEACON);
- return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
- }
+ if (!msg)
+ return -ENOBUFS;
-@@ -5602,7 +5607,7 @@ static void nl80211_teardown_ap(struct i
+@@ -6100,7 +6100,7 @@ static void nl80211_teardown_ap(struct i
nl80211_mgmt_unsubscribe(bss, "AP teardown");
nl80211_put_wiphy_data_ap(bss);
-- bss->beacon_set = 0;
-+ wpa_driver_nl80211_del_beacon(bss);
+- bss->flink->beacon_set = 0;
++ wpa_driver_nl80211_del_beacon_all(bss);
}
-@@ -8051,8 +8056,6 @@ static int wpa_driver_nl80211_if_remove(
+@@ -8859,8 +8859,6 @@ static int wpa_driver_nl80211_if_remove(
} else {
wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
nl80211_teardown_ap(bss);
- if (!bss->added_if && !drv->first_bss->next)
-- wpa_driver_nl80211_del_beacon(bss);
+- wpa_driver_nl80211_del_beacon_all(bss);
nl80211_destroy_bss(bss);
if (!bss->added_if)
i802_set_iface_flags(bss, 0);
-@@ -8449,7 +8452,6 @@ static int wpa_driver_nl80211_deinit_ap(
- if (!is_ap_interface(drv->nlmode))
- return -1;
- wpa_driver_nl80211_del_beacon(bss);
-- bss->beacon_set = 0;
-
- /*
- * If the P2P GO interface was dynamically added, then it is
-@@ -8469,7 +8471,6 @@ static int wpa_driver_nl80211_stop_ap(vo
- if (!is_ap_interface(drv->nlmode))
- return -1;
- wpa_driver_nl80211_del_beacon(bss);
-- bss->beacon_set = 0;
- return 0;
- }
-
diff --git a/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch b/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch
deleted file mode 100644
index 349522e06a1..00000000000
--- a/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch
+++ /dev/null
@@ -1,106 +0,0 @@
---- a/hostapd/ctrl_iface.c
-+++ b/hostapd/ctrl_iface.c
-@@ -67,6 +67,7 @@
- #include "fst/fst_ctrl_iface.h"
- #include "config_file.h"
- #include "ctrl_iface.h"
-+#include "config_file.h"
-
-
- #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
-@@ -82,6 +83,7 @@ static void hostapd_ctrl_iface_send(stru
- enum wpa_msg_type type,
- const char *buf, size_t len);
-
-+static char *reload_opts = NULL;
-
- static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
- struct sockaddr_storage *from,
-@@ -133,6 +135,61 @@ static int hostapd_ctrl_iface_new_sta(st
- return 0;
- }
-
-+static char *get_option(char *opt, char *str)
-+{
-+ int len = strlen(str);
-+
-+ if (!strncmp(opt, str, len))
-+ return opt + len;
-+ else
-+ return NULL;
-+}
-+
-+static struct hostapd_config *hostapd_ctrl_iface_config_read(const char *fname)
-+{
-+ struct hostapd_config *conf;
-+ char *opt, *val;
-+
-+ conf = hostapd_config_read(fname);
-+ if (!conf)
-+ return NULL;
-+
-+ for (opt = strtok(reload_opts, " ");
-+ opt;
-+ opt = strtok(NULL, " ")) {
-+
-+ if ((val = get_option(opt, "channel=")))
-+ conf->channel = atoi(val);
-+ else if ((val = get_option(opt, "ht_capab=")))
-+ conf->ht_capab = atoi(val);
-+ else if ((val = get_option(opt, "ht_capab_mask=")))
-+ conf->ht_capab &= atoi(val);
-+ else if ((val = get_option(opt, "sec_chan=")))
-+ conf->secondary_channel = atoi(val);
-+ else if ((val = get_option(opt, "hw_mode=")))
-+ conf->hw_mode = atoi(val);
-+ else if ((val = get_option(opt, "ieee80211n=")))
-+ conf->ieee80211n = atoi(val);
-+ else
-+ break;
-+ }
-+
-+ return conf;
-+}
-+
-+static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt)
-+{
-+ struct hostapd_config * (*config_read_cb)(const char *config_fname);
-+ struct hostapd_iface *iface = hapd->iface;
-+
-+ config_read_cb = iface->interfaces->config_read_cb;
-+ iface->interfaces->config_read_cb = hostapd_ctrl_iface_config_read;
-+ reload_opts = txt;
-+
-+ hostapd_reload_config(iface);
-+
-+ iface->interfaces->config_read_cb = config_read_cb;
-+}
-
- #ifdef NEED_AP_MLME
- static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
-@@ -3754,6 +3811,8 @@ static int hostapd_ctrl_iface_receive_pr
- } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
- reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
- reply_size);
-+ } else if (os_strncmp(buf, "UPDATE ", 7) == 0) {
-+ hostapd_ctrl_iface_update(hapd, buf + 7);
- } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
- ieee802_1x_erp_flush(hapd);
- #ifdef RADIUS_SERVER
---- a/src/ap/ctrl_iface_ap.c
-+++ b/src/ap/ctrl_iface_ap.c
-@@ -919,7 +919,13 @@ int hostapd_parse_csa_settings(const cha
-
- int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
- {
-- return hostapd_drv_stop_ap(hapd);
-+ struct hostapd_iface *iface = hapd->iface;
-+ int i;
-+
-+ for (i = 0; i < iface->num_bss; i++)
-+ hostapd_drv_stop_ap(iface->bss[i]);
-+
-+ return 0;
- }
-
-
diff --git a/package/network/services/hostapd/patches/370-ap_sta_support.patch b/package/network/services/hostapd/patches/370-ap_sta_support.patch
deleted file mode 100644
index c5cad3bb8da..00000000000
--- a/package/network/services/hostapd/patches/370-ap_sta_support.patch
+++ /dev/null
@@ -1,392 +0,0 @@
---- a/wpa_supplicant/Makefile
-+++ b/wpa_supplicant/Makefile
-@@ -108,6 +108,8 @@ OBJS_c += ../src/utils/common.o
- OBJS_c += ../src/common/cli.o
- OBJS += wmm_ac.o
-
-+OBJS += ../src/common/wpa_ctrl.o
-+
- ifndef CONFIG_OS
- ifdef CONFIG_NATIVE_WINDOWS
- CONFIG_OS=win32
---- a/wpa_supplicant/bss.c
-+++ b/wpa_supplicant/bss.c
-@@ -11,6 +11,7 @@
- #include "utils/common.h"
- #include "utils/eloop.h"
- #include "common/ieee802_11_defs.h"
-+#include "common/ieee802_11_common.h"
- #include "drivers/driver.h"
- #include "eap_peer/eap.h"
- #include "wpa_supplicant_i.h"
-@@ -282,6 +283,10 @@ void calculate_update_time(const struct
- static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
- struct os_reltime *fetch_time)
- {
-+ struct ieee80211_ht_capabilities *capab;
-+ struct ieee80211_ht_operation *oper;
-+ struct ieee802_11_elems elems;
-+
- dst->flags = src->flags;
- os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
- dst->freq = src->freq;
-@@ -294,6 +299,15 @@ static void wpa_bss_copy_res(struct wpa_
- dst->est_throughput = src->est_throughput;
- dst->snr = src->snr;
-
-+ memset(&elems, 0, sizeof(elems));
-+ ieee802_11_parse_elems((u8 *) (src + 1), src->ie_len, &elems, 0);
-+ capab = (struct ieee80211_ht_capabilities *) elems.ht_capabilities;
-+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
-+ if (capab)
-+ dst->ht_capab = le_to_host16(capab->ht_capabilities_info);
-+ if (oper)
-+ dst->ht_param = oper->ht_param;
-+
- calculate_update_time(fetch_time, src->age, &dst->last_update);
- }
-
---- a/wpa_supplicant/bss.h
-+++ b/wpa_supplicant/bss.h
-@@ -94,6 +94,10 @@ struct wpa_bss {
- u8 ssid[SSID_MAX_LEN];
- /** Length of SSID */
- size_t ssid_len;
-+ /** HT capabilities */
-+ u16 ht_capab;
-+ /* Five octets of HT Operation Information */
-+ u8 ht_param;
- /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
- int freq;
- /** Beacon interval in TUs (host byte order) */
---- a/wpa_supplicant/main.c
-+++ b/wpa_supplicant/main.c
-@@ -34,7 +34,7 @@ static void usage(void)
- "vW] [-P<pid file>] "
- "[-g<global ctrl>] \\\n"
- " [-G<group>] \\\n"
-- " -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
-+ " -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-H<hostapd path>] "
- "[-p<driver_param>] \\\n"
- " [-b<br_ifname>] [-e<entropy file>]"
- #ifdef CONFIG_DEBUG_FILE
-@@ -74,6 +74,7 @@ static void usage(void)
- " -g = global ctrl_interface\n"
- " -G = global ctrl_interface group\n"
- " -h = show this help text\n"
-+ " -H = connect to a hostapd instance to manage state changes\n"
- " -i = interface name\n"
- " -I = additional configuration file\n"
- " -K = include keys (passwords, etc.) in debug output\n"
-@@ -201,7 +202,7 @@ int main(int argc, char *argv[])
-
- for (;;) {
- c = getopt(argc, argv,
-- "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
-+ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuvW");
- if (c < 0)
- break;
- switch (c) {
-@@ -248,6 +249,9 @@ int main(int argc, char *argv[])
- usage();
- exitcode = 0;
- goto out;
-+ case 'H':
-+ iface->hostapd_ctrl = optarg;
-+ break;
- case 'i':
- iface->ifname = optarg;
- break;
---- a/wpa_supplicant/wpa_supplicant.c
-+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -130,6 +130,54 @@ static void wpas_update_fils_connect_par
- static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
- #endif /* CONFIG_OWE */
-
-+static int hostapd_stop(struct wpa_supplicant *wpa_s)
-+{
-+ const char *cmd = "STOP_AP";
-+ char buf[256];
-+ size_t len = sizeof(buf);
-+
-+ if (wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL) < 0) {
-+ wpa_printf(MSG_ERROR, "\nFailed to stop hostapd AP interfaces\n");
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static int hostapd_reload(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-+{
-+ char *cmd = NULL;
-+ char buf[256];
-+ size_t len = sizeof(buf);
-+ enum hostapd_hw_mode hw_mode;
-+ u8 channel;
-+ int sec_chan = 0;
-+ int ret;
-+
-+ if (!bss)
-+ return -1;
-+
-+ if (bss->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
-+ int sec = bss->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
-+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
-+ sec_chan = 1;
-+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
-+ sec_chan = -1;
-+ }
-+
-+ hw_mode = ieee80211_freq_to_chan(bss->freq, &channel);
-+ if (asprintf(&cmd, "UPDATE channel=%d sec_chan=%d hw_mode=%d",
-+ channel, sec_chan, hw_mode) < 0)
-+ return -1;
-+
-+ ret = wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL);
-+ free(cmd);
-+
-+ if (ret < 0) {
-+ wpa_printf(MSG_ERROR, "\nFailed to reload hostapd AP interfaces\n");
-+ return -1;
-+ }
-+ return 0;
-+}
-
- #ifdef CONFIG_WEP
- /* Configure default/group WEP keys for static WEP */
-@@ -1007,6 +1055,8 @@ void wpa_supplicant_set_state(struct wpa
-
- sme_sched_obss_scan(wpa_s, 1);
-
-+ if (wpa_s->hostapd)
-+ hostapd_reload(wpa_s, wpa_s->current_bss);
- #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
- if (!fils_hlp_sent && ssid && ssid->eap.erp)
- update_fils_connect_params = true;
-@@ -1017,6 +1067,8 @@ void wpa_supplicant_set_state(struct wpa
- #endif /* CONFIG_OWE */
- } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
- state == WPA_ASSOCIATED) {
-+ if (wpa_s->hostapd)
-+ hostapd_stop(wpa_s);
- wpa_s->new_connection = 1;
- wpa_drv_set_operstate(wpa_s, 0);
- #ifndef IEEE8021X_EAPOL
-@@ -2276,6 +2328,8 @@ void wpa_supplicant_associate(struct wpa
- return;
- }
- wpa_s->current_bss = bss;
-+ if (wpa_s->hostapd)
-+ hostapd_reload(wpa_s, wpa_s->current_bss);
- #else /* CONFIG_MESH */
- wpa_msg(wpa_s, MSG_ERROR,
- "mesh mode support not included in the build");
-@@ -6426,6 +6480,16 @@ static int wpa_supplicant_init_iface(str
- sizeof(wpa_s->bridge_ifname));
- }
-
-+ if (iface->hostapd_ctrl) {
-+ wpa_s->hostapd = wpa_ctrl_open(iface->hostapd_ctrl);
-+ if (!wpa_s->hostapd) {
-+ wpa_printf(MSG_ERROR, "\nFailed to connect to hostapd\n");
-+ return -1;
-+ }
-+ if (hostapd_stop(wpa_s) < 0)
-+ return -1;
-+ }
-+
- /* RSNA Supplicant Key Management - INITIALIZE */
- eapol_sm_notify_portEnabled(wpa_s->eapol, false);
- eapol_sm_notify_portValid(wpa_s->eapol, false);
-@@ -6763,6 +6827,11 @@ static void wpa_supplicant_deinit_iface(
- if (terminate)
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
-
-+ if (wpa_s->hostapd) {
-+ wpa_ctrl_close(wpa_s->hostapd);
-+ wpa_s->hostapd = NULL;
-+ }
-+
- wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
-
---- a/wpa_supplicant/wpa_supplicant_i.h
-+++ b/wpa_supplicant/wpa_supplicant_i.h
-@@ -103,6 +103,11 @@ struct wpa_interface {
- const char *ifname;
-
- /**
-+ * hostapd_ctrl - path to hostapd control socket for notification
-+ */
-+ const char *hostapd_ctrl;
-+
-+ /**
- * bridge_ifname - Optional bridge interface name
- *
- * If the driver interface (ifname) is included in a Linux bridge
-@@ -615,6 +620,8 @@ struct wpa_supplicant {
- #endif /* CONFIG_CTRL_IFACE_BINDER */
- char bridge_ifname[16];
-
-+ struct wpa_ctrl *hostapd;
-+
- char *confname;
- char *confanother;
-
---- a/hostapd/ctrl_iface.c
-+++ b/hostapd/ctrl_iface.c
-@@ -2883,6 +2883,11 @@ static int hostapd_ctrl_iface_chan_switc
- return 0;
- }
-
-+ if (os_strstr(pos, " auto-ht")) {
-+ settings.freq_params.ht_enabled = iface->conf->ieee80211n;
-+ settings.freq_params.vht_enabled = iface->conf->ieee80211ac;
-+ }
-+
- for (i = 0; i < iface->num_bss; i++) {
-
- /* Save CHAN_SWITCH VHT and HE config */
---- a/src/ap/beacon.c
-+++ b/src/ap/beacon.c
-@@ -1758,11 +1758,6 @@ int ieee802_11_set_beacon(struct hostapd
- return -1;
- }
-
-- if (hapd->csa_in_progress) {
-- wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
-- return -1;
-- }
--
- hapd->beacon_set_done = 1;
-
- if (ieee802_11_build_ap_params(hapd, &params) < 0)
---- a/wpa_supplicant/events.c
-+++ b/wpa_supplicant/events.c
-@@ -4665,6 +4665,60 @@ static void wpas_event_unprot_beacon(str
- }
-
-
-+static void
-+supplicant_ch_switch_started(struct wpa_supplicant *wpa_s,
-+ union wpa_event_data *data)
-+{
-+ char buf[256];
-+ size_t len = sizeof(buf);
-+ char *cmd = NULL;
-+ int width = 20;
-+ int ret;
-+
-+ if (!wpa_s->hostapd)
-+ return;
-+
-+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
-+ "count=%d freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
-+ data->ch_switch.count,
-+ data->ch_switch.freq,
-+ data->ch_switch.ht_enabled,
-+ data->ch_switch.ch_offset,
-+ channel_width_to_string(data->ch_switch.ch_width),
-+ data->ch_switch.cf1,
-+ data->ch_switch.cf2);
-+
-+ switch (data->ch_switch.ch_width) {
-+ case CHAN_WIDTH_20_NOHT:
-+ case CHAN_WIDTH_20:
-+ width = 20;
-+ break;
-+ case CHAN_WIDTH_40:
-+ width = 40;
-+ break;
-+ case CHAN_WIDTH_80:
-+ width = 80;
-+ break;
-+ case CHAN_WIDTH_160:
-+ case CHAN_WIDTH_80P80:
-+ width = 160;
-+ break;
-+ }
-+
-+ asprintf(&cmd, "CHAN_SWITCH %d %d sec_channel_offset=%d center_freq1=%d center_freq2=%d, bandwidth=%d auto-ht\n",
-+ data->ch_switch.count - 1,
-+ data->ch_switch.freq,
-+ data->ch_switch.ch_offset,
-+ data->ch_switch.cf1,
-+ data->ch_switch.cf2,
-+ width);
-+ ret = wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL);
-+ free(cmd);
-+
-+ if (ret < 0)
-+ wpa_printf(MSG_ERROR, "\nFailed to reload hostapd AP interfaces\n");
-+}
-+
- void supplicant_event(void *ctx, enum wpa_event_type event,
- union wpa_event_data *data)
- {
-@@ -4980,8 +5034,10 @@ void supplicant_event(void *ctx, enum wp
- channel_width_to_string(data->ch_switch.ch_width),
- data->ch_switch.cf1,
- data->ch_switch.cf2);
-- if (event == EVENT_CH_SWITCH_STARTED)
-+ if (event == EVENT_CH_SWITCH_STARTED) {
-+ supplicant_ch_switch_started(wpa_s, data);
- break;
-+ }
-
- wpa_s->assoc_freq = data->ch_switch.freq;
- wpa_s->current_ssid->frequency = data->ch_switch.freq;
---- a/src/drivers/driver.h
-+++ b/src/drivers/driver.h
-@@ -5829,6 +5829,7 @@ union wpa_event_data {
-
- /**
- * struct ch_switch
-+ * @count: Count until channel switch activates
- * @freq: Frequency of new channel in MHz
- * @ht_enabled: Whether this is an HT channel
- * @ch_offset: Secondary channel offset
-@@ -5837,6 +5838,7 @@ union wpa_event_data {
- * @cf2: Center frequency 2
- */
- struct ch_switch {
-+ int count;
- int freq;
- int ht_enabled;
- int ch_offset;
---- a/src/drivers/driver_nl80211_event.c
-+++ b/src/drivers/driver_nl80211_event.c
-@@ -684,7 +684,7 @@ static void mlme_event_ch_switch(struct
- struct nlattr *ifindex, struct nlattr *freq,
- struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2,
-- int finished)
-+ struct nlattr *count, int finished)
- {
- struct i802_bss *bss;
- union wpa_event_data data;
-@@ -745,6 +745,8 @@ static void mlme_event_ch_switch(struct
- data.ch_switch.cf1 = nla_get_u32(cf1);
- if (cf2)
- data.ch_switch.cf2 = nla_get_u32(cf2);
-+ if (count)
-+ data.ch_switch.count = nla_get_u32(count);
-
- if (finished)
- bss->freq = data.ch_switch.freq;
-@@ -3003,6 +3005,7 @@ static void do_process_drv_event(struct
- tb[NL80211_ATTR_CHANNEL_WIDTH],
- tb[NL80211_ATTR_CENTER_FREQ1],
- tb[NL80211_ATTR_CENTER_FREQ2],
-+ tb[NL80211_ATTR_CH_SWITCH_COUNT],
- 0);
- break;
- case NL80211_CMD_CH_SWITCH_NOTIFY:
-@@ -3013,6 +3016,7 @@ static void do_process_drv_event(struct
- tb[NL80211_ATTR_CHANNEL_WIDTH],
- tb[NL80211_ATTR_CENTER_FREQ1],
- tb[NL80211_ATTR_CENTER_FREQ2],
-+ NULL,
- 1);
- break;
- case NL80211_CMD_DISCONNECT:
diff --git a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch
index ca634077b72..f7720fce2fa 100644
--- a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch
+++ b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch
@@ -12,7 +12,7 @@
else
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
-@@ -3569,6 +3569,7 @@ static int hostapd_ctrl_iface_receive_pr
+@@ -3314,6 +3314,7 @@ static int hostapd_ctrl_iface_receive_pr
reply_size);
} else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
reply_len = hostapd_drv_status(hapd, reply, reply_size);
@@ -20,7 +20,7 @@
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
if (reply_len >= 0) {
-@@ -3610,6 +3611,7 @@ static int hostapd_ctrl_iface_receive_pr
+@@ -3355,6 +3356,7 @@ static int hostapd_ctrl_iface_receive_pr
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
reply_size);
@@ -30,7 +30,7 @@
reply_len = -1;
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
-@@ -955,6 +955,9 @@ ifdef CONFIG_FILS
+@@ -983,6 +983,9 @@ ifdef CONFIG_FILS
OBJS += ../src/ap/fils_hlp.o
endif
ifdef CONFIG_CTRL_IFACE
@@ -42,7 +42,7 @@
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
-@@ -2308,7 +2308,7 @@ static int wpa_supplicant_ctrl_iface_sta
+@@ -2326,7 +2326,7 @@ static int wpa_supplicant_ctrl_iface_sta
pos += ret;
}
@@ -51,7 +51,7 @@
if (wpa_s->ap_iface) {
pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
end - pos,
-@@ -10919,6 +10919,7 @@ char * wpa_supplicant_ctrl_iface_process
+@@ -12087,6 +12087,7 @@ char * wpa_supplicant_ctrl_iface_process
reply_len = -1;
} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
@@ -59,7 +59,7 @@
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
if (reply_len >= 0) {
-@@ -10931,6 +10932,7 @@ char * wpa_supplicant_ctrl_iface_process
+@@ -12099,6 +12100,7 @@ char * wpa_supplicant_ctrl_iface_process
reply_size - reply_len);
#endif /* CONFIG_MACSEC */
}
@@ -67,7 +67,7 @@
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
wpa_s, buf + 6, reply, reply_size);
-@@ -11419,6 +11421,7 @@ char * wpa_supplicant_ctrl_iface_process
+@@ -12587,6 +12589,7 @@ char * wpa_supplicant_ctrl_iface_process
reply_len = wpa_supplicant_ctrl_iface_bss(
wpa_s, buf + 4, reply, reply_size);
#ifdef CONFIG_AP
@@ -75,7 +75,7 @@
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
} else if (os_strncmp(buf, "STA ", 4) == 0) {
-@@ -11427,12 +11430,15 @@ char * wpa_supplicant_ctrl_iface_process
+@@ -12595,12 +12598,15 @@ char * wpa_supplicant_ctrl_iface_process
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
reply_size);
@@ -93,15 +93,61 @@
reply_len = -1;
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
-@@ -25,6 +25,7 @@
- #include "mbo_ap.h"
+@@ -26,6 +26,26 @@
#include "taxonomy.h"
-
+ #include "wnm_ap.h"
+
++static const char * hw_mode_str(enum hostapd_hw_mode mode)
++{
++ switch (mode) {
++ case HOSTAPD_MODE_IEEE80211B:
++ return "b";
++ case HOSTAPD_MODE_IEEE80211G:
++ return "g";
++ case HOSTAPD_MODE_IEEE80211A:
++ return "a";
++ case HOSTAPD_MODE_IEEE80211AD:
++ return "ad";
++ case HOSTAPD_MODE_IEEE80211ANY:
++ return "any";
++ case NUM_HOSTAPD_MODES:
++ return "invalid";
++ }
++ return "unknown";
++}
++
+#ifdef CONFIG_CTRL_IFACE_MIB
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
size_t curr_len, const u8 *mcs_set)
-@@ -451,6 +452,7 @@ int hostapd_ctrl_iface_sta_next(struct h
+@@ -212,26 +232,6 @@ static const char * timeout_next_str(int
+ }
+
+
+-static const char * hw_mode_str(enum hostapd_hw_mode mode)
+-{
+- switch (mode) {
+- case HOSTAPD_MODE_IEEE80211B:
+- return "b";
+- case HOSTAPD_MODE_IEEE80211G:
+- return "g";
+- case HOSTAPD_MODE_IEEE80211A:
+- return "a";
+- case HOSTAPD_MODE_IEEE80211AD:
+- return "ad";
+- case HOSTAPD_MODE_IEEE80211ANY:
+- return "any";
+- case NUM_HOSTAPD_MODES:
+- return "invalid";
+- }
+- return "unknown";
+-}
+-
+-
+ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ char *buf, size_t buflen)
+@@ -493,6 +493,7 @@ int hostapd_ctrl_iface_sta_next(struct h
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
@@ -109,7 +155,7 @@
#ifdef CONFIG_P2P_MANAGER
static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
-@@ -807,12 +809,12 @@ int hostapd_ctrl_iface_status(struct hos
+@@ -884,12 +885,12 @@ int hostapd_ctrl_iface_status(struct hos
return len;
len += ret;
}
@@ -126,7 +172,7 @@
if (os_snprintf_error(buflen - len, ret))
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
-@@ -2712,6 +2712,7 @@ static const char * bool_txt(bool val)
+@@ -2834,6 +2834,7 @@ static const char * bool_txt(bool val)
return val ? "TRUE" : "FALSE";
}
@@ -134,7 +180,7 @@
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
{
-@@ -2898,6 +2899,7 @@ int ieee802_1x_get_mib_sta(struct hostap
+@@ -3020,6 +3021,7 @@ int ieee802_1x_get_mib_sta(struct hostap
return len;
}
@@ -144,7 +190,7 @@
static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
-@@ -4519,6 +4519,7 @@ static const char * wpa_bool_txt(int val
+@@ -5328,6 +5328,7 @@ static const char * wpa_bool_txt(int val
return val ? "TRUE" : "FALSE";
}
@@ -152,7 +198,7 @@
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
-@@ -4669,7 +4670,7 @@ int wpa_get_mib_sta(struct wpa_state_mac
+@@ -5480,7 +5481,7 @@ int wpa_get_mib_sta(struct wpa_state_mac
return len;
}
@@ -163,7 +209,7 @@
{
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
-@@ -2767,6 +2767,8 @@ static u32 wpa_key_mgmt_suite(struct wpa
+@@ -3834,6 +3834,8 @@ static u32 wpa_key_mgmt_suite(struct wpa
}
@@ -172,7 +218,7 @@
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
-@@ -2848,6 +2850,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch
+@@ -3915,6 +3917,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch
return (int) len;
}
@@ -182,7 +228,7 @@
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
-@@ -1364,7 +1364,7 @@ int wpas_ap_wps_nfc_report_handover(stru
+@@ -1499,7 +1499,7 @@ int wpas_ap_wps_nfc_report_handover(stru
#endif /* CONFIG_WPS */
diff --git a/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch b/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch
index d2414faf01f..e9083f6ecc6 100644
--- a/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch
+++ b/package/network/services/hostapd/patches/381-hostapd_cli_UNKNOWN-COMMAND.patch
@@ -1,6 +1,6 @@
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
-@@ -744,7 +744,7 @@ static int wpa_ctrl_command_sta(struct w
+@@ -757,7 +757,7 @@ static int wpa_ctrl_command_sta(struct w
}
buf[len] = '\0';
diff --git a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch
index 65a8b07e65a..4592c341277 100644
--- a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch
+++ b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch
@@ -1,6 +1,6 @@
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
-@@ -2444,6 +2444,31 @@ u32 wpa_akm_to_suite(int akm)
+@@ -2841,6 +2841,31 @@ u32 wpa_akm_to_suite(int akm)
}
@@ -32,7 +32,7 @@
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len)
-@@ -2451,8 +2476,19 @@ int wpa_compare_rsn_ie(int ft_initial_as
+@@ -2848,8 +2873,19 @@ int wpa_compare_rsn_ie(int ft_initial_as
if (ie1 == NULL || ie2 == NULL)
return -1;
diff --git a/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch b/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch
index 73a8c7694d5..edcd9852574 100644
--- a/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch
+++ b/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch
@@ -11,7 +11,7 @@
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = bss->wpa_pairwise;
-@@ -1178,8 +1177,7 @@ int hostapd_init_wps(struct hostapd_data
+@@ -1181,8 +1180,7 @@ int hostapd_init_wps(struct hostapd_data
WPA_CIPHER_GCMP_256)) {
wps->encr_types |= WPS_ENCR_AES;
wps->encr_types_rsn |= WPS_ENCR_AES;
diff --git a/package/network/services/hostapd/patches/410-limit_debug_messages.patch b/package/network/services/hostapd/patches/410-limit_debug_messages.patch
index d2713fc29b2..48a5589200f 100644
--- a/package/network/services/hostapd/patches/410-limit_debug_messages.patch
+++ b/package/network/services/hostapd/patches/410-limit_debug_messages.patch
@@ -60,7 +60,7 @@
#ifdef CONFIG_DEBUG_FILE
static char *last_path = NULL;
#endif /* CONFIG_DEBUG_FILE */
-@@ -636,7 +610,7 @@ void wpa_msg_register_ifname_cb(wpa_msg_
+@@ -644,7 +618,7 @@ void wpa_msg_register_ifname_cb(wpa_msg_
}
@@ -69,7 +69,7 @@
{
va_list ap;
char *buf;
-@@ -674,7 +648,7 @@ void wpa_msg(void *ctx, int level, const
+@@ -682,7 +656,7 @@ void wpa_msg(void *ctx, int level, const
}
@@ -80,9 +80,9 @@
char *buf;
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
-@@ -50,6 +50,17 @@ int wpa_debug_reopen_file(void);
- void wpa_debug_close_file(void);
+@@ -51,6 +51,17 @@ void wpa_debug_close_file(void);
void wpa_debug_setup_stdout(void);
+ void wpa_debug_stop_log(void);
+/* internal */
+void _wpa_hexdump(int level, const char *title, const u8 *buf,
@@ -98,7 +98,7 @@
/**
* wpa_debug_printf_timestamp - Print timestamp for debug output
*
-@@ -70,9 +81,15 @@ void wpa_debug_print_timestamp(void);
+@@ -71,9 +82,15 @@ void wpa_debug_print_timestamp(void);
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
@@ -115,7 +115,7 @@
/**
* wpa_hexdump - conditional hex dump
* @level: priority level (MSG_*) of the message
-@@ -84,7 +101,13 @@ PRINTF_FORMAT(2, 3);
+@@ -85,7 +102,13 @@ PRINTF_FORMAT(2, 3);
* output may be directed to stdout, stderr, and/or syslog based on
* configuration. The contents of buf is printed out has hex dump.
*/
@@ -130,7 +130,7 @@
static inline void wpa_hexdump_buf(int level, const char *title,
const struct wpabuf *buf)
-@@ -106,7 +129,13 @@ static inline void wpa_hexdump_buf(int l
+@@ -107,7 +130,13 @@ static inline void wpa_hexdump_buf(int l
* like wpa_hexdump(), but by default, does not include secret keys (passwords,
* etc.) in debug output.
*/
@@ -145,7 +145,7 @@
static inline void wpa_hexdump_buf_key(int level, const char *title,
const struct wpabuf *buf)
-@@ -128,8 +157,14 @@ static inline void wpa_hexdump_buf_key(i
+@@ -129,8 +158,14 @@ static inline void wpa_hexdump_buf_key(i
* the hex numbers and ASCII characters (for printable range) are shown. 16
* bytes per line will be shown.
*/
@@ -162,7 +162,7 @@
/**
* wpa_hexdump_ascii_key - conditional hex dump, hide keys
-@@ -145,8 +180,14 @@ void wpa_hexdump_ascii(int level, const
+@@ -146,8 +181,14 @@ void wpa_hexdump_ascii(int level, const
* bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
* default, does not include secret keys (passwords, etc.) in debug output.
*/
@@ -179,7 +179,7 @@
/*
* wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
-@@ -183,7 +224,12 @@ void wpa_hexdump_ascii_key(int level, co
+@@ -184,7 +225,12 @@ void wpa_hexdump_ascii_key(int level, co
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
@@ -193,7 +193,7 @@
/**
* wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
-@@ -197,8 +243,13 @@ void wpa_msg(void *ctx, int level, const
+@@ -198,8 +244,13 @@ void wpa_msg(void *ctx, int level, const
* attached ctrl_iface monitors. In other words, it can be used for frequent
* events that do not need to be sent to syslog.
*/
diff --git a/package/network/services/hostapd/patches/420-indicate-features.patch b/package/network/services/hostapd/patches/420-indicate-features.patch
index f9dff66073c..07df8e5a9af 100644
--- a/package/network/services/hostapd/patches/420-indicate-features.patch
+++ b/package/network/services/hostapd/patches/420-indicate-features.patch
@@ -1,23 +1,24 @@
--- a/hostapd/main.c
+++ b/hostapd/main.c
-@@ -15,6 +15,7 @@
- #include "utils/common.h"
- #include "utils/eloop.h"
- #include "utils/uuid.h"
-+#include "utils/build_features.h"
- #include "crypto/random.h"
- #include "crypto/tls.h"
- #include "common/version.h"
-@@ -691,7 +692,7 @@ int main(int argc, char *argv[])
+@@ -31,7 +31,7 @@
+ #include "config_file.h"
+ #include "eap_register.h"
+ #include "ctrl_iface.h"
+-
++#include "build_features.h"
+
+ struct hapd_global {
+ void **drv_priv;
+@@ -799,7 +799,7 @@ int main(int argc, char *argv[])
wpa_supplicant_event = hostapd_wpa_event;
wpa_supplicant_event_global = hostapd_wpa_event_global;
for (;;) {
-- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
-+ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:v::");
+- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q");
++ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:qv::");
if (c < 0)
break;
switch (c) {
-@@ -728,6 +729,8 @@ int main(int argc, char *argv[])
+@@ -836,6 +836,8 @@ int main(int argc, char *argv[])
break;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 'v':
@@ -25,7 +26,7 @@
+ exit(!has_feature(optarg));
show_version();
exit(1);
- break;
+ case 'g':
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -12,6 +12,7 @@
@@ -33,19 +34,19 @@
#include "common.h"
+#include "build_features.h"
+ #include "crypto/crypto.h"
#include "fst/fst.h"
#include "wpa_supplicant_i.h"
- #include "driver_i.h"
@@ -202,7 +203,7 @@ int main(int argc, char *argv[])
for (;;) {
c = getopt(argc, argv,
-- "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuvW");
-+ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuv::W");
+- "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
++ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuv::W");
if (c < 0)
break;
switch (c) {
-@@ -305,8 +306,12 @@ int main(int argc, char *argv[])
+@@ -302,8 +303,12 @@ int main(int argc, char *argv[])
break;
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
case 'v':
diff --git a/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch b/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch
index dc1fa3d29d9..a21f0bf7cee 100644
--- a/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch
+++ b/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch
@@ -1,6 +1,6 @@
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
-@@ -388,7 +388,6 @@ static int hostapd_cli_cmd_disassociate(
+@@ -401,7 +401,6 @@ static int hostapd_cli_cmd_disassociate(
}
@@ -8,7 +8,7 @@
static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
-@@ -401,7 +400,6 @@ static int hostapd_cli_cmd_signature(str
+@@ -414,7 +413,6 @@ static int hostapd_cli_cmd_signature(str
os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
@@ -16,7 +16,7 @@
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
-@@ -418,7 +416,6 @@ static int hostapd_cli_cmd_sa_query(stru
+@@ -431,7 +429,6 @@ static int hostapd_cli_cmd_sa_query(stru
}
@@ -24,7 +24,7 @@
static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
-@@ -644,7 +641,6 @@ static int hostapd_cli_cmd_wps_config(st
+@@ -657,7 +654,6 @@ static int hostapd_cli_cmd_wps_config(st
ssid_hex, argv[1]);
return wpa_ctrl_command(ctrl, buf);
}
@@ -32,7 +32,7 @@
static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
-@@ -1579,13 +1575,10 @@ static const struct hostapd_cli_cmd host
+@@ -1610,13 +1606,10 @@ static const struct hostapd_cli_cmd host
{ "disassociate", hostapd_cli_cmd_disassociate,
hostapd_complete_stations,
"<addr> = disassociate a station" },
@@ -46,7 +46,7 @@
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
-@@ -1610,7 +1603,6 @@ static const struct hostapd_cli_cmd host
+@@ -1641,7 +1634,6 @@ static const struct hostapd_cli_cmd host
"<SSID> <auth> <encr> <key> = configure AP" },
{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
"= show current WPS status" },
diff --git a/package/network/services/hostapd/patches/432-missing-typedef.patch b/package/network/services/hostapd/patches/432-missing-typedef.patch
deleted file mode 100644
index 7a100f1a0d2..00000000000
--- a/package/network/services/hostapd/patches/432-missing-typedef.patch
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/src/drivers/linux_wext.h
-+++ b/src/drivers/linux_wext.h
-@@ -26,6 +26,7 @@ typedef int32_t __s32;
- typedef uint16_t __u16;
- typedef int16_t __s16;
- typedef uint8_t __u8;
-+typedef int8_t __s8;
- #ifndef __user
- #define __user
- #endif /* __user */
diff --git a/package/network/services/hostapd/patches/450-scan_wait.patch b/package/network/services/hostapd/patches/450-scan_wait.patch
deleted file mode 100644
index ac874ad66a4..00000000000
--- a/package/network/services/hostapd/patches/450-scan_wait.patch
+++ /dev/null
@@ -1,73 +0,0 @@
---- a/hostapd/main.c
-+++ b/hostapd/main.c
-@@ -39,6 +39,8 @@ struct hapd_global {
- };
-
- static struct hapd_global global;
-+static int daemonize = 0;
-+static char *pid_file = NULL;
-
-
- #ifndef CONFIG_NO_HOSTAPD_LOGGER
-@@ -146,6 +148,14 @@ static void hostapd_logger_cb(void *ctx,
- }
- #endif /* CONFIG_NO_HOSTAPD_LOGGER */
-
-+static void hostapd_setup_complete_cb(void *ctx)
-+{
-+ if (daemonize && os_daemonize(pid_file)) {
-+ perror("daemon");
-+ return;
-+ }
-+ daemonize = 0;
-+}
-
- /**
- * hostapd_driver_init - Preparate driver interface
-@@ -164,6 +174,8 @@ static int hostapd_driver_init(struct ho
- return -1;
- }
-
-+ hapd->setup_complete_cb = hostapd_setup_complete_cb;
-+
- /* Initialize the driver interface */
- if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
- b = NULL;
-@@ -404,8 +416,6 @@ static void hostapd_global_deinit(const
- #endif /* CONFIG_NATIVE_WINDOWS */
-
- eap_server_unregister_methods();
--
-- os_daemonize_terminate(pid_file);
- }
-
-
-@@ -431,18 +441,6 @@ static int hostapd_global_run(struct hap
- }
- #endif /* EAP_SERVER_TNC */
-
-- if (daemonize) {
-- if (os_daemonize(pid_file)) {
-- wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
-- return -1;
-- }
-- if (eloop_sock_requeue()) {
-- wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
-- strerror(errno));
-- return -1;
-- }
-- }
--
- eloop_run();
-
- return 0;
-@@ -645,8 +643,7 @@ int main(int argc, char *argv[])
- struct hapd_interfaces interfaces;
- int ret = 1;
- size_t i, j;
-- int c, debug = 0, daemonize = 0;
-- char *pid_file = NULL;
-+ int c, debug = 0;
- const char *log_file = NULL;
- const char *entropy_file = NULL;
- char **bss_config = NULL, **tmp_bss;
diff --git a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch
index e0e687e1613..dc19553e26e 100644
--- a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch
+++ b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch
@@ -22,7 +22,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org>
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_common.h"
-@@ -851,6 +852,9 @@ struct wpa_driver_associate_params {
+@@ -953,6 +954,9 @@ struct wpa_driver_associate_params {
* responsible for selecting with which BSS to associate. */
const u8 *bssid;
@@ -42,7 +42,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org>
#include "config.h"
-@@ -2321,6 +2322,97 @@ static char * wpa_config_write_peerkey(c
+@@ -2389,6 +2390,97 @@ static char * wpa_config_write_mac_value
#endif /* NO_CONFIG_WRITE */
@@ -140,7 +140,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org>
/* Helper macros for network block parser */
#ifdef OFFSET
-@@ -2606,6 +2698,8 @@ static const struct parse_data ssid_fiel
+@@ -2674,6 +2766,8 @@ static const struct parse_data ssid_fiel
{ INT(ap_max_inactivity) },
{ INT(dtim_period) },
{ INT(beacon_int) },
@@ -162,7 +162,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org>
#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
-@@ -843,6 +845,9 @@ struct wpa_ssid {
+@@ -879,6 +881,9 @@ struct wpa_ssid {
*/
void *parent_cred;
@@ -174,7 +174,7 @@ Signed-hostap: Antonio Quartulli <ordex@autistici.org>
* macsec_policy - Determines the policy for MACsec secure session
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -3726,6 +3726,12 @@ static void wpas_start_assoc_cb(struct w
+@@ -4177,6 +4177,12 @@ static void wpas_start_assoc_cb(struct w
params.beacon_int = ssid->beacon_int;
else
params.beacon_int = wpa_s->conf->beacon_int;
diff --git a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch b/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch
deleted file mode 100644
index 1d2a053faaf..00000000000
--- a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From ffc4445958a3ed4064f2e1bf73fa478a61c5cf7b Mon Sep 17 00:00:00 2001
-From: Antonio Quartulli <ordex@autistici.org>
-Date: Sun, 3 Jun 2012 18:42:25 +0200
-Subject: [PATCHv2 602/602] driver_nl80211: use new parameters during ibss join
-
-Signed-hostap: Antonio Quartulli <ordex@autistici.org>
----
- src/drivers/driver_nl80211.c | 33 ++++++++++++++++++++++++++++++++-
- 1 file changed, 32 insertions(+), 1 deletion(-)
-
---- a/src/drivers/driver_nl80211.c
-+++ b/src/drivers/driver_nl80211.c
-@@ -5951,7 +5951,7 @@ static int wpa_driver_nl80211_ibss(struc
- struct wpa_driver_associate_params *params)
- {
- struct nl_msg *msg;
-- int ret = -1;
-+ int ret = -1, i;
- int count = 0;
-
- wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
-@@ -5978,6 +5978,37 @@ retry:
- nl80211_put_beacon_int(msg, params->beacon_int))
- goto fail;
-
-+ if (params->fixed_freq) {
-+ wpa_printf(MSG_DEBUG, " * fixed_freq");
-+ nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED);
-+ }
-+
-+ if (params->beacon_int > 0) {
-+ wpa_printf(MSG_DEBUG, " * beacon_int=%d",
-+ params->beacon_int);
-+ nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-+ params->beacon_int);
-+ }
-+
-+ if (params->rates[0] > 0) {
-+ wpa_printf(MSG_DEBUG, " * basic_rates:");
-+ i = 0;
-+ while (i < NL80211_MAX_SUPP_RATES &&
-+ params->rates[i] > 0) {
-+ wpa_printf(MSG_DEBUG, " %.1f",
-+ (double)params->rates[i] / 2);
-+ i++;
-+ }
-+ nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, i,
-+ params->rates);
-+ }
-+
-+ if (params->mcast_rate > 0) {
-+ wpa_printf(MSG_DEBUG, " * mcast_rate=%.1f",
-+ (double)params->mcast_rate / 10);
-+ nla_put_u32(msg, NL80211_ATTR_MCAST_RATE, params->mcast_rate);
-+ }
-+
- ret = nl80211_set_conn_keys(params, msg);
- if (ret)
- goto fail;
diff --git a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch
index 1794befe950..daa36c2f35c 100644
--- a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch
+++ b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch
@@ -19,7 +19,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com>
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
-@@ -1618,6 +1618,7 @@ struct wpa_driver_mesh_join_params {
+@@ -1827,6 +1827,7 @@ struct wpa_driver_mesh_join_params {
#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
unsigned int flags;
bool handle_dfs;
@@ -29,7 +29,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com>
struct wpa_driver_set_key_params {
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
-@@ -10476,6 +10476,18 @@ static int nl80211_put_mesh_id(struct nl
+@@ -11667,6 +11667,18 @@ static int nl80211_put_mesh_id(struct nl
}
@@ -48,7 +48,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com>
static int nl80211_put_mesh_config(struct nl_msg *msg,
struct wpa_driver_mesh_bss_params *params)
{
-@@ -10537,6 +10549,7 @@ static int nl80211_join_mesh(struct i802
+@@ -11728,6 +11740,7 @@ static int nl80211_join_mesh(struct i802
nl80211_put_basic_rates(msg, params->basic_rates) ||
nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
@@ -58,7 +58,7 @@ Tested-by: Simon Wunderlich <simon.wunderlich@openmesh.com>
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
-@@ -600,6 +600,7 @@ int wpa_supplicant_join_mesh(struct wpa_
+@@ -632,6 +632,7 @@ int wpa_supplicant_join_mesh(struct wpa_
params->meshid = ssid->ssid;
params->meshid_len = ssid->ssid_len;
diff --git a/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch b/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch
index 4c7cb9ea36f..4d7d85f4ab8 100644
--- a/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch
+++ b/package/network/services/hostapd/patches/464-fix-mesh-obss-check.patch
@@ -1,19 +1,13 @@
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -2457,11 +2457,13 @@ void ibss_mesh_setup_freq(struct wpa_sup
- for (j = 0; j < wpa_s->last_scan_res_used; j++) {
- struct wpa_bss *bss = wpa_s->last_scan_res[j];
+@@ -3040,6 +3040,10 @@ void ibss_mesh_setup_freq(struct wpa_sup
-- if (ssid->mode != WPAS_MODE_IBSS)
-+ /* Don't adjust control freq in case of fixed_freq */
-+ if (ssid->fixed_freq) {
-+ obss_scan = 0;
- break;
-+ }
+ freq->freq = ssid->frequency;
-- /* Don't adjust control freq in case of fixed_freq */
-- if (ssid->fixed_freq)
-+ if (ssid->mode != WPAS_MODE_IBSS)
- break;
++ if (ssid->fixed_freq) {
++ obss_scan = 0;
++ }
++
+ if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
+ struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
- if (!bss_is_ibss(bss))
diff --git a/package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch b/package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch
new file mode 100644
index 00000000000..7d3d94648e1
--- /dev/null
+++ b/package/network/services/hostapd/patches/465-hostapd-config-support-random-BSS-color.patch
@@ -0,0 +1,24 @@
+From c9304d3303d563ad6d2619f4e07864ed12f96889 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Sat, 14 May 2022 21:41:03 +0200
+Subject: [PATCH] hostapd: config: support random BSS color
+
+Configure the HE BSS color to a random value in case the config defines
+a BSS color which exceeds the max BSS color (63).
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ hostapd/config_file.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -3500,6 +3500,8 @@ static int hostapd_config_fill(struct ho
+ } else if (os_strcmp(buf, "he_bss_color") == 0) {
+ conf->he_op.he_bss_color = atoi(pos) & 0x3f;
+ conf->he_op.he_bss_color_disabled = 0;
++ if (atoi(pos) > 63)
++ conf->he_op.he_bss_color = os_random() % 63 + 1;
+ } else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
+ conf->he_op.he_bss_color_partial = atoi(pos);
+ } else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
diff --git a/package/network/services/hostapd/patches/470-survey_data_fallback.patch b/package/network/services/hostapd/patches/470-survey_data_fallback.patch
index efd82599d36..79ab48c5c27 100644
--- a/package/network/services/hostapd/patches/470-survey_data_fallback.patch
+++ b/package/network/services/hostapd/patches/470-survey_data_fallback.patch
@@ -1,44 +1,29 @@
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
-@@ -302,18 +302,12 @@ static void acs_fail(struct hostapd_ifac
- static long double
- acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
- {
-- long double factor, busy, total;
-+ long double factor, busy = 0, total;
-
- if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY)
- busy = survey->channel_time_busy;
- else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX)
- busy = survey->channel_time_rx;
-- else {
-- /* This shouldn't really happen as survey data is checked in
-- * acs_sanity_check() */
-- wpa_printf(MSG_ERROR, "ACS: Survey data missing");
-- return 0;
-- }
-
- total = survey->channel_time;
-
-@@ -422,20 +416,19 @@ static int acs_usable_bw160_chan(const s
+@@ -455,17 +455,17 @@ static int acs_get_bw_center_chan(int fr
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
+ survey->nf = -95;
- wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
+ wpa_printf(MSG_INFO,
+ "ACS: Survey for freq %d is missing noise floor",
+ survey->freq);
- return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
+ survey->channel_time = 0;
- wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
+ wpa_printf(MSG_INFO,
+ "ACS: Survey for freq %d is missing channel time",
+ survey->freq);
- return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
- !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
+@@ -473,7 +473,6 @@ static int acs_survey_is_sufficient(stru
wpa_printf(MSG_INFO,
- "ACS: Survey is missing RX and busy time (at least one is required)");
+ "ACS: Survey for freq %d is missing RX and busy time (at least one is required)",
+ survey->freq);
- return 0;
}
diff --git a/package/network/services/hostapd/patches/500-lto-jobserver-support.patch b/package/network/services/hostapd/patches/500-lto-jobserver-support.patch
index 1475590d063..67312c5004a 100644
--- a/package/network/services/hostapd/patches/500-lto-jobserver-support.patch
+++ b/package/network/services/hostapd/patches/500-lto-jobserver-support.patch
@@ -1,6 +1,6 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
-@@ -1293,7 +1293,7 @@ hostapd_multi.a: $(BCHECK) $(OBJS)
+@@ -1396,7 +1396,7 @@ hostapd_multi.a: $(BCHECK) $(OBJS)
@$(AR) cr $@ hostapd_multi.o $(OBJS)
hostapd: $(OBJS)
@@ -9,7 +9,7 @@
@$(E) " LD " $@
ifdef CONFIG_WPA_TRACE
-@@ -1304,7 +1304,7 @@ _OBJS_VAR := OBJS_c
+@@ -1407,7 +1407,7 @@ _OBJS_VAR := OBJS_c
include ../src/objs.mk
hostapd_cli: $(OBJS_c)
@@ -20,7 +20,7 @@
NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS)
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
-@@ -1918,31 +1918,31 @@ wpa_supplicant_multi.a: .config $(BCHECK
+@@ -2037,31 +2037,31 @@ wpa_supplicant_multi.a: .config $(BCHECK
@$(AR) cr $@ wpa_supplicant_multi.o $(OBJS)
wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
diff --git a/package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch b/package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch
new file mode 100644
index 00000000000..0efa6db9085
--- /dev/null
+++ b/package/network/services/hostapd/patches/590-rrm-wnm-statistics.patch
@@ -0,0 +1,92 @@
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -163,6 +163,21 @@ struct hostapd_sae_commit_queue {
+ };
+
+ /**
++ * struct hostapd_openwrt_stats - OpenWrt custom STA/AP statistics
++ */
++struct hostapd_openwrt_stats {
++ struct {
++ u64 neighbor_report_tx;
++ } rrm;
++
++ struct {
++ u64 bss_transition_query_rx;
++ u64 bss_transition_request_tx;
++ u64 bss_transition_response_rx;
++ } wnm;
++};
++
++/**
+ * struct hostapd_data - hostapd per-BSS data structure
+ */
+ struct hostapd_data {
+@@ -182,6 +197,9 @@ struct hostapd_data {
+
+ struct hostapd_data *mld_first_bss;
+
++ /* OpenWrt specific statistics */
++ struct hostapd_openwrt_stats openwrt_stats;
++
+ int num_sta; /* number of entries in sta_list */
+ struct sta_info *sta_list; /* STA info list head */
+ #define STA_HASH_SIZE 256
+--- a/src/ap/wnm_ap.c
++++ b/src/ap/wnm_ap.c
+@@ -386,6 +386,7 @@ static int ieee802_11_send_bss_trans_mgm
+ mgmt->u.action.u.bss_tm_req.validity_interval = 1;
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
++ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
+ MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
+ "validity_interval=%u",
+@@ -790,10 +791,12 @@ int ieee802_11_rx_wnm_action_ap(struct h
+ plen);
+ return 0;
+ case WNM_BSS_TRANS_MGMT_QUERY:
++ hapd->openwrt_stats.wnm.bss_transition_query_rx++;
+ ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
+ case WNM_BSS_TRANS_MGMT_RESP:
++ hapd->openwrt_stats.wnm.bss_transition_response_rx++;
+ ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
+@@ -840,6 +843,7 @@ int wnm_send_disassoc_imminent(struct ho
+
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
++ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
+ MACSTR, disassoc_timer, MAC2STR(sta->addr));
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
+@@ -921,6 +925,7 @@ int wnm_send_ess_disassoc_imminent(struc
+ return -1;
+ }
+
++ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
+ if (disassoc_timer) {
+ /* send disassociation frame after time-out */
+ set_disassoc_timer(hapd, sta, disassoc_timer);
+@@ -1001,6 +1006,7 @@ int wnm_send_bss_tm_req(struct hostapd_d
+ }
+ os_free(buf);
+
++ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
+ if (disassoc_timer) {
+ /* send disassociation frame after time-out */
+ set_disassoc_timer(hapd, sta, disassoc_timer);
+--- a/src/ap/rrm.c
++++ b/src/ap/rrm.c
+@@ -269,6 +269,8 @@ static void hostapd_send_nei_report_resp
+ }
+ }
+
++ hapd->openwrt_stats.rrm.neighbor_report_tx++;
++
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch
index 005ed54e0c7..a6ccf83331f 100644
--- a/package/network/services/hostapd/patches/600-ubus_support.patch
+++ b/package/network/services/hostapd/patches/600-ubus_support.patch
@@ -1,11 +1,12 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
-@@ -166,6 +166,11 @@ OBJS += ../src/common/hw_features_common
+@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
OBJS += ../src/eapol_auth/eapol_auth_sm.o
+ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT
++OBJS += ../src/utils/uloop.o
+OBJS += ../src/ap/ubus.o
+LIBS += -lubox -lubus
+endif
@@ -14,7 +15,7 @@
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -17,6 +17,7 @@
+@@ -18,6 +18,7 @@
#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
@@ -22,16 +23,7 @@
#define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \
-@@ -80,7 +81,7 @@ struct hapd_interfaces {
- #ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
- #endif /* CONFIG_CTRL_IFACE_UDP */
--
-+ struct ubus_object ubus;
- };
-
- enum hostapd_chan_status {
-@@ -154,6 +155,7 @@ struct hostapd_data {
+@@ -184,6 +185,7 @@ struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
@@ -39,7 +31,7 @@
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
unsigned int disabled:1;
-@@ -610,6 +612,7 @@ hostapd_alloc_bss_data(struct hostapd_if
+@@ -695,6 +697,7 @@ hostapd_alloc_bss_data(struct hostapd_if
struct hostapd_bss_config *bss);
int hostapd_setup_interface(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
@@ -49,7 +41,7 @@
struct hostapd_iface * hostapd_alloc_iface(void);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -396,6 +396,7 @@ void hostapd_free_hapd_data(struct hosta
+@@ -435,6 +435,7 @@ void hostapd_free_hapd_data(struct hosta
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
@@ -57,7 +49,7 @@
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
-@@ -1422,6 +1423,8 @@ static int hostapd_setup_bss(struct host
+@@ -1187,6 +1188,8 @@ static int hostapd_start_beacon(struct h
if (hapd->driver && hapd->driver->set_operstate)
hapd->driver->set_operstate(hapd->drv_priv, 1);
@@ -66,7 +58,7 @@
return 0;
}
-@@ -2028,6 +2031,7 @@ static int hostapd_setup_interface_compl
+@@ -2275,6 +2278,7 @@ static int hostapd_setup_interface_compl
if (err)
goto fail;
@@ -74,15 +66,15 @@
wpa_printf(MSG_DEBUG, "Completing interface initialization");
if (iface->freq) {
#ifdef NEED_AP_MLME
-@@ -2225,6 +2229,7 @@ dfs_offload:
+@@ -2494,6 +2498,7 @@ dfs_offload:
fail:
wpa_printf(MSG_ERROR, "Interface initialization failed");
+ hostapd_ubus_free_iface(iface);
- hostapd_set_state(iface, HAPD_IFACE_DISABLED);
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
- #ifdef CONFIG_FST
-@@ -2700,6 +2705,7 @@ void hostapd_interface_deinit_free(struc
+
+ if (iface->is_no_ir) {
+ hostapd_set_state(iface, HAPD_IFACE_NO_IR);
+@@ -2984,6 +2989,7 @@ void hostapd_interface_deinit_free(struc
(unsigned int) iface->conf->num_bss);
driver = iface->bss[0]->driver;
drv_priv = iface->bss[0]->drv_priv;
@@ -92,7 +84,7 @@
__func__, driver, drv_priv);
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
-@@ -3553,13 +3553,18 @@ static void handle_auth(struct hostapd_d
+@@ -2786,7 +2786,7 @@ static void handle_auth(struct hostapd_d
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
struct sta_info *sta = NULL;
@@ -101,9 +93,10 @@
u16 fc;
const u8 *challenge = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
- size_t resp_ies_len = 0;
- u16 seq_ctrl;
+@@ -2795,6 +2795,11 @@ static void handle_auth(struct hostapd_d
struct radius_sta rad_info;
+ const u8 *dst, *sa, *bssid;
+ bool mld_sta = false;
+ struct hostapd_ubus_request req = {
+ .type = HOSTAPD_UBUS_AUTH_REQ,
+ .mgmt_frame = mgmt,
@@ -112,7 +105,7 @@
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
-@@ -3727,6 +3732,13 @@ static void handle_auth(struct hostapd_d
+@@ -2986,6 +2991,13 @@ static void handle_auth(struct hostapd_d
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -126,7 +119,7 @@
if (res == HOSTAPD_ACL_PENDING)
return;
-@@ -5454,7 +5466,7 @@ static void handle_assoc(struct hostapd_
+@@ -5161,7 +5173,7 @@ static void handle_assoc(struct hostapd_
int resp = WLAN_STATUS_SUCCESS;
u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
const u8 *pos;
@@ -135,7 +128,7 @@
struct sta_info *sta;
u8 *tmp = NULL;
#ifdef CONFIG_FILS
-@@ -5667,6 +5679,11 @@ static void handle_assoc(struct hostapd_
+@@ -5374,6 +5386,11 @@ static void handle_assoc(struct hostapd_
left = res;
}
#endif /* CONFIG_FILS */
@@ -147,9 +140,9 @@
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
-@@ -5831,6 +5848,14 @@ static void handle_assoc(struct hostapd_
- pos, left, rssi, omit_rsnxe);
- os_free(tmp);
+@@ -5472,6 +5489,13 @@ static void handle_assoc(struct hostapd_
+ }
+ #endif /* CONFIG_FILS */
+ ubus_resp = hostapd_ubus_handle_event(hapd, &req);
+ if (ubus_resp) {
@@ -158,30 +151,29 @@
+ resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
-+
+ fail:
+
/*
- * Remove the station in case transmission of a success response fails
- * (the STA was added associated to the driver) or if the station was
-@@ -5858,6 +5883,7 @@ static void handle_disassoc(struct hosta
- wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
- MAC2STR(mgmt->sa),
- le_to_host16(mgmt->u.disassoc.reason_code));
+@@ -5753,6 +5777,7 @@ static void handle_disassoc(struct hosta
+ (unsigned long) len);
+ return;
+ }
+ hostapd_ubus_notify(hapd, "disassoc", mgmt->sa);
sta = ap_get_sta(hapd, mgmt->sa);
- if (sta == NULL) {
-@@ -5927,6 +5953,8 @@ static void handle_deauth(struct hostapd
+ if (!sta) {
+@@ -5784,6 +5809,8 @@ static void handle_deauth(struct hostapd
/* Clear the PTKSA cache entries for PASN */
ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
+ hostapd_ubus_notify(hapd, "deauth", mgmt->sa);
+
sta = ap_get_sta(hapd, mgmt->sa);
- if (sta == NULL) {
- wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+ if (!sta) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
-@@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat
+@@ -1036,6 +1036,12 @@ void handle_probe_req(struct hostapd_dat
u16 csa_offs[2];
size_t csa_offs_len;
struct radius_sta rad_info;
@@ -194,7 +186,7 @@
if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
ssi_signal < hapd->iconf->rssi_ignore_probe_request)
-@@ -1009,6 +1015,12 @@ void handle_probe_req(struct hostapd_dat
+@@ -1222,6 +1228,12 @@ void handle_probe_req(struct hostapd_dat
}
#endif /* CONFIG_P2P */
@@ -209,7 +201,7 @@
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
-@@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d
+@@ -260,6 +260,10 @@ int hostapd_notif_assoc(struct hostapd_d
u16 reason = WLAN_REASON_UNSPECIFIED;
int status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -220,7 +212,7 @@
if (addr == NULL) {
/*
-@@ -237,6 +241,12 @@ int hostapd_notif_assoc(struct hostapd_d
+@@ -396,6 +400,12 @@ int hostapd_notif_assoc(struct hostapd_d
goto fail;
}
@@ -235,24 +227,83 @@
wpabuf_free(sta->p2p_ie);
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
-@@ -459,6 +459,7 @@ void ap_handle_timer(void *eloop_ctx, vo
+@@ -471,6 +471,7 @@ void ap_handle_timer(void *eloop_ctx, vo
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"local deauth request");
- ap_free_sta(hapd, sta);
+ hostapd_ubus_notify(hapd, "local-deauth", sta->addr);
+ ap_free_sta(hapd, sta);
return;
}
-
-@@ -614,6 +615,7 @@ skip_poll:
+@@ -626,6 +627,7 @@ skip_poll:
+ mlme_deauthenticate_indication(
hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- ap_free_sta(hapd, sta);
+ hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr);
+ ap_free_sta(hapd, sta);
break;
}
- }
-@@ -1329,6 +1331,7 @@ void ap_sta_set_authorized(struct hostap
- buf, ip_addr, keyid_buf);
+@@ -1344,15 +1346,28 @@ void ap_sta_set_authorized(struct hostap
+ sta->addr, authorized, dev_addr);
+
+ if (authorized) {
++ static const char * const auth_algs[] = {
++ [WLAN_AUTH_OPEN] = "open",
++ [WLAN_AUTH_SHARED_KEY] = "shared",
++ [WLAN_AUTH_FT] = "ft",
++ [WLAN_AUTH_SAE] = "sae",
++ [WLAN_AUTH_FILS_SK] = "fils-sk",
++ [WLAN_AUTH_FILS_SK_PFS] = "fils-sk-pfs",
++ [WLAN_AUTH_FILS_PK] = "fils-pk",
++ [WLAN_AUTH_PASN] = "pasn",
++ };
++ const char *auth_alg = NULL;
+ const u8 *dpp_pkhash;
+ const char *keyid;
+ char dpp_pkhash_buf[100];
+ char keyid_buf[100];
+ char ip_addr[100];
++ char alg_buf[100];
+
+ dpp_pkhash_buf[0] = '\0';
+ keyid_buf[0] = '\0';
+ ip_addr[0] = '\0';
++ alg_buf[0] = '\0';
+ #ifdef CONFIG_P2P
+ if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
+ os_snprintf(ip_addr, sizeof(ip_addr),
+@@ -1362,6 +1377,13 @@ void ap_sta_set_authorized(struct hostap
+ }
+ #endif /* CONFIG_P2P */
+
++ if (sta->auth_alg < ARRAY_SIZE(auth_algs))
++ auth_alg = auth_algs[sta->auth_alg];
++
++ if (auth_alg)
++ os_snprintf(alg_buf, sizeof(alg_buf),
++ " auth_alg=%s", auth_alg);
++
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ os_snprintf(keyid_buf, sizeof(keyid_buf),
+@@ -1380,17 +1402,19 @@ void ap_sta_set_authorized(struct hostap
+ dpp_pkhash, SHA256_MAC_LEN);
+ }
+
+- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s",
+- buf, ip_addr, keyid_buf, dpp_pkhash_buf);
++ hostapd_ubus_notify_authorized(hapd, sta, auth_alg);
++ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s%s",
++ buf, ip_addr, keyid_buf, dpp_pkhash_buf, alg_buf);
+
+ if (hapd->msg_ctx_parent &&
+ hapd->msg_ctx_parent != hapd->msg_ctx)
+ wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+- AP_STA_CONNECTED "%s%s%s%s",
++ AP_STA_CONNECTED "%s%s%s%s%s",
+ buf, ip_addr, keyid_buf,
+- dpp_pkhash_buf);
++ dpp_pkhash_buf, alg_buf);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
+ hostapd_ubus_notify(hapd, "disassoc", sta->addr);
@@ -261,7 +312,7 @@
hapd->msg_ctx_parent != hapd->msg_ctx)
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
-@@ -265,6 +265,7 @@ static void hostapd_wpa_auth_psk_failure
+@@ -269,6 +269,7 @@ static void hostapd_wpa_auth_psk_failure
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
MAC2STR(addr));
@@ -271,20 +322,21 @@
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
-@@ -176,6 +176,12 @@ ifdef CONFIG_EAPOL_TEST
+@@ -192,6 +192,13 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
+ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT
+OBJS += ubus.o
++OBJS += ../src/utils/uloop.o
+LIBS += -lubox -lubus
+endif
+
ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
LIBS += -lgcov
-@@ -959,6 +965,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
+@@ -987,6 +994,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
CFLAGS += -DCONFIG_CTRL_IFACE_MIB
endif
OBJS += ../src/ap/ctrl_iface_ap.o
@@ -296,7 +348,7 @@
CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
-@@ -7017,6 +7017,8 @@ struct wpa_supplicant * wpa_supplicant_a
+@@ -7595,6 +7595,8 @@ struct wpa_supplicant * wpa_supplicant_a
}
#endif /* CONFIG_P2P */
@@ -305,7 +357,7 @@
return wpa_s;
}
-@@ -7043,6 +7045,8 @@ int wpa_supplicant_remove_iface(struct w
+@@ -7621,6 +7623,8 @@ int wpa_supplicant_remove_iface(struct w
struct wpa_supplicant *parent = wpa_s->parent;
#endif /* CONFIG_MESH */
@@ -314,7 +366,7 @@
/* Remove interface from the global list of interfaces */
prev = global->ifaces;
if (prev == wpa_s) {
-@@ -7346,8 +7350,12 @@ int wpa_supplicant_run(struct wpa_global
+@@ -7967,8 +7971,12 @@ int wpa_supplicant_run(struct wpa_global
eloop_register_signal_terminate(wpa_supplicant_terminate, global);
eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
@@ -329,15 +381,15 @@
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
-@@ -19,6 +19,7 @@
- #include "wps/wps_defs.h"
+@@ -21,6 +21,7 @@
#include "config_ssid.h"
#include "wmm_ac.h"
+ #include "pasn/pasn_common.h"
+#include "ubus.h"
extern const char *const wpa_supplicant_version;
extern const char *const wpa_supplicant_license;
-@@ -321,6 +322,8 @@ struct wpa_global {
+@@ -319,6 +320,8 @@ struct wpa_global {
#endif /* CONFIG_WIFI_DISPLAY */
struct psk_list_entry *add_psk; /* From group formation */
@@ -346,7 +398,7 @@
};
-@@ -605,6 +608,7 @@ struct wpa_supplicant {
+@@ -685,6 +688,7 @@ struct wpa_supplicant {
unsigned char own_addr[ETH_ALEN];
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
@@ -364,7 +416,7 @@
#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
-@@ -392,6 +393,8 @@ static int wpa_supplicant_wps_cred(void
+@@ -402,6 +403,8 @@ static int wpa_supplicant_wps_cred(void
wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
cred->cred_attr, cred->cred_attr_len);
@@ -373,36 +425,18 @@
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
---- a/hostapd/main.c
-+++ b/hostapd/main.c
-@@ -895,6 +895,7 @@ int main(int argc, char *argv[])
- }
-
- hostapd_global_ctrl_iface_init(&interfaces);
-+ hostapd_ubus_add(&interfaces);
-
- if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
- wpa_printf(MSG_ERROR, "Failed to start eloop");
-@@ -904,6 +905,7 @@ int main(int argc, char *argv[])
- ret = 0;
-
- out:
-+ hostapd_ubus_free(&interfaces);
- hostapd_global_ctrl_iface_deinit(&interfaces);
- /* Deinitialize all interfaces */
- for (i = 0; i < interfaces.count; i++) {
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -203,7 +203,7 @@ int main(int argc, char *argv[])
for (;;) {
c = getopt(argc, argv,
-- "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuv::W");
-+ "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:nNo:O:p:P:qsTtuv::W");
+- "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuv::W");
++ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:nNo:O:p:P:qsTtuv::W");
if (c < 0)
break;
switch (c) {
-@@ -271,6 +271,9 @@ int main(int argc, char *argv[])
+@@ -268,6 +268,9 @@ int main(int argc, char *argv[])
params.conf_p2p_dev = optarg;
break;
#endif /* CONFIG_P2P */
@@ -424,6 +458,16 @@
}
+@@ -352,6 +355,9 @@ void hostapd_handle_radio_measurement(st
+ mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
+
+ switch (mgmt->u.action.u.rrm.action) {
++ case WLAN_RRM_LINK_MEASUREMENT_REPORT:
++ hostapd_ubus_handle_link_measurement(hapd, buf, len);
++ break;
+ case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
+ hostapd_handle_radio_msmt_report(hapd, buf, len);
+ break;
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -22,6 +22,7 @@
@@ -464,7 +508,7 @@
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
-@@ -1193,6 +1193,8 @@ int hostapd_dfs_radar_detected(struct ho
+@@ -1216,6 +1216,8 @@ int hostapd_dfs_pre_cac_expired(struct h
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
@@ -506,7 +550,7 @@
}
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
-@@ -324,6 +324,7 @@ struct sta_info {
+@@ -322,6 +322,7 @@ struct sta_info {
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
@@ -514,3 +558,191 @@
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
+--- a/src/ap/wnm_ap.c
++++ b/src/ap/wnm_ap.c
+@@ -455,7 +455,8 @@ static void ieee802_11_rx_bss_trans_mgmt
+ MAC2STR(addr), reason, hex ? " neighbor=" : "", hex);
+ os_free(hex);
+
+- ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
++ if (!hostapd_ubus_notify_bss_transition_query(hapd, addr, dialog_token, reason, pos, end - pos))
++ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
+ }
+
+
+@@ -477,7 +478,7 @@ static void ieee802_11_rx_bss_trans_mgmt
+ size_t len)
+ {
+ u8 dialog_token, status_code, bss_termination_delay;
+- const u8 *pos, *end;
++ const u8 *pos, *end, *target_bssid = NULL;
+ int enabled = hapd->conf->bss_transition;
+ struct sta_info *sta;
+
+@@ -524,6 +525,7 @@ static void ieee802_11_rx_bss_trans_mgmt
+ wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
+ return;
+ }
++ target_bssid = pos;
+ sta->agreed_to_steer = 1;
+ eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+ eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
+@@ -543,6 +545,10 @@ static void ieee802_11_rx_bss_trans_mgmt
+ MAC2STR(addr), status_code, bss_termination_delay);
+ }
+
++ hostapd_ubus_notify_bss_transition_response(hapd, sta->addr, dialog_token,
++ status_code, bss_termination_delay,
++ target_bssid, pos, end - pos);
++
+ wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
+ pos, end - pos);
+ }
+--- a/src/utils/eloop.c
++++ b/src/utils/eloop.c
+@@ -77,6 +77,9 @@ struct eloop_sock_table {
+ struct eloop_data {
+ int max_sock;
+
++ eloop_timeout_poll_handler timeout_poll_cb;
++ eloop_poll_handler poll_cb;
++
+ size_t count; /* sum of all table counts */
+ #ifdef CONFIG_ELOOP_POLL
+ size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+@@ -1121,6 +1124,12 @@ void eloop_run(void)
+ os_reltime_sub(&timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
++ }
++
++ if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout))
++ timeout = (void *)1;
++
++ if (timeout) {
+ #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
+ timeout_ms = tv.sec * 1000 + tv.usec / 1000;
+ #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
+@@ -1190,7 +1199,8 @@ void eloop_run(void)
+ eloop.exceptions.changed = 0;
+
+ eloop_process_pending_signals();
+-
++ if (eloop.poll_cb)
++ eloop.poll_cb();
+
+ /* check if some registered timeouts have occurred */
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+@@ -1252,6 +1262,14 @@ out:
+ return;
+ }
+
++int eloop_register_cb(eloop_poll_handler poll_cb,
++ eloop_timeout_poll_handler timeout_cb)
++{
++ eloop.poll_cb = poll_cb;
++ eloop.timeout_poll_cb = timeout_cb;
++
++ return 0;
++}
+
+ void eloop_terminate(void)
+ {
+--- a/src/utils/eloop.h
++++ b/src/utils/eloop.h
+@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
+ */
+ typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+
++typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set);
++typedef void (*eloop_poll_handler)(void);
++
+ /**
+ * eloop_init() - Initialize global event loop data
+ * Returns: 0 on success, -1 on failure
+@@ -73,6 +76,9 @@ typedef void (*eloop_signal_handler)(int
+ */
+ int eloop_init(void);
+
++int eloop_register_cb(eloop_poll_handler poll_cb,
++ eloop_timeout_poll_handler timeout_cb);
++
+ /**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+@@ -320,6 +326,8 @@ int eloop_register_signal_reconfig(eloop
+ */
+ int eloop_sock_requeue(void);
+
++void eloop_add_uloop(void);
++
+ /**
+ * eloop_run - Start the event loop
+ *
+--- /dev/null
++++ b/src/utils/uloop.c
+@@ -0,0 +1,64 @@
++#include <libubox/uloop.h>
++#include "includes.h"
++#include "common.h"
++#include "eloop.h"
++
++static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx)
++{
++}
++
++static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events)
++{
++ unsigned int changed = events ^ fd->flags;
++
++ if (changed & ULOOP_READ) {
++ if (events & ULOOP_READ)
++ eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd);
++ else
++ eloop_unregister_sock(fd->fd, EVENT_TYPE_READ);
++ }
++
++ if (changed & ULOOP_WRITE) {
++ if (events & ULOOP_WRITE)
++ eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd);
++ else
++ eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE);
++ }
++}
++
++static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set)
++{
++ struct os_reltime tv_uloop;
++ int timeout_ms = uloop_get_next_timeout();
++
++ if (timeout_ms < 0)
++ return false;
++
++ tv_uloop.sec = timeout_ms / 1000;
++ tv_uloop.usec = (timeout_ms % 1000) * 1000;
++
++ if (!tv_set || os_reltime_before(&tv_uloop, tv)) {
++ *tv = tv_uloop;
++ return true;
++ }
++
++ return false;
++}
++
++static void uloop_poll_handler(void)
++{
++ uloop_run_timeout(0);
++}
++
++void eloop_add_uloop(void)
++{
++ static bool init_done = false;
++
++ if (!init_done) {
++ uloop_init();
++ uloop_fd_set_cb = eloop_uloop_fd_cb;
++ init_done = true;
++ }
++
++ eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler);
++}
diff --git a/package/network/services/hostapd/patches/601-ucode_support.patch b/package/network/services/hostapd/patches/601-ucode_support.patch
new file mode 100644
index 00000000000..cfdb51f356c
--- /dev/null
+++ b/package/network/services/hostapd/patches/601-ucode_support.patch
@@ -0,0 +1,671 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -168,9 +168,21 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.
+
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+-OBJS += ../src/utils/uloop.o
+ OBJS += ../src/ap/ubus.o
+-LIBS += -lubox -lubus
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ../src/ap/ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
++OBJS += ../src/utils/uloop.o
++LIBS += -lubox
+ endif
+
+ ifdef CONFIG_CODE_COVERAGE
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -1007,6 +1007,7 @@ int main(int argc, char *argv[])
+ }
+
+ hostapd_global_ctrl_iface_init(&interfaces);
++ hostapd_ucode_init(&interfaces);
+
+ if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+ wpa_printf(MSG_ERROR, "Failed to start eloop");
+@@ -1016,6 +1017,7 @@ int main(int argc, char *argv[])
+ ret = 0;
+
+ out:
++ hostapd_ucode_free();
+ hostapd_global_ctrl_iface_deinit(&interfaces);
+ /* Deinitialize all interfaces */
+ for (i = 0; i < interfaces.count; i++) {
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -19,6 +19,7 @@
+ #include "ap_config.h"
+ #include "drivers/driver.h"
+ #include "ubus.h"
++#include "ucode.h"
+
+ #define OCE_STA_CFON_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_STA_CFON) && \
+@@ -51,6 +52,10 @@ struct hapd_interfaces {
+ struct hostapd_config * (*config_read_cb)(const char *config_fname);
+ int (*ctrl_iface_init)(struct hostapd_data *hapd);
+ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
++ int (*ctrl_iface_recv)(struct hostapd_data *hapd,
++ char *buf, char *reply, int reply_size,
++ struct sockaddr_storage *from,
++ socklen_t fromlen);
+ int (*for_each_interface)(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
+@@ -186,6 +191,7 @@ struct hostapd_data {
+ struct hostapd_config *iconf;
+ struct hostapd_bss_config *conf;
+ struct hostapd_ubus_bss ubus;
++ struct hostapd_ucode_bss ucode;
+ int interface_added; /* virtual interface added for this BSS */
+ unsigned int started:1;
+ unsigned int disabled:1;
+@@ -506,6 +512,7 @@ struct hostapd_sta_info {
+ */
+ struct hostapd_iface {
+ struct hapd_interfaces *interfaces;
++ struct hostapd_ucode_iface ucode;
+ void *owner;
+ char *config_fname;
+ struct hostapd_config *conf;
+@@ -706,6 +713,8 @@ struct hostapd_iface * hostapd_init(stru
+ struct hostapd_iface *
+ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug);
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon);
++void hostapd_bss_deinit(struct hostapd_data *hapd);
+ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc);
+ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -252,6 +252,8 @@ int hostapd_reload_config(struct hostapd
+ struct hostapd_config *newconf, *oldconf;
+ size_t j;
+
++ hostapd_ucode_reload_bss(hapd);
++
+ if (iface->config_fname == NULL) {
+ /* Only in-memory config in use - assume it has been updated */
+ hostapd_clear_old(iface);
+@@ -435,6 +437,7 @@ void hostapd_free_hapd_data(struct hosta
+ hapd->beacon_set_done = 0;
+
+ wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
++ hostapd_ucode_free_bss(hapd);
+ hostapd_ubus_free_bss(hapd);
+ accounting_deinit(hapd);
+ hostapd_deinit_wpa(hapd);
+@@ -600,6 +603,7 @@ void hostapd_cleanup_iface_partial(struc
+ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+ {
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
++ hostapd_ucode_free_iface(iface);
+ eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ NULL);
+
+@@ -1189,6 +1193,7 @@ static int hostapd_start_beacon(struct h
+ hapd->driver->set_operstate(hapd->drv_priv, 1);
+
+ hostapd_ubus_add_bss(hapd);
++ hostapd_ucode_add_bss(hapd);
+
+ return 0;
+ }
+@@ -1211,8 +1216,7 @@ static int hostapd_start_beacon(struct h
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+-static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+- bool start_beacon)
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
+ {
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 ssid[SSID_MAX_LEN + 1];
+@@ -2698,7 +2702,7 @@ hostapd_alloc_bss_data(struct hostapd_if
+ }
+
+
+-static void hostapd_bss_deinit(struct hostapd_data *hapd)
++void hostapd_bss_deinit(struct hostapd_data *hapd)
+ {
+ if (!hapd)
+ return;
+@@ -3491,7 +3495,8 @@ int hostapd_remove_iface(struct hapd_int
+ hapd_iface = interfaces->iface[i];
+ if (hapd_iface == NULL)
+ return -1;
+- if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
++ if (!os_strcmp(hapd_iface->phy, buf) ||
++ !os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
+ wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+ hapd_iface->driver_ap_teardown =
+ !!(hapd_iface->drv_flags &
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -195,8 +195,20 @@ endif
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+ OBJS += ubus.o
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
+ OBJS += ../src/utils/uloop.o
+-LIBS += -lubox -lubus
++LIBS += -lubox
+ endif
+
+ ifdef CONFIG_CODE_COVERAGE
+@@ -997,6 +1009,9 @@ OBJS += ../src/ap/ctrl_iface_ap.o
+ ifdef CONFIG_UBUS
+ OBJS += ../src/ap/ubus.o
+ endif
++ifdef CONFIG_UCODE
++OBJS += ../src/ap/ucode.o
++endif
+ endif
+
+ CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -1044,6 +1044,7 @@ void wpa_supplicant_set_state(struct wpa
+ sme_sched_obss_scan(wpa_s, 0);
+ }
+ wpa_s->wpa_state = state;
++ wpas_ucode_update_state(wpa_s);
+
+ #ifdef CONFIG_BGSCAN
+ if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
+@@ -7594,6 +7595,7 @@ struct wpa_supplicant * wpa_supplicant_a
+ #endif /* CONFIG_P2P */
+
+ wpas_ubus_add_bss(wpa_s);
++ wpas_ucode_add_bss(wpa_s);
+
+ return wpa_s;
+ }
+@@ -7621,6 +7623,7 @@ int wpa_supplicant_remove_iface(struct w
+ struct wpa_supplicant *parent = wpa_s->parent;
+ #endif /* CONFIG_MESH */
+
++ wpas_ucode_free_bss(wpa_s);
+ wpas_ubus_free_bss(wpa_s);
+
+ /* Remove interface from the global list of interfaces */
+@@ -7931,6 +7934,7 @@ struct wpa_global * wpa_supplicant_init(
+
+ eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
+ wpas_periodic, global, NULL);
++ wpas_ucode_init(global);
+
+ return global;
+ }
+@@ -7969,12 +7973,8 @@ int wpa_supplicant_run(struct wpa_global
+ eloop_register_signal_terminate(wpa_supplicant_terminate, global);
+ eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
+
+- wpas_ubus_add(global);
+-
+ eloop_run();
+
+- wpas_ubus_free(global);
+-
+ return 0;
+ }
+
+@@ -8007,6 +8007,8 @@ void wpa_supplicant_deinit(struct wpa_gl
+
+ wpas_notify_supplicant_deinitialized(global);
+
++ wpas_ucode_free();
++
+ eap_peer_unregister_methods();
+ #ifdef CONFIG_AP
+ eap_server_unregister_methods();
+--- a/wpa_supplicant/wpa_supplicant_i.h
++++ b/wpa_supplicant/wpa_supplicant_i.h
+@@ -22,6 +22,7 @@
+ #include "wmm_ac.h"
+ #include "pasn/pasn_common.h"
+ #include "ubus.h"
++#include "ucode.h"
+
+ extern const char *const wpa_supplicant_version;
+ extern const char *const wpa_supplicant_license;
+@@ -689,6 +690,7 @@ struct wpa_supplicant {
+ unsigned char perm_addr[ETH_ALEN];
+ char ifname[100];
+ struct wpas_ubus_bss ubus;
++ struct wpas_ucode_bss ucode;
+ #ifdef CONFIG_MATCH_IFACE
+ int matched;
+ #endif /* CONFIG_MATCH_IFACE */
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -4856,6 +4856,7 @@ try_again:
+ return -1;
+ }
+
++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+ return 0;
+@@ -4957,6 +4958,7 @@ fail:
+ os_free(fname);
+
+ interface->global_ctrl_sock = s;
++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ interface, NULL);
+
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -3787,6 +3787,25 @@ struct wpa_driver_ops {
+ const char *ifname);
+
+ /**
++ * if_rename - Rename a virtual interface
++ * @priv: Private driver interface data
++ * @type: Interface type
++ * @ifname: Interface name of the virtual interface to be renamed
++ * (NULL when renaming the AP BSS interface)
++ * @new_name: New interface name of the virtual interface
++ * Returns: 0 on success, -1 on failure
++ */
++ int (*if_rename)(void *priv, enum wpa_driver_if_type type,
++ const char *ifname, const char *new_name);
++
++ /**
++ * set_first_bss - Make a virtual interface the first (primary) bss
++ * @priv: Private driver interface data
++ * Returns: 0 on success, -1 on failure
++ */
++ int (*set_first_bss)(void *priv);
++
++ /**
+ * set_sta_vlan - Bind a station into a specific interface (AP only)
+ * @priv: Private driver interface data
+ * @ifname: Interface (main or virtual BSS or VLAN)
+@@ -6440,6 +6459,7 @@ union wpa_event_data {
+
+ /**
+ * struct ch_switch
++ * @count: Count until channel switch activates
+ * @freq: Frequency of new channel in MHz
+ * @ht_enabled: Whether this is an HT channel
+ * @ch_offset: Secondary channel offset
+@@ -6450,6 +6470,7 @@ union wpa_event_data {
+ * @punct_bitmap: Puncturing bitmap
+ */
+ struct ch_switch {
++ int count;
+ int freq;
+ int ht_enabled;
+ int ch_offset;
+--- a/src/drivers/driver_nl80211_event.c
++++ b/src/drivers/driver_nl80211_event.c
+@@ -1202,6 +1202,7 @@ static void mlme_event_ch_switch(struct
+ struct nlattr *bw, struct nlattr *cf1,
+ struct nlattr *cf2,
+ struct nlattr *punct_bitmap,
++ struct nlattr *count,
+ int finished)
+ {
+ struct i802_bss *bss;
+@@ -1265,6 +1266,8 @@ static void mlme_event_ch_switch(struct
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
++ if (count)
++ data.ch_switch.count = nla_get_u32(count);
+
+ if (finished)
+ bss->flink->freq = data.ch_switch.freq;
+@@ -3912,6 +3915,7 @@ static void do_process_drv_event(struct
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2],
+ tb[NL80211_ATTR_PUNCT_BITMAP],
++ tb[NL80211_ATTR_CH_SWITCH_COUNT],
+ 0);
+ break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+@@ -3924,6 +3928,7 @@ static void do_process_drv_event(struct
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2],
+ tb[NL80211_ATTR_PUNCT_BITMAP],
++ NULL,
+ 1);
+ break;
+ case NL80211_CMD_DISCONNECT:
+--- a/wpa_supplicant/events.c
++++ b/wpa_supplicant/events.c
+@@ -5389,6 +5389,7 @@ void supplicant_event(void *ctx, enum wp
+ event_to_string(event), event);
+ #endif /* CONFIG_NO_STDOUT_DEBUG */
+
++ wpas_ucode_event(wpa_s, event, data);
+ switch (event) {
+ case EVENT_AUTH:
+ #ifdef CONFIG_FST
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -393,6 +393,23 @@ static inline int hostapd_drv_stop_ap(st
+ return hapd->driver->stop_ap(hapd->drv_priv);
+ }
+
++static inline int hostapd_drv_if_rename(struct hostapd_data *hapd,
++ enum wpa_driver_if_type type,
++ const char *ifname,
++ const char *new_name)
++{
++ if (!hapd->driver || !hapd->driver->if_rename || !hapd->drv_priv)
++ return -1;
++ return hapd->driver->if_rename(hapd->drv_priv, type, ifname, new_name);
++}
++
++static inline int hostapd_drv_set_first_bss(struct hostapd_data *hapd)
++{
++ if (!hapd->driver || !hapd->driver->set_first_bss || !hapd->drv_priv)
++ return 0;
++ return hapd->driver->set_first_bss(hapd->drv_priv);
++}
++
+ static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
+ struct wpa_channel_info *ci)
+ {
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -73,6 +73,16 @@ enum nlmsgerr_attrs {
+
+ #endif /* ANDROID */
+
++static void handle_nl_debug_hook(struct nl_msg *msg, int tx)
++{
++ const struct nlmsghdr *nlh;
++
++ if (!wpa_netlink_hook)
++ return;
++
++ nlh = nlmsg_hdr(msg);
++ wpa_netlink_hook(tx, nlh, nlh->nlmsg_len);
++}
+
+ static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
+ {
+@@ -379,6 +389,11 @@ static int no_seq_check(struct nl_msg *m
+ return NL_OK;
+ }
+
++static int debug_handler(struct nl_msg *msg, void *arg)
++{
++ handle_nl_debug_hook(msg, 0);
++ return NL_OK;
++}
+
+ static void nl80211_nlmsg_clear(struct nl_msg *msg)
+ {
+@@ -415,6 +430,7 @@ static int send_and_recv(struct nl80211_
+ if (!msg)
+ return -ENOMEM;
+
++ handle_nl_debug_hook(msg, 1);
+ cb = nl_cb_clone(global->nl_cb);
+ if (!cb)
+ goto out;
+@@ -443,6 +459,7 @@ static int send_and_recv(struct nl80211_
+
+ err = 1;
+
++ nl_cb_set(cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ if (ack_handler_custom) {
+@@ -919,6 +936,7 @@ nl80211_get_wiphy_data_ap(struct i802_bs
+ os_free(w);
+ return NULL;
+ }
++ nl_cb_set(w->nl_cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL);
+ nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+@@ -1333,7 +1351,7 @@ static void wpa_driver_nl80211_event_rtm
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
+ namebuf, ifname);
+- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
++ if (drv->first_bss->ifindex != ifi->ifi_index) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not the main interface (%s) - do not indicate interface down",
+ drv->first_bss->ifname);
+@@ -1369,7 +1387,7 @@ static void wpa_driver_nl80211_event_rtm
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
+ namebuf, ifname);
+- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
++ if (drv->first_bss->ifindex != ifi->ifi_index) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not the main interface (%s) - do not indicate interface up",
+ drv->first_bss->ifname);
+@@ -1992,6 +2010,7 @@ static int wpa_driver_nl80211_init_nl_gl
+ /* Continue without vendor events */
+ }
+
++ nl_cb_set(global->nl_cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL);
+ nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+@@ -2160,6 +2179,7 @@ static int nl80211_init_bss(struct i802_
+ if (!bss->nl_cb)
+ return -1;
+
++ nl_cb_set(bss->nl_cb, NL_CB_MSG_IN, NL_CB_CUSTOM, debug_handler, NULL);
+ nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+@@ -8432,6 +8452,7 @@ static void *i802_init(struct hostapd_da
+ char master_ifname[IFNAMSIZ];
+ int ifindex, br_ifindex = 0;
+ int br_added = 0;
++ int err;
+
+ bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+ params->global_priv, 1,
+@@ -8491,21 +8512,17 @@ static void *i802_init(struct hostapd_da
+ (params->num_bridge == 0 || !params->bridge[0]))
+ add_ifidx(drv, br_ifindex, drv->ifindex);
+
+- if (bss->added_if_into_bridge || bss->already_in_bridge) {
+- int err;
+-
+- drv->rtnl_sk = nl_socket_alloc();
+- if (drv->rtnl_sk == NULL) {
+- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
+- goto failed;
+- }
++ drv->rtnl_sk = nl_socket_alloc();
++ if (drv->rtnl_sk == NULL) {
++ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
++ goto failed;
++ }
+
+- err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
+- if (err) {
+- wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
+- nl_geterror(err));
+- goto failed;
+- }
++ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
++ if (err) {
++ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
++ nl_geterror(err));
++ goto failed;
+ }
+
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
+@@ -8875,6 +8892,50 @@ static int wpa_driver_nl80211_if_remove(
+ return 0;
+ }
+
++static int wpa_driver_nl80211_if_rename(struct i802_bss *bss,
++ enum wpa_driver_if_type type,
++ const char *ifname, const char *new_name)
++{
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++ struct ifinfomsg ifi = {
++ .ifi_family = AF_UNSPEC,
++ .ifi_index = bss->ifindex,
++ };
++ struct nl_msg *msg;
++ int res = -ENOMEM;
++
++ if (ifname)
++ ifi.ifi_index = if_nametoindex(ifname);
++
++ msg = nlmsg_alloc_simple(RTM_SETLINK, 0);
++ if (!msg)
++ return res;
++
++ if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
++ goto out;
++
++ if (nla_put_string(msg, IFLA_IFNAME, new_name))
++ goto out;
++
++ res = nl_send_auto_complete(drv->rtnl_sk, msg);
++ if (res < 0)
++ goto out;
++
++ res = nl_wait_for_ack(drv->rtnl_sk);
++ if (res) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Renaming device %s to %s failed: %s",
++ ifname ? ifname : bss->ifname, new_name, nl_geterror(res));
++ goto out;
++ }
++
++ if (type == WPA_IF_AP_BSS && !ifname)
++ os_strlcpy(bss->ifname, new_name, sizeof(bss->ifname));
++
++out:
++ nlmsg_free(msg);
++ return res;
++}
+
+ static int cookie_handler(struct nl_msg *msg, void *arg)
+ {
+@@ -10513,6 +10574,37 @@ static int driver_nl80211_if_remove(void
+ }
+
+
++static int driver_nl80211_if_rename(void *priv, enum wpa_driver_if_type type,
++ const char *ifname, const char *new_name)
++{
++ struct i802_bss *bss = priv;
++ return wpa_driver_nl80211_if_rename(bss, type, ifname, new_name);
++}
++
++
++static int driver_nl80211_set_first_bss(void *priv)
++{
++ struct i802_bss *bss = priv, *tbss;
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++
++ if (drv->first_bss == bss)
++ return 0;
++
++ for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
++ if (tbss->next != bss)
++ continue;
++
++ tbss->next = bss->next;
++ bss->next = drv->first_bss;
++ drv->first_bss = bss;
++ drv->ctx = bss->ctx;
++ return 0;
++ }
++
++ return -1;
++}
++
++
+ static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len, int noack,
+ unsigned int freq,
+@@ -13697,6 +13789,8 @@ const struct wpa_driver_ops wpa_driver_n
+ .set_acl = wpa_driver_nl80211_set_acl,
+ .if_add = wpa_driver_nl80211_if_add,
+ .if_remove = driver_nl80211_if_remove,
++ .if_rename = driver_nl80211_if_rename,
++ .set_first_bss = driver_nl80211_set_first_bss,
+ .send_mlme = driver_nl80211_send_mlme,
+ .get_hw_feature_data = nl80211_get_hw_feature_data,
+ .sta_add = wpa_driver_nl80211_sta_add,
+--- a/src/utils/wpa_debug.c
++++ b/src/utils/wpa_debug.c
+@@ -26,6 +26,10 @@ static FILE *wpa_debug_tracing_file = NU
+ #define WPAS_TRACE_PFX "wpas <%d>: "
+ #endif /* CONFIG_DEBUG_LINUX_TRACING */
+
++void (*wpa_printf_hook)(int level, const char *fmt, va_list ap);
++void (*wpa_hexdump_hook)(int level, const char *title, const void *buf,
++ size_t len);
++void (*wpa_netlink_hook)(int tx, const void *data, size_t len);
+
+ int wpa_debug_level = MSG_INFO;
+ int wpa_debug_show_keys = 0;
+@@ -210,6 +214,12 @@ void _wpa_printf(int level, const char *
+ {
+ va_list ap;
+
++ if (wpa_printf_hook) {
++ va_start(ap, fmt);
++ wpa_printf_hook(level, fmt, ap);
++ va_end(ap);
++ }
++
+ if (level >= wpa_debug_level) {
+ #ifdef CONFIG_ANDROID_LOG
+ va_start(ap, fmt);
+@@ -260,6 +270,9 @@ void _wpa_hexdump(int level, const char
+ {
+ size_t i;
+
++ if (wpa_hexdump_hook)
++ wpa_hexdump_hook(level, title, buf, len);
++
+ #ifdef CONFIG_DEBUG_LINUX_TRACING
+ if (wpa_debug_tracing_file != NULL) {
+ fprintf(wpa_debug_tracing_file,
+--- a/src/utils/wpa_debug.h
++++ b/src/utils/wpa_debug.h
+@@ -11,6 +11,10 @@
+
+ #include "wpabuf.h"
+
++extern void (*wpa_printf_hook)(int level, const char *fmt, va_list ap);
++extern void (*wpa_hexdump_hook)(int level, const char *title,
++ const void *buf, size_t len);
++extern void (*wpa_netlink_hook)(int tx, const void *data, size_t len);
+ extern int wpa_debug_level;
+ extern int wpa_debug_show_keys;
+ extern int wpa_debug_timestamp;
diff --git a/package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch b/package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch
new file mode 100644
index 00000000000..a03fcc9f92b
--- /dev/null
+++ b/package/network/services/hostapd/patches/610-hostapd_cli_ujail_permission.patch
@@ -0,0 +1,33 @@
+--- a/src/common/wpa_ctrl.c
++++ b/src/common/wpa_ctrl.c
+@@ -135,7 +135,7 @@ try_again:
+ return NULL;
+ }
+ tries++;
+-#ifdef ANDROID
++
+ /* Set client socket file permissions so that bind() creates the client
+ * socket with these permissions and there is no need to try to change
+ * them with chmod() after bind() which would have potential issues with
+@@ -147,7 +147,7 @@ try_again:
+ * operations to allow the response to go through. Those are using the
+ * no-deference-symlinks version to avoid races. */
+ fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+-#endif /* ANDROID */
++
+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+ sizeof(ctrl->local)) < 0) {
+ if (errno == EADDRINUSE && tries < 2) {
+@@ -165,7 +165,11 @@ try_again:
+ return NULL;
+ }
+
+-#ifdef ANDROID
++#ifndef ANDROID
++ /* Set group even if we do not have privileges to change owner */
++ lchown(ctrl->local.sun_path, -1, 101);
++ lchown(ctrl->local.sun_path, 101, 101);
++#else
+ /* Set group even if we do not have privileges to change owner */
+ lchown(ctrl->local.sun_path, -1, AID_WIFI);
+ lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
diff --git a/package/network/services/hostapd/patches/700-wifi-reload.patch b/package/network/services/hostapd/patches/700-wifi-reload.patch
deleted file mode 100644
index 5993b0d4450..00000000000
--- a/package/network/services/hostapd/patches/700-wifi-reload.patch
+++ /dev/null
@@ -1,220 +0,0 @@
---- a/hostapd/config_file.c
-+++ b/hostapd/config_file.c
-@@ -2453,6 +2453,8 @@ static int hostapd_config_fill(struct ho
- bss->isolate = atoi(pos);
- } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
- bss->ap_max_inactivity = atoi(pos);
-+ } else if (os_strcmp(buf, "config_id") == 0) {
-+ bss->config_id = os_strdup(pos);
- } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
- bss->skip_inactivity_poll = atoi(pos);
- } else if (os_strcmp(buf, "country_code") == 0) {
-@@ -3153,6 +3155,8 @@ static int hostapd_config_fill(struct ho
- }
- } else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
- conf->acs_exclude_dfs = atoi(pos);
-+ } else if (os_strcmp(buf, "radio_config_id") == 0) {
-+ conf->config_id = os_strdup(pos);
- } else if (os_strcmp(buf, "op_class") == 0) {
- conf->op_class = atoi(pos);
- } else if (os_strcmp(buf, "channel") == 0) {
---- a/src/ap/ap_config.c
-+++ b/src/ap/ap_config.c
-@@ -791,6 +791,7 @@ void hostapd_config_free_bss(struct host
- os_free(conf->radius_req_attr_sqlite);
- os_free(conf->rsn_preauth_interfaces);
- os_free(conf->ctrl_interface);
-+ os_free(conf->config_id);
- os_free(conf->ca_cert);
- os_free(conf->server_cert);
- os_free(conf->server_cert2);
-@@ -987,6 +988,7 @@ void hostapd_config_free(struct hostapd_
-
- for (i = 0; i < conf->num_bss; i++)
- hostapd_config_free_bss(conf->bss[i]);
-+ os_free(conf->config_id);
- os_free(conf->bss);
- os_free(conf->supported_rates);
- os_free(conf->basic_rates);
---- a/src/ap/ap_config.h
-+++ b/src/ap/ap_config.h
-@@ -279,6 +279,8 @@ struct hostapd_bss_config {
- char vlan_bridge[IFNAMSIZ + 1];
- char wds_bridge[IFNAMSIZ + 1];
-
-+ char *config_id;
-+
- enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
-
- unsigned int logger_syslog; /* module bitfield */
-@@ -938,6 +940,7 @@ struct spatial_reuse {
- struct hostapd_config {
- struct hostapd_bss_config **bss, *last_bss;
- size_t num_bss;
-+ char *config_id;
-
- u16 beacon_int;
- int rts_threshold;
---- a/src/ap/hostapd.c
-+++ b/src/ap/hostapd.c
-@@ -219,6 +219,10 @@ static int hostapd_iface_conf_changed(st
- {
- size_t i;
-
-+ if (newconf->config_id != oldconf->config_id)
-+ if (strcmp(newconf->config_id, oldconf->config_id))
-+ return 1;
-+
- if (newconf->num_bss != oldconf->num_bss)
- return 1;
-
-@@ -232,7 +236,7 @@ static int hostapd_iface_conf_changed(st
- }
-
-
--int hostapd_reload_config(struct hostapd_iface *iface)
-+int hostapd_reload_config(struct hostapd_iface *iface, int reconf)
- {
- struct hapd_interfaces *interfaces = iface->interfaces;
- struct hostapd_data *hapd = iface->bss[0];
-@@ -255,13 +259,16 @@ int hostapd_reload_config(struct hostapd
- if (newconf == NULL)
- return -1;
-
-- hostapd_clear_old(iface);
--
- oldconf = hapd->iconf;
- if (hostapd_iface_conf_changed(newconf, oldconf)) {
- char *fname;
- int res;
-
-+ if (reconf)
-+ return -1;
-+
-+ hostapd_clear_old(iface);
-+
- wpa_printf(MSG_DEBUG,
- "Configuration changes include interface/BSS modification - force full disable+enable sequence");
- fname = os_strdup(iface->config_fname);
-@@ -286,6 +293,24 @@ int hostapd_reload_config(struct hostapd
- wpa_printf(MSG_ERROR,
- "Failed to enable interface on config reload");
- return res;
-+ } else {
-+ for (j = 0; j < iface->num_bss; j++) {
-+ hapd = iface->bss[j];
-+ if (!hapd->config_id || strcmp(hapd->config_id, newconf->bss[j]->config_id)) {
-+ hostapd_flush_old_stations(iface->bss[j],
-+ WLAN_REASON_PREV_AUTH_NOT_VALID);
-+#ifdef CONFIG_WEP
-+ hostapd_broadcast_wep_clear(iface->bss[j]);
-+#endif
-+
-+#ifndef CONFIG_NO_RADIUS
-+ /* TODO: update dynamic data based on changed configuration
-+ * items (e.g., open/close sockets, etc.) */
-+ radius_client_flush(iface->bss[j]->radius, 0);
-+#endif /* CONFIG_NO_RADIUS */
-+ wpa_printf(MSG_INFO, "bss %zu changed", j);
-+ }
-+ }
- }
- iface->conf = newconf;
-
-@@ -302,6 +327,12 @@ int hostapd_reload_config(struct hostapd
-
- for (j = 0; j < iface->num_bss; j++) {
- hapd = iface->bss[j];
-+ if (hapd->config_id) {
-+ os_free(hapd->config_id);
-+ hapd->config_id = NULL;
-+ }
-+ if (newconf->bss[j]->config_id)
-+ hapd->config_id = strdup(newconf->bss[j]->config_id);
- hapd->iconf = newconf;
- hapd->conf = newconf->bss[j];
- hostapd_reload_bss(hapd);
-@@ -2397,6 +2428,10 @@ hostapd_alloc_bss_data(struct hostapd_if
- hapd->iconf = conf;
- hapd->conf = bss;
- hapd->iface = hapd_iface;
-+ if (bss && bss->config_id)
-+ hapd->config_id = strdup(bss->config_id);
-+ else
-+ hapd->config_id = NULL;
- if (conf)
- hapd->driver = conf->driver;
- hapd->ctrl_sock = -1;
---- a/src/ap/hostapd.h
-+++ b/src/ap/hostapd.h
-@@ -46,7 +46,7 @@ struct mesh_conf;
- struct hostapd_iface;
-
- struct hapd_interfaces {
-- int (*reload_config)(struct hostapd_iface *iface);
-+ int (*reload_config)(struct hostapd_iface *iface, int reconf);
- struct hostapd_config * (*config_read_cb)(const char *config_fname);
- int (*ctrl_iface_init)(struct hostapd_data *hapd);
- void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-@@ -156,6 +156,7 @@ struct hostapd_data {
- struct hostapd_config *iconf;
- struct hostapd_bss_config *conf;
- struct hostapd_ubus_bss ubus;
-+ char *config_id;
- int interface_added; /* virtual interface added for this BSS */
- unsigned int started:1;
- unsigned int disabled:1;
-@@ -604,7 +605,7 @@ struct hostapd_iface {
- int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
- int (*cb)(struct hostapd_iface *iface,
- void *ctx), void *ctx);
--int hostapd_reload_config(struct hostapd_iface *iface);
-+int hostapd_reload_config(struct hostapd_iface *iface, int reconf);
- void hostapd_reconfig_encryption(struct hostapd_data *hapd);
- struct hostapd_data *
- hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
---- a/src/drivers/driver_nl80211.c
-+++ b/src/drivers/driver_nl80211.c
-@@ -4820,6 +4820,9 @@ static int wpa_driver_nl80211_set_ap(voi
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
- ret, strerror(-ret));
-+ if (!bss->beacon_set)
-+ ret = 0;
-+ bss->beacon_set = 0;
- } else {
- bss->beacon_set = 1;
- nl80211_set_bss(bss, params->cts_protect, params->preamble,
---- a/hostapd/ctrl_iface.c
-+++ b/hostapd/ctrl_iface.c
-@@ -186,7 +186,7 @@ static int hostapd_ctrl_iface_update(str
- iface->interfaces->config_read_cb = hostapd_ctrl_iface_config_read;
- reload_opts = txt;
-
-- hostapd_reload_config(iface);
-+ hostapd_reload_config(iface, 0);
-
- iface->interfaces->config_read_cb = config_read_cb;
- }
---- a/hostapd/main.c
-+++ b/hostapd/main.c
-@@ -317,7 +317,7 @@ static void handle_term(int sig, void *s
-
- static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
- {
-- if (hostapd_reload_config(iface) < 0) {
-+ if (hostapd_reload_config(iface, 0) < 0) {
- wpa_printf(MSG_WARNING, "Failed to read new configuration "
- "file - continuing with old.");
- }
---- a/src/ap/wps_hostapd.c
-+++ b/src/ap/wps_hostapd.c
-@@ -315,7 +315,7 @@ static void wps_reload_config(void *eloo
-
- wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
- if (iface->interfaces == NULL ||
-- iface->interfaces->reload_config(iface) < 0) {
-+ iface->interfaces->reload_config(iface, 1) < 0) {
- wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
- "configuration");
- }
diff --git a/package/network/services/hostapd/patches/701-reload_config_inline.patch b/package/network/services/hostapd/patches/701-reload_config_inline.patch
new file mode 100644
index 00000000000..3c62bf670f5
--- /dev/null
+++ b/package/network/services/hostapd/patches/701-reload_config_inline.patch
@@ -0,0 +1,33 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -4816,7 +4816,12 @@ struct hostapd_config * hostapd_config_r
+ int errors = 0;
+ size_t i;
+
+- f = fopen(fname, "r");
++ if (!strncmp(fname, "data:", 5)) {
++ f = fmemopen((void *)(fname + 5), strlen(fname + 5), "r");
++ fname = "<inline>";
++ } else {
++ f = fopen(fname, "r");
++ }
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ "for reading.", fname);
+--- a/wpa_supplicant/config_file.c
++++ b/wpa_supplicant/config_file.c
+@@ -326,8 +326,13 @@ struct wpa_config * wpa_config_read(cons
+ while (cred_tail && cred_tail->next)
+ cred_tail = cred_tail->next;
+
++ if (!strncmp(name, "data:", 5)) {
++ f = fmemopen((void *)(name + 5), strlen(name + 5), "r");
++ name = "<inline>";
++ } else {
++ f = fopen(name, "r");
++ }
+ wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
+- f = fopen(name, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
diff --git a/package/network/services/hostapd/patches/710-vlan_no_bridge.patch b/package/network/services/hostapd/patches/710-vlan_no_bridge.patch
index 73db32e54a6..63d1b8a3b83 100644
--- a/package/network/services/hostapd/patches/710-vlan_no_bridge.patch
+++ b/package/network/services/hostapd/patches/710-vlan_no_bridge.patch
@@ -1,6 +1,6 @@
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
-@@ -115,6 +115,7 @@ struct hostapd_ssid {
+@@ -121,6 +121,7 @@ struct hostapd_ssid {
#define DYNAMIC_VLAN_OPTIONAL 1
#define DYNAMIC_VLAN_REQUIRED 2
int dynamic_vlan;
@@ -30,7 +30,7 @@
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
-@@ -3366,6 +3366,8 @@ static int hostapd_config_fill(struct ho
+@@ -3351,6 +3351,8 @@ static int hostapd_config_fill(struct ho
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
diff --git a/package/network/services/hostapd/patches/711-wds_bridge_force.patch b/package/network/services/hostapd/patches/711-wds_bridge_force.patch
new file mode 100644
index 00000000000..c0f2c31c448
--- /dev/null
+++ b/package/network/services/hostapd/patches/711-wds_bridge_force.patch
@@ -0,0 +1,22 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2318,6 +2318,8 @@ static int hostapd_config_fill(struct ho
+ sizeof(conf->bss[0]->iface));
+ } else if (os_strcmp(buf, "bridge") == 0) {
+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
++ if (!bss->wds_bridge[0])
++ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
+ } else if (os_strcmp(buf, "bridge_hairpin") == 0) {
+ bss->bridge_hairpin = atoi(pos);
+ } else if (os_strcmp(buf, "vlan_bridge") == 0) {
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -348,8 +348,6 @@ int hostapd_set_wds_sta(struct hostapd_d
+ return -1;
+ if (hapd->conf->wds_bridge[0])
+ bridge = hapd->conf->wds_bridge;
+- else if (hapd->conf->bridge[0])
+- bridge = hapd->conf->bridge;
+ return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
+ bridge, ifname_wds);
+ }
diff --git a/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch b/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch
deleted file mode 100644
index 3ef19e5298c..00000000000
--- a/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 5a24286ed6315e1fef755ca1970792554f59b1fc Mon Sep 17 00:00:00 2001
-From: David Bauer <mail@david-bauer.net>
-Date: Wed, 26 May 2021 22:15:35 +0200
-Subject: [PATCH] ACS: fix channel 100 frequency
-
-Channel 100 is a valid channel to choose for 80MHz operation. However,
-it's assigned to 5500 MHz, not 5550MHz. In fact, there is no channel
-assigned to this frequency.
-
-Fix this obbvious typo to allow ACS to select channel 100 for 80 MHz
-operation again.
-
-Fixes commit bef5eee4f7b2 ("Convert channel to frequency based selection for AP mode ACS")
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
----
- src/ap/acs.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/src/ap/acs.c
-+++ b/src/ap/acs.c
-@@ -386,7 +386,7 @@ static int acs_usable_bw40_chan(const st
-
- static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
- {
-- const int allowed[] = { 5180, 5260, 5550, 5580, 5660, 5745, 5955, 6035,
-+ const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035,
- 6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
- 6755, 6835, 6915, 6995 };
- unsigned int i;
diff --git a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch
index b93a0bcbef1..089c1ddc246 100644
--- a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch
+++ b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch
@@ -1,6 +1,6 @@
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
-@@ -2873,6 +2873,14 @@ static int hostapd_config_fill(struct ho
+@@ -2848,6 +2848,14 @@ static int hostapd_config_fill(struct ho
line, bss->max_num_sta, MAX_STA_COUNT);
return 1;
}
@@ -17,20 +17,20 @@
} else if (os_strcmp(buf, "extended_key_id") == 0) {
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -648,6 +648,7 @@ void hostapd_cleanup_cs_params(struct ho
+@@ -742,6 +742,7 @@ void hostapd_cleanup_cs_params(struct ho
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
+int hostapd_check_max_sta(struct hostapd_data *hapd);
- /* utils.c */
- int hostapd_register_probereq_cb(struct hostapd_data *hapd,
+ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap);
+ void hostapd_cleanup_cca_params(struct hostapd_data *hapd);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -236,6 +236,30 @@ static int hostapd_iface_conf_changed(st
+@@ -244,6 +244,29 @@ static int hostapd_iface_conf_changed(st
+ return 0;
}
-
+static inline int hostapd_iface_num_sta(struct hostapd_iface *iface)
+{
+ int num_sta = 0;
@@ -54,13 +54,12 @@
+
+ return 0;
+}
-+
- int hostapd_reload_config(struct hostapd_iface *iface, int reconf)
+
+ int hostapd_reload_config(struct hostapd_iface *iface)
{
- struct hapd_interfaces *interfaces = iface->interfaces;
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
-@@ -1039,7 +1039,7 @@ void handle_probe_req(struct hostapd_dat
+@@ -1252,7 +1252,7 @@ void handle_probe_req(struct hostapd_dat
if (hapd->conf->no_probe_resp_if_max_sta &&
is_multicast_ether_addr(mgmt->da) &&
is_multicast_ether_addr(mgmt->bssid) &&
@@ -71,7 +70,7 @@
" since no room for additional STA",
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
-@@ -976,6 +976,8 @@ struct hostapd_config {
+@@ -1039,6 +1039,8 @@ struct hostapd_config {
unsigned int track_sta_max_num;
unsigned int track_sta_max_age;
diff --git a/package/network/services/hostapd/patches/730-ft_iface.patch b/package/network/services/hostapd/patches/730-ft_iface.patch
index 793e8e01940..0795ed15a14 100644
--- a/package/network/services/hostapd/patches/730-ft_iface.patch
+++ b/package/network/services/hostapd/patches/730-ft_iface.patch
@@ -1,6 +1,6 @@
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
-@@ -3031,6 +3031,8 @@ static int hostapd_config_fill(struct ho
+@@ -3007,6 +3007,8 @@ static int hostapd_config_fill(struct ho
wpa_printf(MSG_INFO,
"Line %d: Obsolete peerkey parameter ignored", line);
#ifdef CONFIG_IEEE80211R_AP
@@ -11,17 +11,17 @@
hexstr2bin(pos, bss->mobility_domain,
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
-@@ -277,6 +277,7 @@ struct airtime_sta_weight {
+@@ -283,6 +283,7 @@ struct airtime_sta_weight {
struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
+ char ft_iface[IFNAMSIZ + 1];
char vlan_bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
-
+ int bridge_hairpin; /* hairpin_mode on bridge members */
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
-@@ -1565,8 +1565,12 @@ int hostapd_setup_wpa(struct hostapd_dat
+@@ -1727,8 +1727,12 @@ int hostapd_setup_wpa(struct hostapd_dat
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
const char *ft_iface;
diff --git a/package/network/services/hostapd/patches/740-snoop_iface.patch b/package/network/services/hostapd/patches/740-snoop_iface.patch
new file mode 100644
index 00000000000..ce64513a421
--- /dev/null
+++ b/package/network/services/hostapd/patches/740-snoop_iface.patch
@@ -0,0 +1,139 @@
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -284,6 +284,7 @@ struct hostapd_bss_config {
+ char iface[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
+ char ft_iface[IFNAMSIZ + 1];
++ char snoop_iface[IFNAMSIZ + 1];
+ char vlan_bridge[IFNAMSIZ + 1];
+ char wds_bridge[IFNAMSIZ + 1];
+ int bridge_hairpin; /* hairpin_mode on bridge members */
+--- a/src/ap/x_snoop.c
++++ b/src/ap/x_snoop.c
+@@ -33,28 +33,31 @@ int x_snoop_init(struct hostapd_data *ha
+
+ hapd->x_snoop_initialized = true;
+
+- if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
++ if (!conf->snoop_iface[0] &&
++ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+ 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable hairpin_mode on the bridge port");
+ return -1;
+ }
+
+- if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
++ if (!conf->snoop_iface[0] &&
++ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable proxyarp on the bridge port");
+ return -1;
+ }
+
+ if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
+- 1)) {
++ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
+ return -1;
+ }
+
+ #ifdef CONFIG_IPV6
+- if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
++ if (!conf->snoop_iface[0] &&
++ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, NULL, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable multicast snooping on the bridge");
+ return -1;
+@@ -73,8 +76,12 @@ x_snoop_get_l2_packet(struct hostapd_dat
+ {
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct l2_packet_data *l2;
++ const char *ifname = conf->bridge;
++
++ if (conf->snoop_iface[0])
++ ifname = conf->snoop_iface;
+
+- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
++ l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1);
+ if (l2 == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to initialize L2 packet processing %s",
+@@ -127,9 +134,12 @@ void x_snoop_mcast_to_ucast_convert_send
+
+ void x_snoop_deinit(struct hostapd_data *hapd)
+ {
++ struct hostapd_bss_config *conf = hapd->conf;
++
+ if (!hapd->x_snoop_initialized)
+ return;
+- hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
++ hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
++ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 0);
+ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
+ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
+ hapd->x_snoop_initialized = false;
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2322,6 +2322,8 @@ static int hostapd_config_fill(struct ho
+ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
+ } else if (os_strcmp(buf, "bridge_hairpin") == 0) {
+ bss->bridge_hairpin = atoi(pos);
++ } else if (os_strcmp(buf, "snoop_iface") == 0) {
++ os_strlcpy(bss->snoop_iface, pos, sizeof(bss->snoop_iface));
+ } else if (os_strcmp(buf, "vlan_bridge") == 0) {
+ os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
+ } else if (os_strcmp(buf, "wds_bridge") == 0) {
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -366,12 +366,12 @@ static inline int hostapd_drv_br_port_se
+
+ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
+ enum drv_br_net_param param,
+- unsigned int val)
++ const char *ifname, unsigned int val)
+ {
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_set_net_param == NULL)
+ return -1;
+- return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
++ return hapd->driver->br_set_net_param(hapd->drv_priv, param, ifname, val);
+ }
+
+ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -4209,7 +4209,7 @@ struct wpa_driver_ops {
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_set_net_param)(void *priv, enum drv_br_net_param param,
+- unsigned int val);
++ const char *ifname, unsigned int val);
+
+ /**
+ * get_wowlan - Get wake-on-wireless status
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -12168,7 +12168,7 @@ static const char * drv_br_net_param_str
+
+
+ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
+- unsigned int val)
++ const char *ifname, unsigned int val)
+ {
+ struct i802_bss *bss = priv;
+ char path[128];
+@@ -12194,8 +12194,11 @@ static int wpa_driver_br_set_net_param(v
+ return -EINVAL;
+ }
+
++ if (!ifname)
++ ifname = bss->brname;
++
+ os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
+- ip_version, bss->brname, param_txt);
++ ip_version, ifname, param_txt);
+
+ set_val:
+ if (linux_write_system_file(path, val))
diff --git a/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch b/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch
new file mode 100644
index 00000000000..97c32df7044
--- /dev/null
+++ b/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch
@@ -0,0 +1,97 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -1604,6 +1604,8 @@ static int parse_anqp_elem(struct hostap
+ return 0;
+ }
+
++#endif /* CONFIG_INTERWORKING */
++
+
+ static int parse_qos_map_set(struct hostapd_bss_config *bss,
+ char *buf, int line)
+@@ -1645,8 +1647,6 @@ static int parse_qos_map_set(struct host
+ return 0;
+ }
+
+-#endif /* CONFIG_INTERWORKING */
+-
+
+ #ifdef CONFIG_HS20
+ static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
+@@ -4062,10 +4062,10 @@ static int hostapd_config_fill(struct ho
+ bss->gas_frag_limit = val;
+ } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+ bss->gas_comeback_delay = atoi(pos);
++#endif /* CONFIG_INTERWORKING */
+ } else if (os_strcmp(buf, "qos_map_set") == 0) {
+ if (parse_qos_map_set(bss, pos, line) < 0)
+ return 1;
+-#endif /* CONFIG_INTERWORKING */
+ #ifdef CONFIG_RADIUS_TEST
+ } else if (os_strcmp(buf, "dump_msk_file") == 0) {
+ os_free(bss->dump_msk_file);
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -1486,6 +1486,7 @@ int hostapd_setup_bss(struct hostapd_dat
+ wpa_printf(MSG_ERROR, "GAS server initialization failed");
+ return -1;
+ }
++#endif /* CONFIG_INTERWORKING */
+
+ if (conf->qos_map_set_len &&
+ hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
+@@ -1493,7 +1494,6 @@ int hostapd_setup_bss(struct hostapd_dat
+ wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
+ return -1;
+ }
+-#endif /* CONFIG_INTERWORKING */
+
+ if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
+ wpa_printf(MSG_ERROR, "BSS Load initialization failed");
+--- a/wpa_supplicant/events.c
++++ b/wpa_supplicant/events.c
+@@ -2683,8 +2683,6 @@ void wnm_bss_keep_alive_deinit(struct wp
+ }
+
+
+-#ifdef CONFIG_INTERWORKING
+-
+ static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+ size_t len)
+ {
+@@ -2717,8 +2715,6 @@ static void interworking_process_assoc_r
+ }
+ }
+
+-#endif /* CONFIG_INTERWORKING */
+-
+
+ static void wpa_supplicant_set_4addr_mode(struct wpa_supplicant *wpa_s)
+ {
+@@ -3098,10 +3094,8 @@ static int wpa_supplicant_event_associnf
+ wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+ #endif /* CONFIG_WNM */
+-#ifdef CONFIG_INTERWORKING
+ interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+-#endif /* CONFIG_INTERWORKING */
+ if (wpa_s->hw_capab == CAPAB_VHT &&
+ get_ie(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
+--- a/src/ap/ieee802_11_shared.c
++++ b/src/ap/ieee802_11_shared.c
+@@ -1116,13 +1116,11 @@ u8 * hostapd_eid_rsnxe(struct hostapd_da
+ u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+ {
+-#ifdef CONFIG_INTERWORKING
+ /* check for QoS Map support */
+ if (ext_capab_ie_len >= 5) {
+ if (ext_capab_ie[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+-#endif /* CONFIG_INTERWORKING */
+
+ if (ext_capab_ie_len > 0) {
+ sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
diff --git a/package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch b/package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch
new file mode 100644
index 00000000000..f5ebab70d1d
--- /dev/null
+++ b/package/network/services/hostapd/patches/751-qos_map_ignore_when_unsupported.patch
@@ -0,0 +1,12 @@
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -927,7 +927,8 @@ int hostapd_start_dfs_cac(struct hostapd
+ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
+ const u8 *qos_map_set, u8 qos_map_set_len)
+ {
+- if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
++ if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv ||
++ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING))
+ return 0;
+ return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
+ qos_map_set_len);
diff --git a/package/network/services/hostapd/patches/760-dynamic_own_ip.patch b/package/network/services/hostapd/patches/760-dynamic_own_ip.patch
new file mode 100644
index 00000000000..2c705a68cf0
--- /dev/null
+++ b/package/network/services/hostapd/patches/760-dynamic_own_ip.patch
@@ -0,0 +1,109 @@
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -310,6 +310,7 @@ struct hostapd_bss_config {
+ unsigned int eap_sim_db_timeout;
+ int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
+ struct hostapd_ip_addr own_ip_addr;
++ int dynamic_own_ip_addr;
+ char *nas_identifier;
+ struct hostapd_radius_servers *radius;
+ int acct_interim_interval;
+--- a/src/radius/radius_client.c
++++ b/src/radius/radius_client.c
+@@ -163,6 +163,8 @@ struct radius_client_data {
+ */
+ void *ctx;
+
++ struct hostapd_ip_addr local_ip;
++
+ /**
+ * conf - RADIUS client configuration (list of RADIUS servers to use)
+ */
+@@ -720,6 +722,30 @@ static void radius_client_list_add(struc
+
+
+ /**
++ * radius_client_send - Get local address for the RADIUS auth socket
++ * @radius: RADIUS client context from radius_client_init()
++ * @addr: pointer to store the address
++ *
++ * This function returns the local address for the connection to the RADIUS
++ * auth server. It also opens the socket if it's not available yet.
++ */
++int radius_client_get_local_addr(struct radius_client_data *radius,
++ struct hostapd_ip_addr *addr)
++{
++ struct hostapd_radius_servers *conf = radius->conf;
++
++ if (conf->auth_server && radius->auth_sock < 0)
++ radius_client_init_auth(radius);
++
++ if (radius->auth_sock < 0)
++ return -1;
++
++ memcpy(addr, &radius->local_ip, sizeof(*addr));
++
++ return 0;
++}
++
++/**
+ * radius_client_send - Send a RADIUS request
+ * @radius: RADIUS client context from radius_client_init()
+ * @msg: RADIUS message to be sent
+@@ -1238,6 +1264,10 @@ radius_change_server(struct radius_clien
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntoa(claddr.sin_addr),
+ ntohs(claddr.sin_port));
++ if (auth) {
++ radius->local_ip.af = AF_INET;
++ radius->local_ip.u.v4 = claddr.sin_addr;
++ }
+ }
+ break;
+ #ifdef CONFIG_IPV6
+@@ -1249,6 +1279,10 @@ radius_change_server(struct radius_clien
+ inet_ntop(AF_INET6, &claddr6.sin6_addr,
+ abuf, sizeof(abuf)),
+ ntohs(claddr6.sin6_port));
++ if (auth) {
++ radius->local_ip.af = AF_INET6;
++ radius->local_ip.u.v6 = claddr6.sin6_addr;
++ }
+ }
+ break;
+ }
+--- a/src/radius/radius_client.h
++++ b/src/radius/radius_client.h
+@@ -249,6 +249,8 @@ int radius_client_register(struct radius
+ void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+ void (*cb)(const u8 *addr, void *ctx),
+ void *ctx);
++int radius_client_get_local_addr(struct radius_client_data *radius,
++ struct hostapd_ip_addr * addr);
+ int radius_client_send(struct radius_client_data *radius,
+ struct radius_msg *msg,
+ RadiusType msg_type, const u8 *addr);
+--- a/src/ap/ieee802_1x.c
++++ b/src/ap/ieee802_1x.c
+@@ -598,6 +598,10 @@ int add_common_radius_attr(struct hostap
+ struct hostapd_radius_attr *attr;
+ int len;
+
++ if (hapd->conf->dynamic_own_ip_addr)
++ radius_client_get_local_addr(hapd->radius,
++ &hapd->conf->own_ip_addr);
++
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET &&
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2688,6 +2688,8 @@ static int hostapd_config_fill(struct ho
+ } else if (os_strcmp(buf, "iapp_interface") == 0) {
+ wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used");
+ #endif /* CONFIG_IAPP */
++ } else if (os_strcmp(buf, "dynamic_own_ip_addr") == 0) {
++ bss->dynamic_own_ip_addr = atoi(pos);
+ } else if (os_strcmp(buf, "own_ip_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+ wpa_printf(MSG_ERROR,
diff --git a/package/network/services/hostapd/patches/761-shared_das_port.patch b/package/network/services/hostapd/patches/761-shared_das_port.patch
new file mode 100644
index 00000000000..cbb2a1be3c4
--- /dev/null
+++ b/package/network/services/hostapd/patches/761-shared_das_port.patch
@@ -0,0 +1,298 @@
+--- a/src/radius/radius_das.h
++++ b/src/radius/radius_das.h
+@@ -44,6 +44,7 @@ struct radius_das_attrs {
+ struct radius_das_conf {
+ int port;
+ const u8 *shared_secret;
++ const u8 *nas_identifier;
+ size_t shared_secret_len;
+ const struct hostapd_ip_addr *client_addr;
+ unsigned int time_window;
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -1423,6 +1423,7 @@ int hostapd_setup_bss(struct hostapd_dat
+
+ os_memset(&das_conf, 0, sizeof(das_conf));
+ das_conf.port = conf->radius_das_port;
++ das_conf.nas_identifier = conf->nas_identifier;
+ das_conf.shared_secret = conf->radius_das_shared_secret;
+ das_conf.shared_secret_len =
+ conf->radius_das_shared_secret_len;
+--- a/src/radius/radius_das.c
++++ b/src/radius/radius_das.c
+@@ -12,13 +12,26 @@
+ #include "utils/common.h"
+ #include "utils/eloop.h"
+ #include "utils/ip_addr.h"
++#include "utils/list.h"
+ #include "radius.h"
+ #include "radius_das.h"
+
+
+-struct radius_das_data {
++static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
++
++struct radius_das_port {
++ struct dl_list list;
++ struct dl_list das_data;
++
++ int port;
+ int sock;
++};
++
++struct radius_das_data {
++ struct dl_list list;
++ struct radius_das_port *port;
+ u8 *shared_secret;
++ u8 *nas_identifier;
+ size_t shared_secret_len;
+ struct hostapd_ip_addr client_addr;
+ unsigned int time_window;
+@@ -378,56 +391,17 @@ fail:
+ }
+
+
+-static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
++static void
++radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg,
++ struct sockaddr *from, socklen_t fromlen,
++ char *abuf, int from_port)
+ {
+- struct radius_das_data *das = eloop_ctx;
+- u8 buf[1500];
+- union {
+- struct sockaddr_storage ss;
+- struct sockaddr_in sin;
+-#ifdef CONFIG_IPV6
+- struct sockaddr_in6 sin6;
+-#endif /* CONFIG_IPV6 */
+- } from;
+- char abuf[50];
+- int from_port = 0;
+- socklen_t fromlen;
+- int len;
+- struct radius_msg *msg, *reply = NULL;
++ struct radius_msg *reply = NULL;
+ struct radius_hdr *hdr;
+ struct wpabuf *rbuf;
++ struct os_time now;
+ u32 val;
+ int res;
+- struct os_time now;
+-
+- fromlen = sizeof(from);
+- len = recvfrom(sock, buf, sizeof(buf), 0,
+- (struct sockaddr *) &from.ss, &fromlen);
+- if (len < 0) {
+- wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
+- return;
+- }
+-
+- os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+- from_port = ntohs(from.sin.sin_port);
+-
+- wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
+- len, abuf, from_port);
+- if (das->client_addr.u.v4.s_addr &&
+- das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+- wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
+- return;
+- }
+-
+- msg = radius_msg_parse(buf, len);
+- if (msg == NULL) {
+- wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
+- "from %s:%d failed", abuf, from_port);
+- return;
+- }
+-
+- if (wpa_debug_level <= MSG_MSGDUMP)
+- radius_msg_dump(msg);
+
+ if (radius_msg_verify_das_req(msg, das->shared_secret,
+ das->shared_secret_len,
+@@ -494,9 +468,8 @@ static void radius_das_receive(int sock,
+ radius_msg_dump(reply);
+
+ rbuf = radius_msg_get_buf(reply);
+- res = sendto(das->sock, wpabuf_head(rbuf),
+- wpabuf_len(rbuf), 0,
+- (struct sockaddr *) &from.ss, fromlen);
++ res = sendto(das->port->sock, wpabuf_head(rbuf),
++ wpabuf_len(rbuf), 0, from, fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
+ abuf, from_port, strerror(errno));
+@@ -508,6 +481,72 @@ fail:
+ radius_msg_free(reply);
+ }
+
++static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
++{
++ struct radius_das_port *p = eloop_ctx;
++ struct radius_das_data *das;
++ u8 buf[1500];
++ union {
++ struct sockaddr_storage ss;
++ struct sockaddr_in sin;
++#ifdef CONFIG_IPV6
++ struct sockaddr_in6 sin6;
++#endif /* CONFIG_IPV6 */
++ } from;
++ struct radius_msg *msg;
++ size_t nasid_len = 0;
++ u8 *nasid_buf = NULL;
++ char abuf[50];
++ int from_port = 0;
++ socklen_t fromlen;
++ int found = 0;
++ int len;
++
++ fromlen = sizeof(from);
++ len = recvfrom(sock, buf, sizeof(buf), 0,
++ (struct sockaddr *) &from.ss, &fromlen);
++ if (len < 0) {
++ wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
++ return;
++ }
++
++ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
++ from_port = ntohs(from.sin.sin_port);
++
++ msg = radius_msg_parse(buf, len);
++ if (msg == NULL) {
++ wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
++ "from %s:%d failed", abuf, from_port);
++ return;
++ }
++
++ wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
++ len, abuf, from_port);
++
++ if (wpa_debug_level <= MSG_MSGDUMP)
++ radius_msg_dump(msg);
++
++ radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
++ &nasid_buf, &nasid_len, NULL);
++ dl_list_for_each(das, &p->das_data, struct radius_das_data, list) {
++ if (das->client_addr.u.v4.s_addr &&
++ das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr)
++ continue;
++
++ if (das->nas_identifier && nasid_buf &&
++ (nasid_len != os_strlen(das->nas_identifier) ||
++ os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0))
++ continue;
++
++ found = 1;
++ radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
++ fromlen, abuf, from_port);
++ }
++
++ if (!found)
++ wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
++}
++
+
+ static int radius_das_open_socket(int port)
+ {
+@@ -533,6 +572,49 @@ static int radius_das_open_socket(int po
+ }
+
+
++static struct radius_das_port *
++radius_das_open_port(int port)
++{
++ struct radius_das_port *p;
++
++ dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
++ if (p->port == port)
++ return p;
++ }
++
++ p = os_zalloc(sizeof(*p));
++ if (p == NULL)
++ return NULL;
++
++ dl_list_init(&p->das_data);
++ p->port = port;
++ p->sock = radius_das_open_socket(port);
++ if (p->sock < 0)
++ goto free_port;
++
++ if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
++ goto close_port;
++
++ dl_list_add(&das_ports, &p->list);
++
++ return p;
++
++close_port:
++ close(p->sock);
++free_port:
++ os_free(p);
++
++ return NULL;
++}
++
++static void radius_das_close_port(struct radius_das_port *p)
++{
++ dl_list_del(&p->list);
++ eloop_unregister_read_sock(p->sock);
++ close(p->sock);
++ free(p);
++}
++
+ struct radius_das_data *
+ radius_das_init(struct radius_das_conf *conf)
+ {
+@@ -553,6 +635,8 @@ radius_das_init(struct radius_das_conf *
+ das->ctx = conf->ctx;
+ das->disconnect = conf->disconnect;
+ das->coa = conf->coa;
++ if (conf->nas_identifier)
++ das->nas_identifier = os_strdup(conf->nas_identifier);
+
+ os_memcpy(&das->client_addr, conf->client_addr,
+ sizeof(das->client_addr));
+@@ -565,19 +649,15 @@ radius_das_init(struct radius_das_conf *
+ }
+ das->shared_secret_len = conf->shared_secret_len;
+
+- das->sock = radius_das_open_socket(conf->port);
+- if (das->sock < 0) {
++ das->port = radius_das_open_port(conf->port);
++ if (!das->port) {
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
+ "DAS");
+ radius_das_deinit(das);
+ return NULL;
+ }
+
+- if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
+- {
+- radius_das_deinit(das);
+- return NULL;
+- }
++ dl_list_add(&das->port->das_data, &das->list);
+
+ return das;
+ }
+@@ -588,11 +668,14 @@ void radius_das_deinit(struct radius_das
+ if (das == NULL)
+ return;
+
+- if (das->sock >= 0) {
+- eloop_unregister_read_sock(das->sock);
+- close(das->sock);
++ if (das->port) {
++ dl_list_del(&das->list);
++
++ if (dl_list_empty(&das->port->das_data))
++ radius_das_close_port(das->port);
+ }
+
++ os_free(das->nas_identifier);
+ os_free(das->shared_secret);
+ os_free(das);
+ }
diff --git a/package/network/services/hostapd/patches/770-radius_server.patch b/package/network/services/hostapd/patches/770-radius_server.patch
new file mode 100644
index 00000000000..8837a26257b
--- /dev/null
+++ b/package/network/services/hostapd/patches/770-radius_server.patch
@@ -0,0 +1,154 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -63,6 +63,10 @@ endif
+ OBJS += main.o
+ OBJS += config_file.o
+
++ifdef CONFIG_RADIUS_SERVER
++OBJS += radius.o
++endif
++
+ OBJS += ../src/ap/hostapd.o
+ OBJS += ../src/ap/wpa_auth_glue.o
+ OBJS += ../src/ap/drv_callbacks.o
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -40,6 +40,7 @@ struct hapd_global {
+
+ static struct hapd_global global;
+
++extern int radius_main(int argc, char **argv);
+
+ #ifndef CONFIG_NO_HOSTAPD_LOGGER
+ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+@@ -771,6 +772,11 @@ int main(int argc, char *argv[])
+ if (os_program_init())
+ return -1;
+
++#ifdef RADIUS_SERVER
++ if (strstr(argv[0], "radius"))
++ return radius_main(argc, argv);
++#endif
++
+ os_memset(&interfaces, 0, sizeof(interfaces));
+ interfaces.reload_config = hostapd_reload_config;
+ interfaces.config_read_cb = hostapd_config_read;
+--- a/src/radius/radius_server.c
++++ b/src/radius/radius_server.c
+@@ -63,6 +63,12 @@ struct radius_server_counters {
+ u32 unknown_acct_types;
+ };
+
++struct radius_accept_attr {
++ u8 type;
++ u16 len;
++ void *data;
++};
++
+ /**
+ * struct radius_session - Internal RADIUS server data for a session
+ */
+@@ -90,7 +96,7 @@ struct radius_session {
+ unsigned int macacl:1;
+ unsigned int t_c_filtering:1;
+
+- struct hostapd_radius_attr *accept_attr;
++ struct radius_accept_attr *accept_attr;
+
+ u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
+ };
+@@ -394,6 +400,7 @@ static void radius_server_session_free(s
+ radius_msg_free(sess->last_reply);
+ os_free(sess->username);
+ os_free(sess->nas_ip);
++ os_free(sess->accept_attr);
+ os_free(sess);
+ data->num_sess--;
+ }
+@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius
+ }
+ #endif /* CONFIG_ERP */
+
++static struct radius_accept_attr *
++radius_server_copy_attr(const struct hostapd_radius_attr *data)
++{
++ const struct hostapd_radius_attr *attr;
++ struct radius_accept_attr *attr_new;
++ size_t data_size = 0;
++ void *data_buf;
++ int n_attr = 1;
++
++ for (attr = data; attr; attr = attr->next) {
++ n_attr++;
++ data_size += wpabuf_len(attr->val);
++ }
++
++ attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size);
++ if (!attr_new)
++ return NULL;
++
++ data_buf = &attr_new[n_attr];
++ for (n_attr = 0, attr = data; attr; attr = attr->next) {
++ struct radius_accept_attr *cur = &attr_new[n_attr++];
++
++ cur->type = attr->type;
++ cur->len = wpabuf_len(attr->val);
++ cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len);
++ data_buf += cur->len;
++ }
++
++ return attr_new;
++}
+
+ static struct radius_session *
+ radius_server_get_new_session(struct radius_server_data *data,
+@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad
+ eap_user_free(tmp);
+ return NULL;
+ }
+- sess->accept_attr = tmp->accept_attr;
++ sess->accept_attr = radius_server_copy_attr(tmp->accept_attr);
+ sess->macacl = tmp->macacl;
+ eap_user_free(tmp);
+
+@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+- struct hostapd_radius_attr *attr;
+- for (attr = sess->accept_attr; attr; attr = attr->next) {
+- if (!radius_msg_add_attr(msg, attr->type,
+- wpabuf_head(attr->val),
+- wpabuf_len(attr->val))) {
++ struct radius_accept_attr *attr;
++ for (attr = sess->accept_attr; attr->data; attr++) {
++ if (!radius_msg_add_attr(msg, attr->type, attr->data,
++ attr->len)) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+- struct hostapd_radius_attr *attr;
+- for (attr = sess->accept_attr; attr; attr = attr->next) {
+- if (!radius_msg_add_attr(msg, attr->type,
+- wpabuf_head(attr->val),
+- wpabuf_len(attr->val))) {
++ struct radius_accept_attr *attr;
++ for (attr = sess->accept_attr; attr->data; attr++) {
++ if (!radius_msg_add_attr(msg, attr->type, attr->data,
++ attr->len)) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo
+ ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
+ phase2, user);
+ if (ret == 0 && user) {
+- sess->accept_attr = user->accept_attr;
++ sess->accept_attr = radius_server_copy_attr(user->accept_attr);
+ sess->remediation = user->remediation;
+ sess->macacl = user->macacl;
+ sess->t_c_timestamp = user->t_c_timestamp;
diff --git a/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch b/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch
new file mode 100644
index 00000000000..5809a3b7e81
--- /dev/null
+++ b/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch
@@ -0,0 +1,33 @@
+From f0e9f5aab52b3eab85d28338cc996972ced4c39c Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Tue, 17 May 2022 23:07:59 +0200
+Subject: [PATCH] ctrl: make WNM_AP functions dependant on CONFIG_AP
+
+This fixes linking errors found when compiling wpa_supplicant with
+CONFIG_WNM_AP enabled but CONFIG_AP disabled.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ wpa_supplicant/ctrl_iface.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/wpa_supplicant/ctrl_iface.c
++++ b/wpa_supplicant/ctrl_iface.c
+@@ -12763,7 +12763,7 @@ char * wpa_supplicant_ctrl_iface_process
+ if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
+ reply_len = -1;
+ #endif /* CONFIG_WNM */
+-#ifdef CONFIG_WNM_AP
++#if defined(CONFIG_AP) && defined(CONFIG_WNM_AP)
+ } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+ if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18))
+ reply_len = -1;
+@@ -12773,7 +12773,7 @@ char * wpa_supplicant_ctrl_iface_process
+ } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
+ if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11))
+ reply_len = -1;
+-#endif /* CONFIG_WNM_AP */
++#endif /* CONFIG_AP && CONFIG_WNM_AP */
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ wpa_supplicant_ctrl_iface_flush(wpa_s);
+ } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
diff --git a/package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch b/package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch
new file mode 100644
index 00000000000..097d62abc01
--- /dev/null
+++ b/package/network/services/hostapd/patches/991-Fix-OpenWrt-13156.patch
@@ -0,0 +1,63 @@
+From 26cd9bafc1d25e602952ee86cd2a5b8c3a995490 Mon Sep 17 00:00:00 2001
+From: Stijn Tintel <stijn@linux-ipv6.be>
+Date: Fri, 28 Jul 2023 16:27:47 +0300
+Subject: [PATCH] Revert "Do prune_association only after the STA is
+ authorized"
+
+Commit e978072baaca ("Do prune_association only after the STA is
+authorized") causes issues when an STA roams from one interface to
+another interface on the same PHY. The mt7915 driver is not able to
+handle this properly. While the commits fixes a DoS, there are other
+devices and drivers with the same limitation, so revert to the orginal
+behavior for now, until we have a better solution in place.
+
+Ref: https://github.com/openwrt/openwrt/issues/13156
+Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
+---
+ src/ap/hostapd.c | 14 +++++++++++---
+ src/ap/sta_info.c | 3 ---
+ 2 files changed, 11 insertions(+), 6 deletions(-)
+
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -3564,6 +3564,8 @@ int hostapd_remove_iface(struct hapd_int
+ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc)
+ {
++ int mld_assoc_link_id = -1;
++
+ if (hapd->tkip_countermeasures) {
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_MICHAEL_MIC_FAILURE);
+@@ -3571,10 +3573,16 @@ void hostapd_new_assoc_sta(struct hostap
+ }
+
+ #ifdef CONFIG_IEEE80211BE
+- if (hapd->conf->mld_ap && sta->mld_info.mld_sta &&
+- sta->mld_assoc_link_id != hapd->mld_link_id)
+- return;
++ if (hapd->conf->mld_ap && sta->mld_info.mld_sta) {
++ if (sta->mld_assoc_link_id == hapd->mld_link_id) {
++ mld_assoc_link_id = sta->mld_assoc_link_id;
++ } else {
++ return;
++ }
++ }
+ #endif /* CONFIG_IEEE80211BE */
++ if (mld_assoc_link_id != -2)
++ hostapd_prune_associations(hapd, sta->addr, mld_assoc_link_id);
+
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
+ sta->post_csa_sa_query = 0;
+--- a/src/ap/sta_info.c
++++ b/src/ap/sta_info.c
+@@ -1318,9 +1318,6 @@ void ap_sta_set_authorized(struct hostap
+ mld_assoc_link_id = -2;
+ }
+ #endif /* CONFIG_IEEE80211BE */
+- if (mld_assoc_link_id != -2)
+- hostapd_prune_associations(hapd, sta->addr,
+- mld_assoc_link_id);
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ } else {
+ sta->flags &= ~WLAN_STA_AUTHORIZED;
diff --git a/package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch b/package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch
new file mode 100644
index 00000000000..c7b595da57d
--- /dev/null
+++ b/package/network/services/hostapd/patches/992-nl80211-add-extra-ies-only-if-allowed-by-driver.patch
@@ -0,0 +1,62 @@
+From: David Bauer <mail@david-bauer.net>
+To: hostap@lists.infradead.org
+Cc: =?utf-8?q?=C3=89tienne_Morice?= <neon.emorice@mail.com>
+Subject: [PATCH] nl80211: add extra-ies only if allowed by driver
+Date: Sun, 30 Jan 2022 20:22:00 +0100
+Message-Id: <20220130192200.10883-1-mail@david-bauer.net>
+List-Id: <hostap.lists.infradead.org>
+
+Upgrading wpa_supplicant from 2.9 to 2.10 breaks broadcom-wl
+based adapters. The reason for it is hostapd tries to install additional
+IEs for scanning while the driver does not support this.
+
+The kernel indicates the maximum number of bytes for additional scan IEs
+using the NL80211_ATTR_MAX_SCAN_IE_LEN attribute. Save this value and
+only add additional scan IEs in case the driver can accommodate these
+additional IEs.
+
+Reported-by: Étienne Morice <neon.emorice@mail.com>
+Tested-by: Étienne Morice <neon.emorice@mail.com>
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ src/drivers/driver.h | 3 +++
+ src/drivers/driver_nl80211_capa.c | 4 ++++
+ src/drivers/driver_nl80211_scan.c | 2 +-
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -2283,6 +2283,9 @@ struct wpa_driver_capa {
+ /** Maximum number of iterations in a single scan plan */
+ u32 max_sched_scan_plan_iterations;
+
++ /** Maximum number of extra IE bytes for scans */
++ u16 max_scan_ie_len;
++
+ /** Whether sched_scan (offloaded scanning) is supported */
+ int sched_scan_supported;
+
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -949,6 +949,10 @@ static int wiphy_info_handler(struct nl_
+ nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]);
+ }
+
++ if (tb[NL80211_ATTR_MAX_SCAN_IE_LEN])
++ capa->max_scan_ie_len =
++ nla_get_u16(tb[NL80211_ATTR_MAX_SCAN_IE_LEN]);
++
+ if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+ capa->max_match_sets =
+ nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+--- a/src/drivers/driver_nl80211_scan.c
++++ b/src/drivers/driver_nl80211_scan.c
+@@ -222,7 +222,7 @@ nl80211_scan_common(struct i802_bss *bss
+ wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
+ }
+
+- if (params->extra_ies) {
++ if (params->extra_ies && drv->capa.max_scan_ie_len >= params->extra_ies_len) {
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
diff --git a/package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch b/package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch
new file mode 100644
index 00000000000..948c51b196b
--- /dev/null
+++ b/package/network/services/hostapd/patches/993-2023-10-28-ACS-Fix-typo-in-bw_40-frequency-array.patch
@@ -0,0 +1,25 @@
+From 7a733993211ad46cf3032038c1e7e6bdc2322336 Mon Sep 17 00:00:00 2001
+From: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Date: Tue, 5 Sep 2023 09:43:25 +0800
+Subject: [PATCH] ACS: Fix typo in bw_40 frequency array
+
+The range for the 5 GHz channel 118 was encoded with an incorrect
+channel number.
+
+Fixes: ed8e13decc71 (ACS: Extract bw40/80/160 freqs out of acs_usable_bwXXX_chan())
+Signed-off-by: Michael Lee <michael-cy.lee@mediatek.com>
+---
+ src/ap/acs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/ap/acs.c
++++ b/src/ap/acs.c
+@@ -256,7 +256,7 @@ struct bw_item {
+ static const struct bw_item bw_40[] = {
+ { 5180, 5200, 38 }, { 5220, 5240, 46 }, { 5260, 5280, 54 },
+ { 5300, 5320, 62 }, { 5500, 5520, 102 }, { 5540, 5560, 110 },
+- { 5580, 5600, 110 }, { 5620, 5640, 126}, { 5660, 5680, 134 },
++ { 5580, 5600, 118 }, { 5620, 5640, 126 }, { 5660, 5680, 134 },
+ { 5700, 5720, 142 }, { 5745, 5765, 151 }, { 5785, 5805, 159 },
+ { 5825, 5845, 167 }, { 5865, 5885, 175 },
+ { 5955, 5975, 3 }, { 5995, 6015, 11 }, { 6035, 6055, 19 },
diff --git a/package/network/services/hostapd/src/hostapd/radius.c b/package/network/services/hostapd/src/hostapd/radius.c
new file mode 100644
index 00000000000..362a22c276e
--- /dev/null
+++ b/package/network/services/hostapd/src/hostapd/radius.c
@@ -0,0 +1,715 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/tls.h"
+
+#include "ap/ap_config.h"
+#include "eap_server/eap.h"
+#include "radius/radius.h"
+#include "radius/radius_server.h"
+#include "eap_register.h"
+
+#include <libubox/blobmsg_json.h>
+#include <libubox/blobmsg.h>
+#include <libubox/avl.h>
+#include <libubox/avl-cmp.h>
+#include <libubox/kvlist.h>
+
+#include <sys/stat.h>
+#include <fnmatch.h>
+
+#define VENDOR_ID_WISPR 14122
+#define VENDOR_ATTR_SIZE 6
+
+struct radius_parse_attr_data {
+ unsigned int vendor;
+ u8 type;
+ int size;
+ char format;
+ const char *data;
+};
+
+struct radius_parse_attr_state {
+ struct hostapd_radius_attr *prev;
+ struct hostapd_radius_attr *attr;
+ struct wpabuf *buf;
+ void *attrdata;
+};
+
+struct radius_user_state {
+ struct avl_node node;
+ struct eap_user data;
+};
+
+struct radius_user_data {
+ struct kvlist users;
+ struct avl_tree user_state;
+ struct blob_attr *wildcard;
+};
+
+struct radius_state {
+ struct radius_server_data *radius;
+ struct eap_config eap;
+
+ struct radius_user_data phase1, phase2;
+ const char *user_file;
+ time_t user_file_ts;
+
+ int n_attrs;
+ struct hostapd_radius_attr *attrs;
+};
+
+struct radius_config {
+ struct tls_connection_params tls;
+ struct radius_server_conf radius;
+};
+
+enum {
+ USER_ATTR_PASSWORD,
+ USER_ATTR_HASH,
+ USER_ATTR_SALT,
+ USER_ATTR_METHODS,
+ USER_ATTR_RADIUS,
+ USER_ATTR_VLAN,
+ USER_ATTR_MAX_RATE_UP,
+ USER_ATTR_MAX_RATE_DOWN,
+ __USER_ATTR_MAX
+};
+
+static void radius_tls_event(void *ctx, enum tls_event ev,
+ union tls_event_data *data)
+{
+ switch (ev) {
+ case TLS_CERT_CHAIN_SUCCESS:
+ wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
+ break;
+ case TLS_CERT_CHAIN_FAILURE:
+ wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+ data->cert_fail.reason,
+ data->cert_fail.depth,
+ data->cert_fail.subject,
+ data->cert_fail.reason_txt);
+ break;
+ case TLS_PEER_CERTIFICATE:
+ wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
+ data->peer_cert.depth,
+ data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+ data->peer_cert.subject);
+ break;
+ case TLS_ALERT:
+ if (data->alert.is_local)
+ wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
+ data->alert.description);
+ else
+ wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
+ data->alert.description);
+ break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ /* Not applicable to TLS server */
+ break;
+ }
+}
+
+static void radius_userdata_init(struct radius_user_data *u)
+{
+ kvlist_init(&u->users, kvlist_blob_len);
+ avl_init(&u->user_state, avl_strcmp, false, NULL);
+}
+
+static void radius_userdata_free(struct radius_user_data *u)
+{
+ struct radius_user_state *s, *tmp;
+
+ kvlist_free(&u->users);
+ free(u->wildcard);
+ u->wildcard = NULL;
+ avl_remove_all_elements(&u->user_state, s, node, tmp)
+ free(s);
+}
+
+static void
+radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
+{
+ enum {
+ USERSTATE_USERS,
+ USERSTATE_WILDCARD,
+ __USERSTATE_MAX,
+ };
+ static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
+ [USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
+ [USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
+ };
+ struct blob_attr *tb[__USERSTATE_MAX], *cur;
+ int rem;
+
+ if (!data)
+ return;
+
+ blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+ blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
+ kvlist_set(&u->users, blobmsg_name(cur), cur);
+
+ if (tb[USERSTATE_WILDCARD])
+ u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
+}
+
+static void
+load_userfile(struct radius_state *s)
+{
+ enum {
+ USERDATA_PHASE1,
+ USERDATA_PHASE2,
+ __USERDATA_MAX
+ };
+ static const struct blobmsg_policy policy[__USERDATA_MAX] = {
+ [USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
+ [USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
+ };
+ struct blob_attr *tb[__USERDATA_MAX], *cur;
+ static struct blob_buf b;
+ struct stat st;
+ int rem;
+
+ if (stat(s->user_file, &st))
+ return;
+
+ if (s->user_file_ts == st.st_mtime)
+ return;
+
+ s->user_file_ts = st.st_mtime;
+ radius_userdata_free(&s->phase1);
+ radius_userdata_free(&s->phase2);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_json_from_file(&b, s->user_file);
+ blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
+ radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
+ radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
+
+ blob_buf_free(&b);
+}
+
+static struct blob_attr *
+radius_user_get(struct radius_user_data *s, const char *name)
+{
+ struct blob_attr *cur;
+ int rem;
+
+ cur = kvlist_get(&s->users, name);
+ if (cur)
+ return cur;
+
+ blobmsg_for_each_attr(cur, s->wildcard, rem) {
+ static const struct blobmsg_policy policy = {
+ "name", BLOBMSG_TYPE_STRING
+ };
+ struct blob_attr *pattern;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
+ continue;
+
+ blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
+ if (!name)
+ continue;
+
+ if (!fnmatch(blobmsg_get_string(pattern), name, 0))
+ return cur;
+ }
+
+ return NULL;
+}
+
+static struct radius_parse_attr_data *
+radius_parse_attr(struct blob_attr *attr)
+{
+ static const struct blobmsg_policy policy[4] = {
+ { .type = BLOBMSG_TYPE_INT32 },
+ { .type = BLOBMSG_TYPE_INT32 },
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ };
+ static struct radius_parse_attr_data data;
+ struct blob_attr *tb[4];
+ const char *format;
+
+ blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
+
+ if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
+ return NULL;
+
+ format = blobmsg_get_string(tb[2]);
+ if (strlen(format) != 1)
+ return NULL;
+
+ data.vendor = blobmsg_get_u32(tb[0]);
+ data.type = blobmsg_get_u32(tb[1]);
+ data.format = format[0];
+ data.data = blobmsg_get_string(tb[3]);
+ data.size = strlen(data.data);
+
+ switch (data.format) {
+ case 's':
+ break;
+ case 'x':
+ if (data.size & 1)
+ return NULL;
+ data.size /= 2;
+ break;
+ case 'd':
+ data.size = 4;
+ break;
+ default:
+ return NULL;
+ }
+
+ return &data;
+}
+
+static void
+radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
+{
+ struct blob_attr *data = tb[USER_ATTR_RADIUS];
+ struct blob_attr *cur;
+ int rem;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ struct radius_parse_attr_data *data;
+ size_t prev = *attr_size;
+
+ data = radius_parse_attr(cur);
+ if (!data)
+ continue;
+
+ *attr_size += data->size;
+ if (data->vendor)
+ *attr_size += VENDOR_ATTR_SIZE;
+
+ (*n_attr)++;
+ }
+
+ *n_attr += !!tb[USER_ATTR_VLAN] * 3 +
+ !!tb[USER_ATTR_MAX_RATE_UP] +
+ !!tb[USER_ATTR_MAX_RATE_DOWN];
+ *attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
+ !!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
+ !!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
+}
+
+static void *
+radius_add_attr(struct radius_parse_attr_state *state,
+ u32 vendor, u8 type, u8 len)
+{
+ struct hostapd_radius_attr *attr;
+ struct wpabuf *buf;
+ void *val;
+
+ val = state->attrdata;
+
+ buf = state->buf++;
+ buf->buf = val;
+
+ attr = state->attr++;
+ attr->val = buf;
+ attr->type = type;
+
+ if (state->prev)
+ state->prev->next = attr;
+ state->prev = attr;
+
+ if (vendor) {
+ u8 *vendor_hdr = val + 4;
+
+ WPA_PUT_BE32(val, vendor);
+ vendor_hdr[0] = type;
+ vendor_hdr[1] = len + 2;
+
+ len += VENDOR_ATTR_SIZE;
+ val += VENDOR_ATTR_SIZE;
+ attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
+ }
+
+ buf->size = buf->used = len;
+ state->attrdata += len;
+
+ return val;
+}
+
+static void
+radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
+{
+ struct blob_attr *data = tb[USER_ATTR_RADIUS];
+ struct hostapd_radius_attr *prev = NULL;
+ struct blob_attr *cur;
+ int len, rem;
+ void *val;
+
+ if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
+ char buf[5];
+
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
+ WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
+
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
+ WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
+
+ len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
+ memcpy(val, buf, len);
+ }
+
+ if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
+ val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
+ WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+ }
+
+ if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
+ val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
+ WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+ }
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ struct radius_parse_attr_data *data;
+ void *val;
+ int size;
+
+ data = radius_parse_attr(cur);
+ if (!data)
+ continue;
+
+ val = radius_add_attr(state, data->vendor, data->type, data->size);
+ switch (data->format) {
+ case 's':
+ memcpy(val, data->data, data->size);
+ break;
+ case 'x':
+ hexstr2bin(data->data, val, data->size);
+ break;
+ case 'd':
+ WPA_PUT_BE32(val, atoi(data->data));
+ break;
+ }
+ }
+}
+
+static void
+radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
+{
+ struct blob_attr *cur;
+ int rem, n = 0;
+
+ if (!data)
+ return;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ const char *method;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ if (n == EAP_MAX_METHODS)
+ break;
+
+ method = blobmsg_get_string(cur);
+ eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
+ if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
+ eap->methods[n].method == EAP_TYPE_NONE) {
+ if (!strcmp(method, "TTLS-PAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-CHAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-MSCHAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-MSCHAPV2")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+ continue;
+ }
+ }
+ n++;
+ }
+}
+
+static struct eap_user *
+radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
+ const char *id)
+{
+ static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
+ [USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
+ [USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
+ [USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
+ [USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
+ [USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
+ };
+ struct blob_attr *tb[__USER_ATTR_MAX], *cur;
+ char *password_buf, *salt_buf, *name_buf;
+ struct radius_parse_attr_state astate = {};
+ struct hostapd_radius_attr *attr;
+ struct radius_user_state *state;
+ int pw_len = 0, salt_len = 0;
+ struct eap_user *eap;
+ struct wpabuf *val;
+ size_t attrsize = 0;
+ void *attrdata;
+ int n_attr = 0;
+
+ state = avl_find_element(&u->user_state, id, state, node);
+ if (state)
+ return &state->data;
+
+ blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+ if ((cur = tb[USER_ATTR_SALT]) != NULL)
+ salt_len = strlen(blobmsg_get_string(cur)) / 2;
+ if ((cur = tb[USER_ATTR_HASH]) != NULL)
+ pw_len = strlen(blobmsg_get_string(cur)) / 2;
+ else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+ pw_len = blobmsg_len(cur) - 1;
+ radius_count_attrs(tb, &n_attr, &attrsize);
+
+ state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
+ &password_buf, pw_len,
+ &salt_buf, salt_len,
+ &astate.attr, n_attr * sizeof(*astate.attr),
+ &astate.buf, n_attr * sizeof(*astate.buf),
+ &astate.attrdata, attrsize);
+ eap = &state->data;
+ eap->salt = salt_len ? salt_buf : NULL;
+ eap->salt_len = salt_len;
+ eap->password = pw_len ? password_buf : NULL;
+ eap->password_len = pw_len;
+ eap->force_version = -1;
+
+ if ((cur = tb[USER_ATTR_SALT]) != NULL)
+ hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
+ if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+ memcpy(password_buf, blobmsg_get_string(cur), pw_len);
+ else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
+ hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
+ eap->password_hash = 1;
+ }
+ radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
+
+ if (n_attr > 0) {
+ cur = tb[USER_ATTR_RADIUS];
+ eap->accept_attr = astate.attr;
+ radius_parse_attrs(tb, &astate);
+ }
+
+ state->node.key = strcpy(name_buf, id);
+ avl_insert(&u->user_state, &state->node);
+
+ return &state->data;
+
+free:
+ free(state);
+ return NULL;
+}
+
+static int radius_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ struct radius_state *s = ctx;
+ struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
+ struct blob_attr *entry;
+ struct eap_user *data;
+ char *id;
+
+ if (identity_len > 512)
+ return -1;
+
+ load_userfile(s);
+
+ id = alloca(identity_len + 1);
+ memcpy(id, identity, identity_len);
+ id[identity_len] = 0;
+
+ entry = radius_user_get(u, id);
+ if (!entry)
+ return -1;
+
+ if (!user)
+ return 0;
+
+ data = radius_user_get_state(u, entry, id);
+ if (!data)
+ return -1;
+
+ *user = *data;
+ if (user->password_len > 0)
+ user->password = os_memdup(user->password, user->password_len);
+ if (user->salt_len > 0)
+ user->salt = os_memdup(user->salt, user->salt_len);
+ user->phase2 = phase2;
+
+ return 0;
+}
+
+static int radius_setup(struct radius_state *s, struct radius_config *c)
+{
+ struct eap_config *eap = &s->eap;
+ struct tls_config conf = {
+ .event_cb = radius_tls_event,
+ .tls_flags = TLS_CONN_DISABLE_TLSv1_3,
+ .cb_ctx = s,
+ };
+
+ eap->eap_server = 1;
+ eap->max_auth_rounds = 100;
+ eap->max_auth_rounds_short = 50;
+ eap->ssl_ctx = tls_init(&conf);
+ if (!eap->ssl_ctx) {
+ wpa_printf(MSG_INFO, "TLS init failed\n");
+ return 1;
+ }
+
+ if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
+ wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
+ return 1;
+ }
+
+ c->radius.eap_cfg = eap;
+ c->radius.conf_ctx = s;
+ c->radius.get_eap_user = radius_get_eap_user;
+ s->radius = radius_server_init(&c->radius);
+ if (!s->radius) {
+ wpa_printf(MSG_INFO, "failed to initialize radius server\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int radius_init(struct radius_state *s)
+{
+ memset(s, 0, sizeof(*s));
+ radius_userdata_init(&s->phase1);
+ radius_userdata_init(&s->phase2);
+}
+
+static void radius_deinit(struct radius_state *s)
+{
+ if (s->radius)
+ radius_server_deinit(s->radius);
+
+ if (s->eap.ssl_ctx)
+ tls_deinit(s->eap.ssl_ctx);
+
+ radius_userdata_free(&s->phase1);
+ radius_userdata_free(&s->phase2);
+}
+
+static int usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s <options>\n",
+ progname);
+}
+
+int radius_main(int argc, char **argv)
+{
+ static struct radius_state state = {};
+ static struct radius_config config = {};
+ const char *progname = argv[0];
+ int ret = 0;
+ int ch;
+
+ wpa_debug_setup_stdout();
+ wpa_debug_level = 0;
+
+ if (eloop_init()) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ return 1;
+ }
+
+ eap_server_register_methods();
+ radius_init(&state);
+
+ while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
+ switch (ch) {
+ case '6':
+ config.radius.ipv6 = 1;
+ break;
+ case 'C':
+ config.tls.ca_cert = optarg;
+ break;
+ case 'c':
+ if (config.tls.client_cert2)
+ return usage(progname);
+
+ if (config.tls.client_cert)
+ config.tls.client_cert2 = optarg;
+ else
+ config.tls.client_cert = optarg;
+ break;
+ case 'd':
+ config.tls.dh_file = optarg;
+ break;
+ case 'i':
+ state.eap.server_id = optarg;
+ state.eap.server_id_len = strlen(optarg);
+ break;
+ case 'k':
+ if (config.tls.private_key2)
+ return usage(progname);
+
+ if (config.tls.private_key)
+ config.tls.private_key2 = optarg;
+ else
+ config.tls.private_key = optarg;
+ break;
+ case 'K':
+ if (config.tls.private_key_passwd2)
+ return usage(progname);
+
+ if (config.tls.private_key_passwd)
+ config.tls.private_key_passwd2 = optarg;
+ else
+ config.tls.private_key_passwd = optarg;
+ break;
+ case 'p':
+ config.radius.auth_port = atoi(optarg);
+ break;
+ case 'P':
+ config.radius.acct_port = atoi(optarg);
+ break;
+ case 's':
+ config.radius.client_file = optarg;
+ break;
+ case 'u':
+ state.user_file = optarg;
+ break;
+ default:
+ return usage(progname);
+ }
+ }
+
+ if (!config.tls.client_cert || !config.tls.private_key ||
+ !config.radius.client_file || !state.eap.server_id ||
+ !state.user_file) {
+ wpa_printf(MSG_INFO, "missing options\n");
+ goto out;
+ }
+
+ ret = radius_setup(&state, &config);
+ if (ret)
+ goto out;
+
+ load_userfile(&state);
+ eloop_run();
+
+out:
+ radius_deinit(&state);
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c
index 07c366508c4..66eba999017 100644
--- a/package/network/services/hostapd/src/src/ap/ubus.c
+++ b/package/network/services/hostapd/src/src/ap/ubus.c
@@ -11,6 +11,7 @@
#include "utils/eloop.h"
#include "utils/wpabuf.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "hostapd.h"
#include "neighbor_db.h"
#include "wps_hostapd.h"
@@ -22,16 +23,12 @@
#include "wnm_ap.h"
#include "taxonomy.h"
#include "airtime_policy.h"
+#include "hw_features.h"
static struct ubus_context *ctx;
static struct blob_buf b;
static int ctx_ref;
-static inline struct hapd_interfaces *get_hapd_interfaces_from_object(struct ubus_object *obj)
-{
- return container_of(obj, struct hapd_interfaces, ubus);
-}
-
static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
{
return container_of(obj, struct hostapd_data, ubus.obj);
@@ -42,12 +39,6 @@ struct ubus_banned_client {
u8 addr[ETH_ALEN];
};
-static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct ubus_context *ctx = eloop_ctx;
- ubus_handle_event(ctx);
-}
-
static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
{
if (ubus_reconnect(ctx, NULL)) {
@@ -55,12 +46,12 @@ static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
return;
}
- eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+ ubus_add_uloop(ctx);
}
static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
{
- eloop_unregister_read_sock(ctx->sock.fd);
+ uloop_fd_delete(&ctx->sock);
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
}
@@ -69,12 +60,14 @@ static bool hostapd_ubus_init(void)
if (ctx)
return true;
+ eloop_add_uloop();
ctx = ubus_connect(NULL);
if (!ctx)
return false;
ctx->connection_lost = hostapd_ubus_connection_lost;
- eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+ ubus_add_uloop(ctx);
+
return true;
}
@@ -92,7 +85,7 @@ static void hostapd_ubus_ref_dec(void)
if (ctx_ref)
return;
- eloop_unregister_read_sock(ctx->sock.fd);
+ uloop_fd_delete(&ctx->sock);
ubus_free(ctx);
ctx = NULL;
}
@@ -125,38 +118,6 @@ static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *ev
free(event_type);
}
-static void hostapd_send_procd_event(char *bssname, char *event)
-{
- char *name, *s;
- uint32_t id;
- void *v;
-
- if (!ctx || ubus_lookup_id(ctx, "service", &id))
- return;
-
- if (asprintf(&name, "hostapd.%s.%s", bssname, event) < 0)
- return;
-
- blob_buf_init(&b, 0);
-
- s = blobmsg_alloc_string_buffer(&b, "type", strlen(name) + 1);
- sprintf(s, "%s", name);
- blobmsg_add_string_buffer(&b);
-
- v = blobmsg_open_table(&b, "data");
- blobmsg_close_table(&b, v);
-
- ubus_invoke(ctx, id, "event", b.head, NULL, NULL, 1000);
-
- free(name);
-}
-
-static void hostapd_send_shared_event(struct ubus_object *obj, char *bssname, char *event)
-{
- hostapd_send_procd_event(bssname, event);
- hostapd_notify_ubus(obj, bssname, event);
-}
-
static void
hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
{
@@ -201,10 +162,8 @@ hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct blob_attr *msg)
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
- int ret = hostapd_reload_config(hapd->iface, 1);
- hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "reload");
- return ret;
+ return hostapd_reload_config(hapd->iface);
}
@@ -316,10 +275,24 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
blobmsg_add_u8(&b, sta_flags[i].name,
!!(sta->flags & sta_flags[i].flag));
+#ifdef CONFIG_MBO
+ blobmsg_add_u8(&b, "mbo", !!(sta->cell_capa));
+#endif
+
r = blobmsg_open_array(&b, "rrm");
for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
blobmsg_close_array(&b, r);
+
+ r = blobmsg_open_array(&b, "extended_capabilities");
+ /* Check if client advertises extended capabilities */
+ if (sta->ext_capability && sta->ext_capability[0] > 0) {
+ for (i = 0; i < sta->ext_capability[0]; i++) {
+ blobmsg_add_u32(&b, "", sta->ext_capability[1 + i]);
+ }
+ }
+ blobmsg_close_array(&b, r);
+
blobmsg_add_u32(&b, "aid", sta->aid);
#ifdef CONFIG_TAXONOMY
r = blobmsg_alloc_string_buffer(&b, "signature", 1024);
@@ -374,46 +347,26 @@ hostapd_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
return 0;
}
-/* Imported from iw/util.c
- * https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/tree/util.c?id=4b25ae3537af48dbf9d0abf94132e5ba01b32c18#n200
- */
-int ieee80211_frequency_to_channel(int freq)
-{
- /* see 802.11-2007 17.3.8.3.2 and Annex J */
- if (freq == 2484)
- return 14;
- /* see 802.11ax D6.1 27.3.23.2 and Annex E */
- else if (freq == 5935)
- return 2;
- else if (freq < 2484)
- return (freq - 2407) / 5;
- else if (freq >= 4910 && freq <= 4980)
- return (freq - 4000) / 5;
- else if (freq < 5950)
- return (freq - 5000) / 5;
- else if (freq <= 45000) /* DMG band lower limit */
- /* see 802.11ax D6.1 27.3.23.2 */
- return (freq - 5950) / 5;
- else if (freq >= 58320 && freq <= 70200)
- return (freq - 56160) / 2160;
- else
- return 0;
-}
-
static int
hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
- void *airtime_table, *dfs_table;
+ void *airtime_table, *dfs_table, *rrm_table, *wnm_table;
struct os_reltime now;
char ssid[SSID_MAX_LEN + 1];
char phy_name[17];
size_t ssid_len = SSID_MAX_LEN;
+ u8 channel = 0, op_class = 0;
if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
ssid_len = hapd->conf->ssid.ssid_len;
+
+ ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hostapd_get_oper_chwidth(hapd->iconf),
+ &op_class, &channel);
blob_buf_init(&b, 0);
blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
@@ -424,11 +377,31 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
blobmsg_add_string(&b, "ssid", ssid);
blobmsg_add_u32(&b, "freq", hapd->iface->freq);
- blobmsg_add_u32(&b, "channel", ieee80211_frequency_to_channel(hapd->iface->freq));
+ blobmsg_add_u32(&b, "channel", channel);
+ blobmsg_add_u32(&b, "op_class", op_class);
+ blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
+#ifdef CONFIG_IEEE80211AX
+ blobmsg_add_u32(&b, "bss_color", hapd->iface->conf->he_op.he_bss_color_disabled ? -1 :
+ hapd->iface->conf->he_op.he_bss_color);
+#else
+ blobmsg_add_u32(&b, "bss_color", -1);
+#endif
snprintf(phy_name, 17, "%s", hapd->iface->phy);
blobmsg_add_string(&b, "phy", phy_name);
+ /* RRM */
+ rrm_table = blobmsg_open_table(&b, "rrm");
+ blobmsg_add_u64(&b, "neighbor_report_tx", hapd->openwrt_stats.rrm.neighbor_report_tx);
+ blobmsg_close_table(&b, rrm_table);
+
+ /* WNM */
+ wnm_table = blobmsg_open_table(&b, "wnm");
+ blobmsg_add_u64(&b, "bss_transition_query_rx", hapd->openwrt_stats.wnm.bss_transition_query_rx);
+ blobmsg_add_u64(&b, "bss_transition_request_tx", hapd->openwrt_stats.wnm.bss_transition_request_tx);
+ blobmsg_add_u64(&b, "bss_transition_response_rx", hapd->openwrt_stats.wnm.bss_transition_response_rx);
+ blobmsg_close_table(&b, wnm_table);
+
/* Airtime */
airtime_table = blobmsg_open_table(&b, "airtime");
blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time);
@@ -671,68 +644,6 @@ enum {
__CONFIG_MAX
};
-static const struct blobmsg_policy config_add_policy[__CONFIG_MAX] = {
- [CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
- [CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING },
-};
-
-static int
-hostapd_config_add(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
-{
- struct blob_attr *tb[__CONFIG_MAX];
- struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj);
- char buf[128];
-
- blobmsg_parse(config_add_policy, __CONFIG_MAX, tb, blob_data(msg), blob_len(msg));
-
- if (!tb[CONFIG_FILE] || !tb[CONFIG_IFACE])
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- snprintf(buf, sizeof(buf), "bss_config=%s:%s",
- blobmsg_get_string(tb[CONFIG_IFACE]),
- blobmsg_get_string(tb[CONFIG_FILE]));
-
- if (hostapd_add_iface(interfaces, buf))
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- blob_buf_init(&b, 0);
- blobmsg_add_u32(&b, "pid", getpid());
- ubus_send_reply(ctx, req, b.head);
-
- return UBUS_STATUS_OK;
-}
-
-enum {
- CONFIG_REM_IFACE,
- __CONFIG_REM_MAX
-};
-
-static const struct blobmsg_policy config_remove_policy[__CONFIG_REM_MAX] = {
- [CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
-};
-
-static int
-hostapd_config_remove(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
-{
- struct blob_attr *tb[__CONFIG_REM_MAX];
- struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj);
- char buf[128];
-
- blobmsg_parse(config_remove_policy, __CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg));
-
- if (!tb[CONFIG_REM_IFACE])
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- if (hostapd_remove_iface(interfaces, blobmsg_get_string(tb[CONFIG_REM_IFACE])))
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- return UBUS_STATUS_OK;
-}
-
enum {
CSA_FREQ,
CSA_BCN_COUNT,
@@ -781,6 +692,7 @@ hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
struct hostapd_data *hapd = get_hapd_from_object(obj);
struct hostapd_config *iconf = hapd->iface->conf;
struct hostapd_freq_params *freq_params;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
struct csa_settings css = {
.freq_params = {
.ht_enabled = iconf->ieee80211n,
@@ -789,6 +701,8 @@ hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
.sec_channel_offset = iconf->secondary_channel,
}
};
+ u8 chwidth = hostapd_get_oper_chwidth(iconf);
+ u8 seg0 = 0, seg1 = 0;
int ret = UBUS_STATUS_OK;
int i;
@@ -830,6 +744,38 @@ hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
SET_CSA_SETTING(CSA_HE, freq_params.he_enabled, bool);
SET_CSA_SETTING(CSA_BLOCK_TX, block_tx, bool);
+ css.freq_params.channel = hostapd_hw_get_channel(hapd, css.freq_params.freq);
+ if (!css.freq_params.channel)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ switch (css.freq_params.bandwidth) {
+ case 160:
+ chwidth = CHANWIDTH_160MHZ;
+ break;
+ case 80:
+ chwidth = css.freq_params.center_freq2 ? CHANWIDTH_80P80MHZ : CHANWIDTH_80MHZ;
+ break;
+ default:
+ chwidth = CHANWIDTH_USE_HT;
+ break;
+ }
+
+ hostapd_set_freq_params(&css.freq_params, iconf->hw_mode,
+ css.freq_params.freq,
+ css.freq_params.channel, iconf->enable_edmg,
+ iconf->edmg_channel,
+ css.freq_params.ht_enabled,
+ css.freq_params.vht_enabled,
+ css.freq_params.he_enabled,
+ css.freq_params.eht_enabled,
+ css.freq_params.sec_channel_offset,
+ chwidth, seg0, seg1,
+ iconf->vht_capab,
+ mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL,
+ mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
+ NULL);
+
for (i = 0; i < hapd->iface->num_bss; i++) {
struct hostapd_data *bss = hapd->iface->bss[i];
@@ -931,6 +877,7 @@ hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
enum {
BSS_MGMT_EN_NEIGHBOR,
BSS_MGMT_EN_BEACON,
+ BSS_MGMT_EN_LINK_MEASUREMENT,
#ifdef CONFIG_WNM_AP
BSS_MGMT_EN_BSS_TRANSITION,
#endif
@@ -963,6 +910,14 @@ __hostapd_bss_mgmt_enable_f(struct hostapd_data *hapd, int flag)
bss->radio_measurements[0] |= (u8) flags;
return true;
+ case BSS_MGMT_EN_LINK_MEASUREMENT:
+ flags = WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+ if (bss->radio_measurements[0] & flags == flags)
+ return false;
+
+ bss->radio_measurements[0] |= (u8) flags;
+ return true;
#ifdef CONFIG_WNM_AP
case BSS_MGMT_EN_BSS_TRANSITION:
if (bss->bss_transition)
@@ -995,6 +950,7 @@ __hostapd_bss_mgmt_enable(struct hostapd_data *hapd, uint32_t flags)
static const struct blobmsg_policy bss_mgmt_enable_policy[__BSS_MGMT_EN_MAX] = {
[BSS_MGMT_EN_NEIGHBOR] = { "neighbor_report", BLOBMSG_TYPE_BOOL },
[BSS_MGMT_EN_BEACON] = { "beacon_report", BLOBMSG_TYPE_BOOL },
+ [BSS_MGMT_EN_LINK_MEASUREMENT] = { "link_measurement", BLOBMSG_TYPE_BOOL },
#ifdef CONFIG_WNM_AP
[BSS_MGMT_EN_BSS_TRANSITION] = { "bss_transition", BLOBMSG_TYPE_BOOL },
#endif
@@ -1023,6 +979,8 @@ hostapd_bss_mgmt_enable(struct ubus_context *ctx, struct ubus_object *obj,
}
__hostapd_bss_mgmt_enable(hapd, flags);
+
+ return 0;
}
@@ -1175,7 +1133,7 @@ hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
memcpy(&ssid, s, ssid.ssid_len);
}
- hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0);
+ hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0, 0);
wpabuf_free(data);
continue;
@@ -1273,62 +1231,127 @@ hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
return 0;
}
-
-#ifdef CONFIG_WNM_AP
enum {
- WNM_DISASSOC_ADDR,
- WNM_DISASSOC_DURATION,
- WNM_DISASSOC_NEIGHBORS,
- WNM_DISASSOC_ABRIDGED,
- __WNM_DISASSOC_MAX,
+ LM_REQ_ADDR,
+ LM_REQ_TX_POWER_USED,
+ LM_REQ_TX_POWER_MAX,
+ __LM_REQ_MAX,
};
-static const struct blobmsg_policy wnm_disassoc_policy[__WNM_DISASSOC_MAX] = {
- [WNM_DISASSOC_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
- [WNM_DISASSOC_DURATION] { "duration", BLOBMSG_TYPE_INT32 },
- [WNM_DISASSOC_NEIGHBORS] { "neighbors", BLOBMSG_TYPE_ARRAY },
- [WNM_DISASSOC_ABRIDGED] { "abridged", BLOBMSG_TYPE_BOOL },
+static const struct blobmsg_policy lm_req_policy[__LM_REQ_MAX] = {
+ [LM_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [LM_REQ_TX_POWER_USED] = { "tx-power-used", BLOBMSG_TYPE_INT32 },
+ [LM_REQ_TX_POWER_MAX] = { "tx-power-max", BLOBMSG_TYPE_INT32 },
};
static int
-hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *ureq, const char *method,
- struct blob_attr *msg)
+hostapd_rrm_lm_req(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
- struct blob_attr *tb[__WNM_DISASSOC_MAX];
- struct blob_attr *cur;
- struct sta_info *sta;
- int duration = 10;
- int rem;
- int nr_len = 0;
- u8 *nr = NULL;
- u8 req_mode = WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+ struct blob_attr *tb[__LM_REQ_MAX];
+ struct wpabuf *buf;
u8 addr[ETH_ALEN];
+ int ret;
+ int8_t txp_used, txp_max;
+
+ txp_used = 0;
+ txp_max = 0;
- blobmsg_parse(wnm_disassoc_policy, __WNM_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
+ blobmsg_parse(lm_req_policy, __LM_REQ_MAX, tb, blob_data(msg), blob_len(msg));
- if (!tb[WNM_DISASSOC_ADDR])
+ if (!tb[LM_REQ_ADDR])
return UBUS_STATUS_INVALID_ARGUMENT;
- if (hwaddr_aton(blobmsg_data(tb[WNM_DISASSOC_ADDR]), addr))
+ if (tb[LM_REQ_TX_POWER_USED])
+ txp_used = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_USED]);
+
+ if (tb[LM_REQ_TX_POWER_MAX])
+ txp_max = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_MAX]);
+
+ if (hwaddr_aton(blobmsg_data(tb[LM_REQ_ADDR]), addr))
return UBUS_STATUS_INVALID_ARGUMENT;
- if ((cur = tb[WNM_DISASSOC_DURATION]) != NULL)
- duration = blobmsg_get_u32(cur);
+ buf = wpabuf_alloc(5);
+ if (!buf)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, 1);
+ /* TX-Power used */
+ wpabuf_put_u8(buf, txp_used);
+ /* Max TX Power */
+ wpabuf_put_u8(buf, txp_max);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+ if (ret < 0)
+ return -ret;
+
+ return 0;
+}
+
+
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) data;
+ const u8 *pos, *end;
+ u8 token;
+
+ end = data + len;
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+
+ if (end - pos < 8)
+ return;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", mgmt->sa);
+ blobmsg_add_u16(&b, "dialog-token", token);
+ blobmsg_add_u16(&b, "rx-antenna-id", pos[4]);
+ blobmsg_add_u16(&b, "tx-antenna-id", pos[5]);
+ blobmsg_add_u16(&b, "rcpi", pos[6]);
+ blobmsg_add_u16(&b, "rsni", pos[7]);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "link-measurement-report", b.head, -1);
+}
+
+
+#ifdef CONFIG_WNM_AP
+
+static int
+hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
+ u16 disassoc_timer, u8 validity_period, u8 dialog_token,
+ struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
+{
+ struct blob_attr *cur;
+ struct sta_info *sta;
+ int nr_len = 0;
+ int rem;
+ u8 *nr = NULL;
+ u8 req_mode = 0;
+ u8 mbo[10];
+ size_t mbo_len = 0;
sta = ap_get_sta(hapd, addr);
if (!sta)
return UBUS_STATUS_NOT_FOUND;
- if (tb[WNM_DISASSOC_NEIGHBORS]) {
+ if (neighbors) {
u8 *nr_cur;
- if (blobmsg_check_array(tb[WNM_DISASSOC_NEIGHBORS],
+ if (blobmsg_check_array(neighbors,
BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
- blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
+ blobmsg_for_each_attr(cur, neighbors, rem) {
int len = strlen(blobmsg_get_string(cur));
if (len % 2)
@@ -1344,7 +1367,7 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
}
nr_cur = nr;
- blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
+ blobmsg_for_each_attr(cur, neighbors, rem) {
int len = strlen(blobmsg_get_string(cur)) / 2;
*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
@@ -1361,15 +1384,131 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
if (nr)
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
- if (tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]))
+ if (abridged)
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
- if (wnm_send_bss_tm_req(hapd, sta, req_mode, duration, duration, NULL,
- NULL, nr, nr_len, NULL, 0))
+ if (disassoc_imminent)
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+#ifdef CONFIG_MBO
+ u8 *mbo_pos = mbo;
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+#endif
+
+ if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
+ dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
return UBUS_STATUS_UNKNOWN_ERROR;
return 0;
}
+
+enum {
+ BSS_TR_ADDR,
+ BSS_TR_DA_IMMINENT,
+ BSS_TR_DA_TIMER,
+ BSS_TR_VALID_PERIOD,
+ BSS_TR_NEIGHBORS,
+ BSS_TR_ABRIDGED,
+ BSS_TR_DIALOG_TOKEN,
+#ifdef CONFIG_MBO
+ BSS_TR_MBO_REASON,
+ BSS_TR_CELL_PREF,
+ BSS_TR_REASSOC_DELAY,
+#endif
+ __BSS_TR_DISASSOC_MAX
+};
+
+static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
+ [BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
+ [BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
+ [BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
+ [BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
+#ifdef CONFIG_MBO
+ [BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
+#endif
+};
+
+static int
+hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
+ struct sta_info *sta;
+ u32 da_timer = 0;
+ u32 valid_period = 0;
+ u8 addr[ETH_ALEN];
+ u32 dialog_token = 1;
+ bool abridged;
+ bool da_imminent;
+ u8 mbo_reason;
+ u8 cell_pref;
+ u8 reassoc_delay;
+
+ blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[BSS_TR_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BSS_TR_DA_TIMER])
+ da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
+
+ if (tb[BSS_TR_VALID_PERIOD])
+ valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
+
+ if (tb[BSS_TR_DIALOG_TOKEN])
+ dialog_token = blobmsg_get_u32(tb[BSS_TR_DIALOG_TOKEN]);
+
+ da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
+ abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
+
+#ifdef CONFIG_MBO
+ if (tb[BSS_TR_MBO_REASON])
+ mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
+
+ if (tb[BSS_TR_CELL_PREF])
+ cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
+
+ if (tb[BSS_TR_REASSOC_DELAY])
+ reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
+#endif
+
+ return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
+ dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
+}
#endif
#ifdef CONFIG_AIRTIME_POLICY
@@ -1425,10 +1564,61 @@ hostapd_bss_update_airtime(struct ubus_context *ctx, struct ubus_object *obj,
}
#endif
+#ifdef CONFIG_TAXONOMY
+static const struct blobmsg_policy addr_policy[] = {
+ { "address", BLOBMSG_TYPE_STRING }
+};
+
+static bool
+hostapd_add_b64_data(const char *name, const struct wpabuf *buf)
+{
+ char *str;
+
+ if (!buf)
+ return false;
+
+ str = blobmsg_alloc_string_buffer(&b, name, B64_ENCODE_LEN(wpabuf_len(buf)));
+ b64_encode(wpabuf_head(buf), wpabuf_len(buf), str, B64_ENCODE_LEN(wpabuf_len(buf)));
+ blobmsg_add_string_buffer(&b);
+
+ return true;
+}
+
+static int
+hostapd_bss_get_sta_ies(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb;
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+
+ blobmsg_parse(addr_policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
+
+ if (!tb || hwaddr_aton(blobmsg_data(tb), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || (!sta->probe_ie_taxonomy && !sta->assoc_ie_taxonomy))
+ return UBUS_STATUS_NOT_FOUND;
+
+ blob_buf_init(&b, 0);
+ hostapd_add_b64_data("probe_ie", sta->probe_ie_taxonomy);
+ hostapd_add_b64_data("assoc_ie", sta->assoc_ie_taxonomy);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+#endif
+
static const struct ubus_method bss_methods[] = {
UBUS_METHOD_NOARG("reload", hostapd_bss_reload),
UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
+#ifdef CONFIG_TAXONOMY
+ UBUS_METHOD("get_sta_ies", hostapd_bss_get_sta_ies, addr_policy),
+#endif
UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status),
UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
#ifdef CONFIG_AIRTIME_POLICY
@@ -1452,8 +1642,9 @@ static const struct ubus_method bss_methods[] = {
UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
+ UBUS_METHOD("link_measurement_req", hostapd_rrm_lm_req, lm_req_policy),
#ifdef CONFIG_WNM_AP
- UBUS_METHOD("wnm_disassoc_imminent", hostapd_wnm_disassoc_imminent, wnm_disassoc_policy),
+ UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
#endif
};
@@ -1489,8 +1680,6 @@ void hostapd_ubus_add_bss(struct hostapd_data *hapd)
obj->n_methods = bss_object_type.n_methods;
ret = ubus_add_object(ctx, obj);
hostapd_ubus_ref_inc();
-
- hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "add");
}
void hostapd_ubus_free_bss(struct hostapd_data *hapd)
@@ -1498,10 +1687,13 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd)
struct ubus_object *obj = &hapd->ubus.obj;
char *name = (char *) obj->name;
- if (!ctx)
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED)
return;
+#endif
- hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "remove");
+ if (!ctx)
+ return;
if (obj->id) {
ubus_remove_object(ctx, obj);
@@ -1548,47 +1740,6 @@ void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vl
hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove");
}
-static const struct ubus_method daemon_methods[] = {
- UBUS_METHOD("config_add", hostapd_config_add, config_add_policy),
- UBUS_METHOD("config_remove", hostapd_config_remove, config_remove_policy),
-};
-
-static struct ubus_object_type daemon_object_type =
- UBUS_OBJECT_TYPE("hostapd", daemon_methods);
-
-void hostapd_ubus_add(struct hapd_interfaces *interfaces)
-{
- struct ubus_object *obj = &interfaces->ubus;
- int ret;
-
- if (!hostapd_ubus_init())
- return;
-
- obj->name = strdup("hostapd");
-
- obj->type = &daemon_object_type;
- obj->methods = daemon_object_type.methods;
- obj->n_methods = daemon_object_type.n_methods;
- ret = ubus_add_object(ctx, obj);
- hostapd_ubus_ref_inc();
-}
-
-void hostapd_ubus_free(struct hapd_interfaces *interfaces)
-{
- struct ubus_object *obj = &interfaces->ubus;
- char *name = (char *) obj->name;
-
- if (!ctx)
- return;
-
- if (obj->id) {
- ubus_remove_object(ctx, obj);
- hostapd_ubus_ref_dec();
- }
-
- free(name);
-}
-
struct ubus_event_req {
struct ubus_notify_request nreq;
int resp;
@@ -1709,6 +1860,20 @@ void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *
ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
}
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", sta->addr);
+ if (auth_alg)
+ blobmsg_add_string(&b, "auth-alg", auth_alg);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "sta-authorized", b.head, -1);
+}
+
void hostapd_ubus_notify_beacon_report(
struct hostapd_data *hapd, const u8 *addr, u8 token, u8 rep_mode,
struct rrm_measurement_beacon_report *rep, size_t len)
@@ -1731,6 +1896,7 @@ void hostapd_ubus_notify_beacon_report(
blobmsg_add_macaddr(&b, "bssid", rep->bssid);
blobmsg_add_u16(&b, "antenna-id", rep->antenna_id);
blobmsg_add_u16(&b, "parent-tsf", rep->parent_tsf);
+ blobmsg_add_u16(&b, "rep-mode", rep_mode);
ubus_notify(ctx, &hapd->ubus.obj, "beacon-report", b.head, -1);
}
@@ -1741,7 +1907,7 @@ void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequen
struct hostapd_data *hapd;
int i;
- if (!hapd->ubus.obj.has_subscribers)
+ if (!ctx)
return;
blob_buf_init(&b, 0);
@@ -1755,3 +1921,85 @@ void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequen
ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
}
}
+
+#ifdef CONFIG_WNM_AP
+static void hostapd_ubus_notify_bss_transition_add_candidate_list(
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+ char *cl_str;
+ int i;
+
+ if (candidate_list_len == 0)
+ return;
+
+ cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
+ for (i = 0; i < candidate_list_len; i++)
+ snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
+ blobmsg_add_string_buffer(&b);
+
+}
+#endif
+
+void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+ u16 i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u8(&b, "dialog-token", dialog_token);
+ blobmsg_add_u8(&b, "status-code", status_code);
+ blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
+ if (target_bssid)
+ blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
+
+ hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
+#endif
+}
+
+int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+ struct ubus_event_req ureq = {};
+ char *cl_str;
+ u16 i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return 0;
+
+ if (!addr)
+ return 0;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u8(&b, "dialog-token", dialog_token);
+ blobmsg_add_u8(&b, "reason", reason);
+ hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+ if (!hapd->ubus.notify_response) {
+ ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, -1);
+ return 0;
+ }
+
+ if (ubus_notify_async(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, &ureq.nreq))
+ return 0;
+
+ ureq.nreq.status_cb = ubus_event_cb;
+ ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+ return ureq.resp;
+#endif
+}
diff --git a/package/network/services/hostapd/src/src/ap/ubus.h b/package/network/services/hostapd/src/src/ap/ubus.h
index acdac743603..b0f7c44ab5f 100644
--- a/package/network/services/hostapd/src/src/ap/ubus.h
+++ b/package/network/services/hostapd/src/src/ap/ubus.h
@@ -47,6 +47,7 @@ void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len);
void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac);
void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
const u8 *addr, u8 token, u8 rep_mode,
@@ -55,8 +56,17 @@ void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
int chan_width, int cf1, int cf2);
+void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_add(struct hapd_interfaces *interfaces);
void hostapd_ubus_free(struct hapd_interfaces *interfaces);
+int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg);
#else
@@ -91,6 +101,10 @@ static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct ho
return 0;
}
+static inline void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+}
+
static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac)
{
}
@@ -107,6 +121,13 @@ static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *ifac
{
}
+static inline void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+}
+
static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
{
}
@@ -114,6 +135,20 @@ static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
{
}
+
+static inline int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+ return 0;
+}
+
+static inline void
+hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg)
+{
+}
+
#endif
#endif
diff --git a/package/network/services/hostapd/src/src/ap/ucode.c b/package/network/services/hostapd/src/src/ap/ucode.c
new file mode 100644
index 00000000000..16d1b515360
--- /dev/null
+++ b/package/network/services/hostapd/src/src/ap/ucode.c
@@ -0,0 +1,813 @@
+#include <sys/un.h>
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "hostapd.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "ap_drv_ops.h"
+#include "dfs.h"
+#include "acs.h"
+#include <libubox/uloop.h>
+
+static uc_resource_type_t *global_type, *bss_type, *iface_type;
+static struct hapd_interfaces *interfaces;
+static uc_value_t *global, *bss_registry, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (hapd->ucode.idx)
+ return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
+
+ val = uc_resource_new(bss_type, hapd);
+ hapd->ucode.idx = wpa_ucode_registry_add(bss_registry, val);
+
+ return val;
+}
+
+static uc_value_t *
+hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
+{
+ uc_value_t *val;
+
+ if (hapd->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
+
+ val = uc_resource_new(iface_type, hapd);
+ hapd->ucode.idx = wpa_ucode_registry_add(iface_registry, val);
+
+ return val;
+}
+
+static void
+hostapd_ucode_update_bss_list(struct hostapd_iface *iface, uc_value_t *if_bss, uc_value_t *bss)
+{
+ uc_value_t *list;
+ int i;
+
+ list = ucv_array_new(vm);
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
+
+ ucv_array_set(list, i, ucv_get(ucv_string_new(hapd->conf->iface)));
+ ucv_object_add(bss, hapd->conf->iface, ucv_get(val));
+ }
+ ucv_object_add(if_bss, iface->phy, ucv_get(list));
+}
+
+static void
+hostapd_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ uc_value_t *if_bss = ucv_array_new(vm);
+ uc_value_t *bss = ucv_object_new(vm);
+ int i;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+
+ ucv_object_add(ifs, iface->phy, ucv_get(hostapd_ucode_iface_get_uval(iface)));
+ hostapd_ucode_update_bss_list(iface, if_bss, bss);
+ }
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_object_add(ucv_prototype_get(global), "interface_bss", ucv_get(if_bss));
+ ucv_object_add(ucv_prototype_get(global), "bss", ucv_get(bss));
+ ucv_gc(vm);
+}
+
+static uc_value_t *
+uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *iface = uc_fn_arg(0);
+ int ret;
+
+ if (ucv_type(iface) != UC_STRING)
+ return ucv_int64_new(-1);
+
+ ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
+ hostapd_ucode_update_interfaces();
+
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *iface = uc_fn_arg(0);
+
+ if (ucv_type(iface) != UC_STRING)
+ return NULL;
+
+ hostapd_remove_iface(interfaces, ucv_string_get(iface));
+ hostapd_ucode_update_interfaces();
+
+ return NULL;
+}
+
+static struct hostapd_vlan *
+bss_conf_find_vlan(struct hostapd_bss_config *bss, int id)
+{
+ struct hostapd_vlan *vlan;
+
+ for (vlan = bss->vlan; vlan; vlan = vlan->next)
+ if (vlan->vlan_id == id)
+ return vlan;
+
+ return NULL;
+}
+
+static int
+bss_conf_rename_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+ const char *ifname)
+{
+ if (!strcmp(ifname, vlan->ifname))
+ return 0;
+
+ hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, vlan->ifname, ifname);
+ os_strlcpy(vlan->ifname, ifname, sizeof(vlan->ifname));
+
+ return 0;
+}
+
+static int
+bss_reload_vlans(struct hostapd_data *hapd, struct hostapd_bss_config *bss)
+{
+ struct hostapd_bss_config *old_bss = hapd->conf;
+ struct hostapd_vlan *vlan, *vlan_new, *wildcard;
+ char ifname[IFNAMSIZ + 1], vlan_ifname[IFNAMSIZ + 1], *pos;
+ int ret;
+
+ vlan = bss_conf_find_vlan(old_bss, VLAN_ID_WILDCARD);
+ wildcard = bss_conf_find_vlan(bss, VLAN_ID_WILDCARD);
+ if (!!vlan != !!wildcard)
+ return -1;
+
+ if (vlan && wildcard && strcmp(vlan->ifname, wildcard->ifname) != 0)
+ strcpy(vlan->ifname, wildcard->ifname);
+ else
+ wildcard = NULL;
+
+ for (vlan = bss->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == VLAN_ID_WILDCARD ||
+ vlan->dynamic_vlan > 0)
+ continue;
+
+ if (!bss_conf_find_vlan(old_bss, vlan->vlan_id))
+ return -1;
+ }
+
+ for (vlan = old_bss->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ continue;
+
+ if (vlan->dynamic_vlan == 0) {
+ vlan_new = bss_conf_find_vlan(bss, vlan->vlan_id);
+ if (!vlan_new)
+ return -1;
+
+ if (bss_conf_rename_vlan(hapd, vlan, vlan_new->ifname))
+ return -1;
+
+ continue;
+ }
+
+ if (!wildcard)
+ continue;
+
+ os_strlcpy(ifname, wildcard->ifname, sizeof(ifname));
+ pos = os_strchr(ifname, '#');
+ if (!pos)
+ return -1;
+
+ *pos++ = '\0';
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s%d%s",
+ ifname, vlan->vlan_id, pos);
+ if (os_snprintf_error(sizeof(vlan_ifname), ret))
+ return -1;
+
+ if (bss_conf_rename_vlan(hapd, vlan, vlan_ifname))
+ return -1;
+ }
+
+ return 0;
+}
+
+static uc_value_t *
+uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ struct hostapd_bss_config *old_bss;
+ struct hostapd_iface *iface;
+ struct hostapd_config *conf;
+ uc_value_t *file = uc_fn_arg(0);
+ uc_value_t *index = uc_fn_arg(1);
+ uc_value_t *files_only = uc_fn_arg(2);
+ unsigned int i, idx = 0;
+ int ret = -1;
+
+ if (!hapd || ucv_type(file) != UC_STRING)
+ goto out;
+
+ if (ucv_type(index) == UC_INTEGER)
+ idx = ucv_int64_get(index);
+
+ iface = hapd->iface;
+ conf = interfaces->config_read_cb(ucv_string_get(file));
+ if (!conf)
+ goto out;
+
+ if (idx > conf->num_bss || !conf->bss[idx])
+ goto free;
+
+ if (ucv_boolean_get(files_only)) {
+ struct hostapd_bss_config *bss = conf->bss[idx];
+ struct hostapd_bss_config *old_bss = hapd->conf;
+
+#define swap_field(name) \
+ do { \
+ void *ptr = old_bss->name; \
+ old_bss->name = bss->name; \
+ bss->name = ptr; \
+ } while (0)
+
+ swap_field(ssid.wpa_psk_file);
+ ret = bss_reload_vlans(hapd, bss);
+ goto done;
+ }
+
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_drv_stop_ap(hapd);
+ hostapd_free_hapd_data(hapd);
+
+ old_bss = hapd->conf;
+ for (i = 0; i < iface->conf->num_bss; i++)
+ if (iface->conf->bss[i] == hapd->conf)
+ iface->conf->bss[i] = conf->bss[idx];
+ hapd->conf = conf->bss[idx];
+ conf->bss[idx] = old_bss;
+
+ hostapd_setup_bss(hapd, hapd == iface->bss[0], true);
+ hostapd_ucode_update_interfaces();
+
+done:
+ ret = 0;
+free:
+ hostapd_config_free(conf);
+out:
+ return ucv_int64_new(ret);
+}
+
+static void
+hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
+ struct hostapd_bss_config *conf)
+{
+ int i;
+
+ for (i = 0; i < iconf->num_bss; i++)
+ if (iconf->bss[i] == conf)
+ break;
+
+ if (i == iconf->num_bss)
+ return;
+
+ for (i++; i < iconf->num_bss; i++)
+ iconf->bss[i - 1] = iconf->bss[i];
+ iconf->num_bss--;
+}
+
+
+static uc_value_t *
+uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ struct hostapd_iface *iface;
+ int i, idx;
+
+ if (!hapd)
+ return NULL;
+
+ iface = hapd->iface;
+ if (iface->num_bss == 1) {
+ wpa_printf(MSG_ERROR, "trying to delete last bss of an iface: %s\n", hapd->conf->iface);
+ return NULL;
+ }
+
+ for (idx = 0; idx < iface->num_bss; idx++)
+ if (iface->bss[idx] == hapd)
+ break;
+
+ if (idx == iface->num_bss)
+ return NULL;
+
+ for (i = idx + 1; i < iface->num_bss; i++)
+ iface->bss[i - 1] = iface->bss[i];
+
+ iface->num_bss--;
+
+ iface->bss[0]->interface_added = 0;
+ hostapd_drv_set_first_bss(iface->bss[0]);
+ hapd->interface_added = 1;
+
+ hostapd_drv_stop_ap(hapd);
+ hostapd_bss_deinit(hapd);
+ hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
+ hostapd_config_free_bss(hapd->conf);
+ os_free(hapd);
+
+ hostapd_ucode_update_interfaces();
+ ucv_gc(vm);
+
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ struct hostapd_bss_config *bss;
+ struct hostapd_config *conf;
+ struct hostapd_data *hapd;
+ uc_value_t *file = uc_fn_arg(0);
+ uc_value_t *index = uc_fn_arg(1);
+ unsigned int idx = 0;
+ uc_value_t *ret = NULL;
+
+ if (!iface || ucv_type(file) != UC_STRING)
+ goto out;
+
+ if (ucv_type(index) == UC_INTEGER)
+ idx = ucv_int64_get(index);
+
+ conf = interfaces->config_read_cb(ucv_string_get(file));
+ if (!conf || idx > conf->num_bss || !conf->bss[idx])
+ goto out;
+
+ bss = conf->bss[idx];
+ hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+ if (!hapd)
+ goto out;
+
+ hapd->driver = iface->bss[0]->driver;
+ hapd->drv_priv = iface->bss[0]->drv_priv;
+ if (interfaces->ctrl_iface_init &&
+ interfaces->ctrl_iface_init(hapd) < 0)
+ goto free_hapd;
+
+ if (iface->state == HAPD_IFACE_ENABLED &&
+ hostapd_setup_bss(hapd, -1, true))
+ goto deinit_ctrl;
+
+ iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+ sizeof(*iface->bss));
+ iface->bss[iface->num_bss++] = hapd;
+
+ iface->conf->bss = os_realloc_array(iface->conf->bss,
+ iface->conf->num_bss + 1,
+ sizeof(*iface->conf->bss));
+ iface->conf->bss[iface->conf->num_bss] = bss;
+ conf->bss[idx] = NULL;
+ ret = hostapd_ucode_bss_get_uval(hapd);
+ hostapd_ucode_update_interfaces();
+ goto out;
+
+deinit_ctrl:
+ if (interfaces->ctrl_iface_deinit)
+ interfaces->ctrl_iface_deinit(hapd);
+free_hapd:
+ hostapd_free_hapd_data(hapd);
+ os_free(hapd);
+out:
+ hostapd_config_free(conf);
+ return ret;
+}
+
+static uc_value_t *
+uc_hostapd_iface_set_bss_order(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ uc_value_t *bss_list = uc_fn_arg(0);
+ struct hostapd_data **new_bss;
+ struct hostapd_bss_config **new_conf;
+
+ if (!iface)
+ return NULL;
+
+ if (ucv_type(bss_list) != UC_ARRAY ||
+ ucv_array_length(bss_list) != iface->num_bss)
+ return NULL;
+
+ new_bss = calloc(iface->num_bss, sizeof(*new_bss));
+ new_conf = calloc(iface->num_bss, sizeof(*new_conf));
+ for (size_t i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *bss;
+
+ bss = ucv_resource_data(ucv_array_get(bss_list, i), "hostapd.bss");
+ if (bss->iface != iface)
+ goto free;
+
+ for (size_t k = 0; k < i; k++)
+ if (new_bss[k] == bss)
+ goto free;
+
+ new_bss[i] = bss;
+ new_conf[i] = bss->conf;
+ }
+
+ new_bss[0]->interface_added = 0;
+ for (size_t i = 1; i < iface->num_bss; i++)
+ new_bss[i]->interface_added = 1;
+
+ free(iface->bss);
+ iface->bss = new_bss;
+
+ free(iface->conf->bss);
+ iface->conf->bss = new_conf;
+ iface->conf->num_bss = iface->num_bss;
+ hostapd_drv_set_first_bss(iface->bss[0]);
+
+ return ucv_boolean_new(true);
+
+free:
+ free(new_bss);
+ free(new_conf);
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ uc_value_t *arg = uc_fn_arg(0);
+ struct sockaddr_storage from = {};
+ static char reply[4096];
+ int reply_len;
+
+ if (!hapd || !interfaces->ctrl_iface_recv ||
+ ucv_type(arg) != UC_STRING)
+ return NULL;
+
+ reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
+ reply, sizeof(reply),
+ &from, sizeof(from));
+ if (reply_len < 0)
+ return NULL;
+
+ if (reply_len && reply[reply_len - 1] == '\n')
+ reply_len--;
+
+ return ucv_string_new_length(reply, reply_len);
+}
+
+static void
+uc_hostapd_disable_iface(struct hostapd_iface *iface)
+{
+ switch (iface->state) {
+ case HAPD_IFACE_DISABLED:
+ break;
+#ifdef CONFIG_ACS
+ case HAPD_IFACE_ACS:
+ acs_cleanup(iface);
+ iface->scan_cb = NULL;
+ /* fallthrough */
+#endif
+ default:
+ hostapd_disable_iface(iface);
+ break;
+ }
+}
+
+static uc_value_t *
+uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ int i;
+
+ if (!iface)
+ return NULL;
+
+ if (iface->state != HAPD_IFACE_ENABLED)
+ uc_hostapd_disable_iface(iface);
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+
+ hostapd_drv_stop_ap(hapd);
+ hapd->beacon_set_done = 0;
+ }
+
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ uc_value_t *info = uc_fn_arg(0);
+ struct hostapd_config *conf;
+ bool changed = false;
+ uint64_t intval;
+ int i;
+
+ if (!iface)
+ return NULL;
+
+ if (!info) {
+ iface->freq = 0;
+ goto out;
+ }
+
+ if (ucv_type(info) != UC_OBJECT)
+ return NULL;
+
+#define UPDATE_VAL(field, name) \
+ if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \
+ !errno && intval != conf->field) do { \
+ conf->field = intval; \
+ changed = true; \
+ } while(0)
+
+ conf = iface->conf;
+ UPDATE_VAL(op_class, "op_class");
+ UPDATE_VAL(hw_mode, "hw_mode");
+ UPDATE_VAL(channel, "channel");
+ UPDATE_VAL(secondary_channel, "sec_channel");
+ if (!changed &&
+ (iface->bss[0]->beacon_set_done ||
+ iface->state == HAPD_IFACE_DFS))
+ return ucv_boolean_new(true);
+
+ intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL));
+ if (!errno)
+ hostapd_set_oper_centr_freq_seg0_idx(conf, intval);
+
+ intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL));
+ if (!errno)
+ hostapd_set_oper_centr_freq_seg1_idx(conf, intval);
+
+ intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
+ if (!errno)
+ hostapd_set_oper_chwidth(conf, intval);
+
+ intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL));
+ if (!errno)
+ iface->freq = intval;
+ else
+ iface->freq = 0;
+ conf->acs = 0;
+
+out:
+ switch (iface->state) {
+ case HAPD_IFACE_ENABLED:
+ if (!hostapd_is_dfs_required(iface) ||
+ hostapd_is_dfs_chan_available(iface))
+ break;
+ wpa_printf(MSG_INFO, "DFS CAC required on new channel, restart interface");
+ /* fallthrough */
+ default:
+ uc_hostapd_disable_iface(iface);
+ break;
+ }
+
+ if (conf->channel && !iface->freq)
+ iface->freq = hostapd_hw_get_freq(iface->bss[0], conf->channel);
+
+ if (iface->state != HAPD_IFACE_ENABLED) {
+ hostapd_enable_iface(iface);
+ return ucv_boolean_new(true);
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ int ret;
+
+ hapd->conf->start_disabled = 0;
+ hostapd_set_freq(hapd, conf->hw_mode, iface->freq,
+ conf->channel,
+ conf->enable_edmg,
+ conf->edmg_channel,
+ conf->ieee80211n,
+ conf->ieee80211ac,
+ conf->ieee80211ax,
+ conf->ieee80211be,
+ conf->secondary_channel,
+ hostapd_get_oper_chwidth(conf),
+ hostapd_get_oper_centr_freq_seg0_idx(conf),
+ hostapd_get_oper_centr_freq_seg1_idx(conf));
+
+ ieee802_11_set_beacon(hapd);
+ }
+
+ return ucv_boolean_new(true);
+}
+
+static uc_value_t *
+uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ uc_value_t *info = uc_fn_arg(0);
+ struct hostapd_config *conf;
+ struct csa_settings csa = {};
+ uint64_t intval;
+ int i, ret = 0;
+
+ if (!iface || ucv_type(info) != UC_OBJECT)
+ return NULL;
+
+ conf = iface->conf;
+ if ((intval = ucv_int64_get(ucv_object_get(info, "csa_count", NULL))) && !errno)
+ csa.cs_count = intval;
+ if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
+ csa.freq_params.sec_channel_offset = intval;
+
+ csa.freq_params.ht_enabled = conf->ieee80211n;
+ csa.freq_params.vht_enabled = conf->ieee80211ac;
+ csa.freq_params.he_enabled = conf->ieee80211ax;
+#ifdef CONFIG_IEEE80211BE
+ csa.freq_params.eht_enabled = conf->ieee80211be;
+#endif
+ intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
+ if (errno)
+ intval = hostapd_get_oper_chwidth(conf);
+ if (intval)
+ csa.freq_params.bandwidth = 40 << intval;
+ else
+ csa.freq_params.bandwidth = csa.freq_params.sec_channel_offset ? 40 : 20;
+
+ if ((intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL))) && !errno)
+ csa.freq_params.freq = intval;
+ if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq1", NULL))) && !errno)
+ csa.freq_params.center_freq1 = intval;
+ if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq2", NULL))) && !errno)
+ csa.freq_params.center_freq2 = intval;
+
+ for (i = 0; i < iface->num_bss; i++)
+ ret = hostapd_switch_channel(iface->bss[i], &csa);
+
+ return ucv_boolean_new(!ret);
+}
+
+static uc_value_t *
+uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ uc_value_t *ifname_arg = uc_fn_arg(0);
+ char prev_ifname[IFNAMSIZ + 1];
+ struct sta_info *sta;
+ const char *ifname;
+ int ret;
+
+ if (!hapd || ucv_type(ifname_arg) != UC_STRING)
+ return NULL;
+
+ os_strlcpy(prev_ifname, hapd->conf->iface, sizeof(prev_ifname));
+ ifname = ucv_string_get(ifname_arg);
+
+ hostapd_ubus_free_bss(hapd);
+ if (interfaces->ctrl_iface_deinit)
+ interfaces->ctrl_iface_deinit(hapd);
+
+ ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname);
+ if (ret)
+ goto out;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ char cur_name[IFNAMSIZ + 1], new_name[IFNAMSIZ + 1];
+
+ if (!(sta->flags & WLAN_STA_WDS) || sta->pending_wds_enable)
+ continue;
+
+ snprintf(cur_name, sizeof(cur_name), "%s.sta%d", prev_ifname, sta->aid);
+ snprintf(new_name, sizeof(new_name), "%s.sta%d", ifname, sta->aid);
+ hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, cur_name, new_name);
+ }
+
+ if (!strncmp(hapd->conf->ssid.vlan, hapd->conf->iface, sizeof(hapd->conf->ssid.vlan)))
+ os_strlcpy(hapd->conf->ssid.vlan, ifname, sizeof(hapd->conf->ssid.vlan));
+ os_strlcpy(hapd->conf->iface, ifname, sizeof(hapd->conf->iface));
+ hostapd_ubus_add_bss(hapd);
+
+ hostapd_ucode_update_interfaces();
+out:
+ if (interfaces->ctrl_iface_init)
+ interfaces->ctrl_iface_init(hapd);
+
+ return ret ? NULL : ucv_boolean_new(true);
+}
+
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "sha1", uc_wpa_sha1 },
+ { "freq_info", uc_wpa_freq_info },
+ { "add_iface", uc_hostapd_add_iface },
+ { "remove_iface", uc_hostapd_remove_iface },
+ { "udebug_set", uc_wpa_udebug_set },
+ };
+ static const uc_function_list_t bss_fns[] = {
+ { "ctrl", uc_hostapd_bss_ctrl },
+ { "set_config", uc_hostapd_bss_set_config },
+ { "rename", uc_hostapd_bss_rename },
+ { "delete", uc_hostapd_bss_delete },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ { "set_bss_order", uc_hostapd_iface_set_bss_order },
+ { "add_bss", uc_hostapd_iface_add_bss },
+ { "stop", uc_hostapd_iface_stop },
+ { "start", uc_hostapd_iface_start },
+ { "switch_channel", uc_hostapd_iface_switch_channel },
+ };
+ uc_value_t *data, *proto;
+
+ interfaces = ifaces;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
+ bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
+ iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+ bss_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("hostapd", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
+ goto free_vm;
+ ucv_gc(vm);
+
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void hostapd_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
+
+void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+ wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
+}
+
+void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("bss_add"))
+ return;
+
+ val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("bss_reload"))
+ return;
+
+ val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
+ if (!val)
+ return;
+
+ hapd->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("bss_remove"))
+ return;
+
+ uc_value_push(ucv_string_new(hapd->conf->iface));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
diff --git a/package/network/services/hostapd/src/src/ap/ucode.h b/package/network/services/hostapd/src/src/ap/ucode.h
new file mode 100644
index 00000000000..d00b787169d
--- /dev/null
+++ b/package/network/services/hostapd/src/src/ap/ucode.h
@@ -0,0 +1,54 @@
+#ifndef __HOSTAPD_AP_UCODE_H
+#define __HOSTAPD_AP_UCODE_H
+
+#include "utils/ucode.h"
+
+struct hostapd_data;
+
+struct hostapd_ucode_bss {
+#ifdef UCODE_SUPPORT
+ int idx;
+#endif
+};
+
+struct hostapd_ucode_iface {
+#ifdef UCODE_SUPPORT
+ int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces);
+
+void hostapd_ucode_free(void);
+void hostapd_ucode_free_iface(struct hostapd_iface *iface);
+void hostapd_ucode_add_bss(struct hostapd_data *hapd);
+void hostapd_ucode_free_bss(struct hostapd_data *hapd);
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd);
+
+#else
+
+static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+ return -EINVAL;
+}
+static inline void hostapd_ucode_free(void)
+{
+}
+static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+}
+static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd)
+{
+}
+static inline void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+}
+static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+}
+
+#endif
+
+#endif
diff --git a/package/network/services/hostapd/src/src/utils/build_features.h b/package/network/services/hostapd/src/src/utils/build_features.h
index 3ab5246c789..553769ecebc 100644
--- a/package/network/services/hostapd/src/src/utils/build_features.h
+++ b/package/network/services/hostapd/src/src/utils/build_features.h
@@ -7,10 +7,6 @@ static inline int has_feature(const char *feat)
if (!strcmp(feat, "eap"))
return 1;
#endif
-#ifdef CONFIG_IEEE80211N
- if (!strcmp(feat, "11n"))
- return 1;
-#endif
#ifdef CONFIG_IEEE80211AC
if (!strcmp(feat, "11ac"))
return 1;
@@ -51,6 +47,18 @@ static inline int has_feature(const char *feat)
if (!strcmp(feat, "wps"))
return 1;
#endif
+#ifdef CONFIG_FILS
+ if (!strcmp(feat, "fils"))
+ return 1;
+#endif
+#ifdef CONFIG_OCV
+ if (!strcmp(feat, "ocv"))
+ return 1;
+#endif
+#ifdef CONFIG_MESH
+ if (!strcmp(feat, "mesh"))
+ return 1;
+#endif
return 0;
}
diff --git a/package/network/services/hostapd/src/src/utils/ucode.c b/package/network/services/hostapd/src/src/utils/ucode.c
new file mode 100644
index 00000000000..29c753c3269
--- /dev/null
+++ b/package/network/services/hostapd/src/src/utils/ucode.c
@@ -0,0 +1,502 @@
+#include <unistd.h>
+#include "ucode.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "common/ieee802_11_common.h"
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <linux/nl80211.h>
+#include <libubox/uloop.h>
+#include <ucode/compiler.h>
+#include <udebug.h>
+
+static uc_value_t *registry;
+static uc_vm_t vm;
+static struct uloop_timeout gc_timer;
+static struct udebug ud;
+static struct udebug_buf ud_log, ud_nl[3];
+static const struct udebug_buf_meta meta_log = {
+ .name = "wpa_log",
+ .format = UDEBUG_FORMAT_STRING,
+};
+static const struct udebug_buf_meta meta_nl_ll = {
+ .name = "wpa_nl_ctrl",
+ .format = UDEBUG_FORMAT_PACKET,
+ .sub_format = UDEBUG_DLT_NETLINK,
+};
+static const struct udebug_buf_meta meta_nl_tx = {
+ .name = "wpa_nl_tx",
+ .format = UDEBUG_FORMAT_PACKET,
+ .sub_format = UDEBUG_DLT_NETLINK,
+};
+#define UDEBUG_FLAG_RX_FRAME (1ULL << 0)
+static const struct udebug_buf_flag rx_flags[] = {
+ { "rx_frame", UDEBUG_FLAG_RX_FRAME },
+};
+static const struct udebug_buf_meta meta_nl_rx = {
+ .name = "wpa_nl_rx",
+ .format = UDEBUG_FORMAT_PACKET,
+ .sub_format = UDEBUG_DLT_NETLINK,
+ .flags = rx_flags,
+ .n_flags = ARRAY_SIZE(rx_flags),
+};
+static struct udebug_ubus_ring udebug_rings[] = {
+ {
+ .buf = &ud_log,
+ .meta = &meta_log,
+ .default_entries = 1024,
+ .default_size = 64 * 1024
+ },
+ {
+ .buf = &ud_nl[0],
+ .meta = &meta_nl_rx,
+ .default_entries = 1024,
+ .default_size = 256 * 1024,
+ },
+ {
+ .buf = &ud_nl[1],
+ .meta = &meta_nl_tx,
+ .default_entries = 1024,
+ .default_size = 64 * 1024,
+ },
+ {
+ .buf = &ud_nl[2],
+ .meta = &meta_nl_ll,
+ .default_entries = 1024,
+ .default_size = 32 * 1024,
+ }
+};
+char *udebug_service;
+struct udebug_ubus ud_ubus;
+
+static void uc_gc_timer(struct uloop_timeout *timeout)
+{
+ ucv_gc(&vm);
+}
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *level = uc_fn_arg(0);
+ uc_value_t *ret, **args;
+ uc_cfn_ptr_t _sprintf;
+ int l = MSG_INFO;
+ int i, start = 0;
+
+ _sprintf = uc_stdlib_function("sprintf");
+ if (!sprintf)
+ return NULL;
+
+ if (ucv_type(level) == UC_INTEGER) {
+ l = ucv_int64_get(level);
+ start++;
+ }
+
+ if (nargs <= start)
+ return NULL;
+
+ ret = _sprintf(vm, nargs - start);
+ if (ucv_type(ret) != UC_STRING)
+ return NULL;
+
+ wpa_printf(l, "%s", ucv_string_get(ret));
+ ucv_put(ret);
+
+ return NULL;
+}
+
+uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *freq = uc_fn_arg(0);
+ uc_value_t *sec = uc_fn_arg(1);
+ int width = ucv_uint64_get(uc_fn_arg(2));
+ int freq_val, center_idx, center_ofs;
+ enum oper_chan_width chanwidth;
+ enum hostapd_hw_mode hw_mode;
+ u8 op_class, channel, tmp_channel;
+ const char *modestr;
+ int sec_channel = 0;
+ uc_value_t *ret;
+
+ if (ucv_type(freq) != UC_INTEGER)
+ return NULL;
+
+ freq_val = ucv_int64_get(freq);
+ if (ucv_type(sec) == UC_INTEGER)
+ sec_channel = ucv_int64_get(sec);
+ else if (sec)
+ return NULL;
+ else if (freq_val > 4000)
+ sec_channel = (freq_val / 20) & 1 ? 1 : -1;
+ else
+ sec_channel = freq_val < 2442 ? 1 : -1;
+
+ if (sec_channel != -1 && sec_channel != 1 && sec_channel != 0)
+ return NULL;
+
+ switch (width) {
+ case 0:
+ chanwidth = CONF_OPER_CHWIDTH_USE_HT;
+ break;
+ case 1:
+ chanwidth = CONF_OPER_CHWIDTH_80MHZ;
+ break;
+ case 2:
+ chanwidth = CONF_OPER_CHWIDTH_160MHZ;
+ break;
+ default:
+ return NULL;
+ }
+
+ hw_mode = ieee80211_freq_to_channel_ext(freq_val, sec_channel,
+ chanwidth, &op_class, &channel);
+ switch (hw_mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ modestr = "b";
+ break;
+ case HOSTAPD_MODE_IEEE80211G:
+ modestr = "g";
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ modestr = "a";
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ modestr = "ad";
+ break;
+ default:
+ return NULL;
+ }
+
+ ret = ucv_object_new(vm);
+ ucv_object_add(ret, "op_class", ucv_int64_new(op_class));
+ ucv_object_add(ret, "channel", ucv_int64_new(channel));
+ ucv_object_add(ret, "hw_mode", ucv_int64_new(hw_mode));
+ ucv_object_add(ret, "hw_mode_str", ucv_get(ucv_string_new(modestr)));
+ ucv_object_add(ret, "sec_channel", ucv_int64_new(sec_channel));
+ ucv_object_add(ret, "frequency", ucv_int64_new(freq_val));
+
+ if (!sec_channel)
+ return ret;
+
+ if (freq_val >= 5900)
+ center_ofs = 0;
+ else if (freq_val >= 5745)
+ center_ofs = 20;
+ else
+ center_ofs = 35;
+ tmp_channel = channel - center_ofs;
+ tmp_channel &= ~((8 << width) - 1);
+ center_idx = tmp_channel + center_ofs + (4 << width) - 1;
+
+ if (freq_val < 3000)
+ ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(0));
+ else
+ ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(center_idx));
+ center_idx = (center_idx - channel) * 5 + freq_val;
+ ucv_object_add(ret, "center_freq1", ucv_int64_new(center_idx));
+
+out:
+ return ret;
+}
+
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs)
+{
+ return ucv_int64_new(getpid());
+}
+
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs)
+{
+ u8 hash[SHA1_MAC_LEN];
+ char hash_hex[2 * ARRAY_SIZE(hash) + 1];
+ uc_value_t *val;
+ size_t *lens;
+ const u8 **args;
+ int i;
+
+ if (!nargs)
+ return NULL;
+
+ args = alloca(nargs * sizeof(*args));
+ lens = alloca(nargs * sizeof(*lens));
+ for (i = 0; i < nargs; i++) {
+ val = uc_fn_arg(i);
+ if (ucv_type(val) != UC_STRING)
+ return NULL;
+
+ args[i] = ucv_string_get(val);
+ lens[i] = ucv_string_length(val);
+ }
+
+ if (sha1_vector(nargs, args, lens, hash))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(hash); i++)
+ sprintf(hash_hex + 2 * i, "%02x", hash[i]);
+
+ return ucv_string_new_length(hash_hex, 2 * ARRAY_SIZE(hash));
+}
+
+uc_vm_t *wpa_ucode_create_vm(void)
+{
+ static uc_parse_config_t config = {
+ .strict_declarations = true,
+ .lstrip_blocks = true,
+ .trim_blocks = true,
+ .raw_mode = true
+ };
+
+ uc_search_path_init(&config.module_search_path);
+ uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.so");
+ uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.uc");
+
+ uc_vm_init(&vm, &config);
+
+ uc_stdlib_load(uc_vm_scope_get(&vm));
+ eloop_add_uloop();
+ gc_timer.cb = uc_gc_timer;
+
+ return &vm;
+}
+
+int wpa_ucode_run(const char *script)
+{
+ uc_source_t *source;
+ uc_program_t *prog;
+ uc_value_t *ops;
+ char *err;
+ int ret;
+
+ source = uc_source_new_file(script);
+ if (!source)
+ return -1;
+
+ prog = uc_compile(vm.config, source, &err);
+ uc_source_put(source);
+ if (!prog) {
+ wpa_printf(MSG_ERROR, "Error loading ucode: %s\n", err);
+ return -1;
+ }
+
+ ret = uc_vm_execute(&vm, prog, &ops);
+ uc_program_put(prog);
+ if (ret || !ops)
+ return -1;
+
+ registry = ucv_array_new(&vm);
+ uc_vm_registry_set(&vm, "hostap.registry", registry);
+ ucv_array_set(registry, 0, ucv_get(ops));
+
+ return 0;
+}
+
+int wpa_ucode_call_prepare(const char *fname)
+{
+ uc_value_t *obj, *func;
+
+ if (!registry)
+ return -1;
+
+ obj = ucv_array_get(registry, 0);
+ if (!obj)
+ return -1;
+
+ func = ucv_object_get(obj, fname, NULL);
+ if (!ucv_is_callable(func))
+ return -1;
+
+ uc_vm_stack_push(&vm, ucv_get(obj));
+ uc_vm_stack_push(&vm, ucv_get(func));
+
+ return 0;
+}
+
+static void udebug_printf_hook(int level, const char *fmt, va_list ap)
+{
+ udebug_entry_init(&ud_log);
+ udebug_entry_vprintf(&ud_log, fmt, ap);
+ udebug_entry_add(&ud_log);
+}
+
+static void udebug_hexdump_hook(int level, const char *title,
+ const void *data, size_t len)
+{
+ char *buf;
+
+ udebug_entry_init(&ud_log);
+ udebug_entry_printf(&ud_log, "%s - hexdump:", title);
+ buf = udebug_entry_append(&ud_log, NULL, 3 * len);
+ for (size_t i = 0; i < len; i++)
+ buf += sprintf(buf, " %02x", *(uint8_t *)(data + i));
+ udebug_entry_add(&ud_log);
+}
+
+static void udebug_netlink_hook(int tx, const void *data, size_t len)
+{
+ struct {
+ uint16_t pkttype;
+ uint16_t arphdr;
+ uint16_t _pad[5];
+ uint16_t proto;
+ } hdr = {
+ .pkttype = host_to_be16(tx ? 7 : 6),
+ .arphdr = host_to_be16(824),
+ .proto = host_to_be16(16),
+ };
+ const struct nlmsghdr *nlh = data;
+ const struct genlmsghdr *gnlh = data + NLMSG_HDRLEN;
+ struct udebug_buf *buf = &ud_nl[!!tx];
+
+ if (nlh->nlmsg_type == 0x10)
+ buf = &ud_nl[2];
+ else if (!tx && gnlh->cmd == NL80211_CMD_FRAME &&
+ !(udebug_buf_flags(buf) & UDEBUG_FLAG_RX_FRAME))
+ return;
+
+ if (!udebug_buf_valid(buf))
+ return;
+
+ udebug_entry_init(buf);
+ udebug_entry_append(buf, &hdr, sizeof(hdr));
+ udebug_entry_append(buf, data, len);
+ udebug_entry_add(buf);
+}
+
+static void
+wpa_udebug_config(struct udebug_ubus *ctx, struct blob_attr *data,
+ bool enabled)
+{
+ udebug_ubus_apply_config(&ud, udebug_rings, ARRAY_SIZE(udebug_rings),
+ data, enabled);
+
+ if (udebug_buf_valid(&ud_log)) {
+ wpa_printf_hook = udebug_printf_hook;
+ wpa_hexdump_hook = udebug_hexdump_hook;
+ } else {
+ wpa_printf_hook = NULL;
+ wpa_hexdump_hook = NULL;
+ }
+
+ if (udebug_buf_valid(&ud_nl[0]) ||
+ udebug_buf_valid(&ud_nl[1]) ||
+ udebug_buf_valid(&ud_nl[2]))
+ wpa_netlink_hook = udebug_netlink_hook;
+ else
+ wpa_netlink_hook = NULL;
+}
+
+uc_value_t *uc_wpa_udebug_set(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *name = uc_fn_arg(0);
+ uc_value_t *ubus = uc_fn_arg(1);
+ static bool enabled = false;
+ struct ubus_context *ctx;
+ bool cur_en;
+
+ cur_en = ucv_type(name) == UC_STRING;
+ ctx = ucv_resource_data(ubus, "ubus.connection");
+ if (!ctx)
+ cur_en = false;
+
+ if (enabled == cur_en)
+ return ucv_boolean_new(true);
+
+ enabled = cur_en;
+ if (enabled) {
+ udebug_service = strdup(ucv_string_get(name));
+ udebug_init(&ud);
+ udebug_auto_connect(&ud, NULL);
+ udebug_ubus_init(&ud_ubus, ctx, udebug_service, wpa_udebug_config);
+ } else {
+ udebug_ubus_free(&ud_ubus);
+ for (size_t i = 0; i < ARRAY_SIZE(udebug_rings); i++)
+ if (udebug_buf_valid(udebug_rings[i].buf))
+ udebug_buf_free(udebug_rings[i].buf);
+ udebug_free(&ud);
+ free(udebug_service);
+ }
+
+ return ucv_boolean_new(true);
+}
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type)
+{
+ uc_value_t *global = uc_resource_new(global_type, NULL);
+ uc_value_t *proto;
+
+ uc_vm_registry_set(&vm, "hostap.global", global);
+ proto = ucv_prototype_get(global);
+ ucv_object_add(proto, "data", ucv_get(ucv_object_new(&vm)));
+
+#define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
+ ADD_CONST(MSG_EXCESSIVE);
+ ADD_CONST(MSG_MSGDUMP);
+ ADD_CONST(MSG_DEBUG);
+ ADD_CONST(MSG_INFO);
+ ADD_CONST(MSG_WARNING);
+ ADD_CONST(MSG_ERROR);
+#undef ADD_CONST
+
+ ucv_object_add(uc_vm_scope_get(&vm), name, ucv_get(global));
+
+ return global;
+}
+
+int wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val)
+{
+ uc_value_t *data;
+ int i = 0;
+
+ while (ucv_array_get(reg, i))
+ i++;
+
+ ucv_array_set(reg, i, ucv_get(val));
+
+ return i + 1;
+}
+
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
+{
+ if (!idx)
+ return NULL;
+
+ return ucv_array_get(reg, idx - 1);
+}
+
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
+{
+ uc_value_t *val = wpa_ucode_registry_get(reg, idx);
+ void **dataptr;
+
+ if (!val)
+ return NULL;
+
+ ucv_array_set(reg, idx - 1, NULL);
+ dataptr = ucv_resource_dataptr(val, NULL);
+ if (dataptr)
+ *dataptr = NULL;
+
+ return val;
+}
+
+
+uc_value_t *wpa_ucode_call(size_t nargs)
+{
+ if (uc_vm_call(&vm, true, nargs) != EXCEPTION_NONE)
+ return NULL;
+
+ if (!gc_timer.pending)
+ uloop_timeout_set(&gc_timer, 10);
+
+ return uc_vm_stack_pop(&vm);
+}
+
+void wpa_ucode_free_vm(void)
+{
+ if (!vm.config)
+ return;
+
+ uc_search_path_free(&vm.config->module_search_path);
+ uc_vm_free(&vm);
+ registry = NULL;
+ vm = (uc_vm_t){};
+}
diff --git a/package/network/services/hostapd/src/src/utils/ucode.h b/package/network/services/hostapd/src/src/utils/ucode.h
new file mode 100644
index 00000000000..c083241e079
--- /dev/null
+++ b/package/network/services/hostapd/src/src/utils/ucode.h
@@ -0,0 +1,30 @@
+#ifndef __HOSTAPD_UTILS_UCODE_H
+#define __HOSTAPD_UTILS_UCODE_H
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include <ucode/lib.h>
+#include <ucode/vm.h>
+
+#define HOSTAPD_UC_PATH "/usr/share/hostap/"
+
+extern uc_value_t *uc_registry;
+uc_vm_t *wpa_ucode_create_vm(void);
+int wpa_ucode_run(const char *script);
+int wpa_ucode_call_prepare(const char *fname);
+uc_value_t *wpa_ucode_call(size_t nargs);
+void wpa_ucode_free_vm(void);
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type);
+
+int wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val);
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx);
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx);
+
+uc_value_t *uc_wpa_udebug_set(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs);
+
+#endif
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.c b/package/network/services/hostapd/src/wpa_supplicant/ubus.c
index 16a68c50731..1c477f0c0cb 100644
--- a/package/network/services/hostapd/src/wpa_supplicant/ubus.c
+++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.c
@@ -30,12 +30,6 @@ static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *ob
return container_of(obj, struct wpa_supplicant, ubus.obj);
}
-static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct ubus_context *ctx = eloop_ctx;
- ubus_handle_event(ctx);
-}
-
static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
{
if (ubus_reconnect(ctx, NULL)) {
@@ -43,12 +37,12 @@ static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
return;
}
- eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+ ubus_add_uloop(ctx);
}
static void wpas_ubus_connection_lost(struct ubus_context *ctx)
{
- eloop_unregister_read_sock(ctx->sock.fd);
+ uloop_fd_delete(&ctx->sock);
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
}
@@ -57,12 +51,14 @@ static bool wpas_ubus_init(void)
if (ctx)
return true;
+ eloop_add_uloop();
ctx = ubus_connect(NULL);
if (!ctx)
return false;
ctx->connection_lost = wpas_ubus_connection_lost;
- eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+ ubus_add_uloop(ctx);
+
return true;
}
@@ -80,7 +76,7 @@ static void wpas_ubus_ref_dec(void)
if (ctx_ref)
return;
- eloop_unregister_read_sock(ctx->sock.fd);
+ uloop_fd_delete(&ctx->sock);
ubus_free(ctx);
ctx = NULL;
}
@@ -211,152 +207,6 @@ void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
free(name);
}
-enum {
- WPAS_CONFIG_DRIVER,
- WPAS_CONFIG_IFACE,
- WPAS_CONFIG_BRIDGE,
- WPAS_CONFIG_HOSTAPD_CTRL,
- WPAS_CONFIG_CTRL,
- WPAS_CONFIG_FILE,
- __WPAS_CONFIG_MAX
-};
-
-static const struct blobmsg_policy wpas_config_add_policy[__WPAS_CONFIG_MAX] = {
- [WPAS_CONFIG_DRIVER] = { "driver", BLOBMSG_TYPE_STRING },
- [WPAS_CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
- [WPAS_CONFIG_BRIDGE] = { "bridge", BLOBMSG_TYPE_STRING },
- [WPAS_CONFIG_HOSTAPD_CTRL] = { "hostapd_ctrl", BLOBMSG_TYPE_STRING },
- [WPAS_CONFIG_CTRL] = { "ctrl", BLOBMSG_TYPE_STRING },
- [WPAS_CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING },
-};
-
-static int
-wpas_config_add(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
-{
- struct blob_attr *tb[__WPAS_CONFIG_MAX];
- struct wpa_global *global = get_wpa_global_from_object(obj);
- struct wpa_interface *iface;
-
- blobmsg_parse(wpas_config_add_policy, __WPAS_CONFIG_MAX, tb, blob_data(msg), blob_len(msg));
-
- if (!tb[WPAS_CONFIG_FILE] || !tb[WPAS_CONFIG_IFACE] || !tb[WPAS_CONFIG_DRIVER])
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- iface = os_zalloc(sizeof(struct wpa_interface));
- if (iface == NULL)
- return UBUS_STATUS_UNKNOWN_ERROR;
-
- iface->driver = blobmsg_get_string(tb[WPAS_CONFIG_DRIVER]);
- iface->ifname = blobmsg_get_string(tb[WPAS_CONFIG_IFACE]);
- iface->confname = blobmsg_get_string(tb[WPAS_CONFIG_FILE]);
-
- if (tb[WPAS_CONFIG_BRIDGE])
- iface->bridge_ifname = blobmsg_get_string(tb[WPAS_CONFIG_BRIDGE]);
-
- if (tb[WPAS_CONFIG_CTRL])
- iface->ctrl_interface = blobmsg_get_string(tb[WPAS_CONFIG_CTRL]);
-
- if (tb[WPAS_CONFIG_HOSTAPD_CTRL])
- iface->hostapd_ctrl = blobmsg_get_string(tb[WPAS_CONFIG_HOSTAPD_CTRL]);
-
- if (!wpa_supplicant_add_iface(global, iface, NULL))
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- blob_buf_init(&b, 0);
- blobmsg_add_u32(&b, "pid", getpid());
- ubus_send_reply(ctx, req, b.head);
-
- return UBUS_STATUS_OK;
-}
-
-enum {
- WPAS_CONFIG_REM_IFACE,
- __WPAS_CONFIG_REM_MAX
-};
-
-static const struct blobmsg_policy wpas_config_remove_policy[__WPAS_CONFIG_REM_MAX] = {
- [WPAS_CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
-};
-
-static int
-wpas_config_remove(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
-{
- struct blob_attr *tb[__WPAS_CONFIG_REM_MAX];
- struct wpa_global *global = get_wpa_global_from_object(obj);
- struct wpa_supplicant *wpa_s = NULL;
- unsigned int found = 0;
-
- blobmsg_parse(wpas_config_remove_policy, __WPAS_CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg));
-
- if (!tb[WPAS_CONFIG_REM_IFACE])
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- /* find wpa_s object for to-be-removed interface */
- for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- if (!strncmp(wpa_s->ifname,
- blobmsg_get_string(tb[WPAS_CONFIG_REM_IFACE]),
- sizeof(wpa_s->ifname)))
- {
- found = 1;
- break;
- }
- }
-
- if (!found)
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- if (wpa_supplicant_remove_iface(global, wpa_s, 0))
- return UBUS_STATUS_INVALID_ARGUMENT;
-
- return UBUS_STATUS_OK;
-}
-
-static const struct ubus_method wpas_daemon_methods[] = {
- UBUS_METHOD("config_add", wpas_config_add, wpas_config_add_policy),
- UBUS_METHOD("config_remove", wpas_config_remove, wpas_config_remove_policy),
-};
-
-static struct ubus_object_type wpas_daemon_object_type =
- UBUS_OBJECT_TYPE("wpa_supplicant", wpas_daemon_methods);
-
-void wpas_ubus_add(struct wpa_global *global)
-{
- struct ubus_object *obj = &global->ubus_global;
- int ret;
-
- if (!wpas_ubus_init())
- return;
-
- obj->name = strdup("wpa_supplicant");
-
- obj->type = &wpas_daemon_object_type;
- obj->methods = wpas_daemon_object_type.methods;
- obj->n_methods = wpas_daemon_object_type.n_methods;
- ret = ubus_add_object(ctx, obj);
- wpas_ubus_ref_inc();
-}
-
-void wpas_ubus_free(struct wpa_global *global)
-{
- struct ubus_object *obj = &global->ubus_global;
- char *name = (char *) obj->name;
-
- if (!ctx)
- return;
-
- if (obj->id) {
- ubus_remove_object(ctx, obj);
- wpas_ubus_ref_dec();
- }
-
- free(name);
-}
-
-
#ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
{
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.h b/package/network/services/hostapd/src/wpa_supplicant/ubus.h
index bf92b98c013..f6681cb26d0 100644
--- a/package/network/services/hostapd/src/wpa_supplicant/ubus.h
+++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.h
@@ -24,9 +24,6 @@ struct wpas_ubus_bss {
void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s);
void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s);
-void wpas_ubus_add(struct wpa_global *global);
-void wpas_ubus_free(struct wpa_global *global);
-
#ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
#endif
@@ -34,14 +31,6 @@ void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential
#else
struct wpas_ubus_bss {};
-static inline void wpas_ubus_add_iface(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void wpas_ubus_free_iface(struct wpa_supplicant *wpa_s)
-{
-}
-
static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
{
}
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ucode.c b/package/network/services/hostapd/src/wpa_supplicant/ucode.c
new file mode 100644
index 00000000000..397f85bde7f
--- /dev/null
+++ b/package/network/services/hostapd/src/wpa_supplicant/ucode.c
@@ -0,0 +1,299 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "drivers/driver.h"
+#include "ap/hostapd.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "bss.h"
+#include "ucode.h"
+
+static struct wpa_global *wpa_global;
+static uc_resource_type_t *global_type, *iface_type;
+static uc_value_t *global, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_s->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+
+ val = uc_resource_new(iface_type, wpa_s);
+ wpa_s->ucode.idx = wpa_ucode_registry_add(iface_registry, val);
+
+ return val;
+}
+
+static void
+wpas_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ struct wpa_supplicant *wpa_s;
+ int i;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("iface_add"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ wpa_s->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("iface_remove"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_update_state(struct wpa_supplicant *wpa_s)
+{
+ const char *state;
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ if (wpa_ucode_call_prepare("state"))
+ return;
+
+ state = wpa_supplicant_state_txt(wpa_s->wpa_state);
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ uc_value_push(ucv_get(ucv_string_new(state)));
+ ucv_put(wpa_ucode_call(3));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data)
+{
+ const char *state;
+ uc_value_t *val;
+
+ if (event != EVENT_CH_SWITCH_STARTED)
+ return;
+
+ val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ if (wpa_ucode_call_prepare("event"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ uc_value_push(ucv_get(ucv_string_new(event_to_string(event))));
+ val = ucv_object_new(vm);
+ uc_value_push(ucv_get(val));
+
+ if (event == EVENT_CH_SWITCH_STARTED) {
+ ucv_object_add(val, "csa_count", ucv_int64_new(data->ch_switch.count));
+ ucv_object_add(val, "frequency", ucv_int64_new(data->ch_switch.freq));
+ ucv_object_add(val, "sec_chan_offset", ucv_int64_new(data->ch_switch.ch_offset));
+ ucv_object_add(val, "center_freq1", ucv_int64_new(data->ch_switch.cf1));
+ ucv_object_add(val, "center_freq2", ucv_int64_new(data->ch_switch.cf2));
+ }
+
+ ucv_put(wpa_ucode_call(4));
+ ucv_gc(vm);
+}
+
+static const char *obj_stringval(uc_value_t *obj, const char *name)
+{
+ uc_value_t *val = ucv_object_get(obj, name, NULL);
+
+ return ucv_string_get(val);
+}
+
+static uc_value_t *
+uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *info = uc_fn_arg(0);
+ uc_value_t *driver = ucv_object_get(info, "driver", NULL);
+ uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
+ uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
+ uc_value_t *config = ucv_object_get(info, "config", NULL);
+ uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
+ struct wpa_interface iface;
+ int ret = -1;
+
+ if (ucv_type(info) != UC_OBJECT)
+ goto out;
+
+ iface = (struct wpa_interface){
+ .driver = "nl80211",
+ .ifname = ucv_string_get(ifname),
+ .bridge_ifname = ucv_string_get(bridge),
+ .confname = ucv_string_get(config),
+ .ctrl_interface = ucv_string_get(ctrl),
+ };
+
+ if (driver) {
+ const char *drvname;
+ if (ucv_type(driver) != UC_STRING)
+ goto out;
+
+ iface.driver = NULL;
+ drvname = ucv_string_get(driver);
+ for (int i = 0; wpa_drivers[i]; i++) {
+ if (!strcmp(drvname, wpa_drivers[i]->name))
+ iface.driver = wpa_drivers[i]->name;
+ }
+
+ if (!iface.driver)
+ goto out;
+ }
+
+ if (!iface.ifname || !iface.confname)
+ goto out;
+
+ ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = NULL;
+ uc_value_t *ifname_arg = uc_fn_arg(0);
+ const char *ifname = ucv_string_get(ifname_arg);
+ int ret = -1;
+
+ if (!ifname)
+ goto out;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ if (!strcmp(wpa_s->ifname, ifname))
+ break;
+
+ if (!wpa_s)
+ goto out;
+
+ ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface");
+ struct wpa_bss *bss;
+ uc_value_t *ret, *val;
+
+ if (!wpa_s)
+ return NULL;
+
+ ret = ucv_object_new(vm);
+
+ val = ucv_string_new(wpa_supplicant_state_txt(wpa_s->wpa_state));
+ ucv_object_add(ret, "state", ucv_get(val));
+
+ bss = wpa_s->current_bss;
+ if (bss) {
+ int sec_chan = 0;
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2) {
+ const struct ieee80211_ht_operation *ht_oper;
+ int sec;
+
+ ht_oper = (const void *) (ie + 2);
+ sec = ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ sec_chan = 1;
+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ sec_chan = -1;
+ }
+
+ ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(sec_chan));
+ ucv_object_add(ret, "frequency", ucv_int64_new(bss->freq));
+ }
+
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+
+ ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(ifmsh->conf->secondary_channel));
+ ucv_object_add(ret, "frequency", ucv_int64_new(ifmsh->freq));
+ }
+#endif
+
+ return ret;
+}
+
+int wpas_ucode_init(struct wpa_global *gl)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "add_iface", uc_wpas_add_iface },
+ { "remove_iface", uc_wpas_remove_iface },
+ { "udebug_set", uc_wpa_udebug_set },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ { "status", uc_wpas_iface_status },
+ };
+ uc_value_t *data, *proto;
+
+ wpa_global = gl;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
+ iface_type = uc_type_declare(vm, "wpas.iface", iface_fns, NULL);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "wpas.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("wpas", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
+ goto free_vm;
+
+ ucv_gc(vm);
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void wpas_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ucode.h b/package/network/services/hostapd/src/wpa_supplicant/ucode.h
new file mode 100644
index 00000000000..a429a0ed87b
--- /dev/null
+++ b/package/network/services/hostapd/src/wpa_supplicant/ucode.h
@@ -0,0 +1,49 @@
+#ifndef __WPAS_UCODE_H
+#define __WPAS_UCODE_H
+
+#include "utils/ucode.h"
+
+struct wpa_global;
+union wpa_event_data;
+struct wpa_supplicant;
+
+struct wpas_ucode_bss {
+#ifdef UCODE_SUPPORT
+ unsigned int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+int wpas_ucode_init(struct wpa_global *gl);
+void wpas_ucode_free(void);
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_update_state(struct wpa_supplicant *wpa_s);
+void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data);
+#else
+static inline int wpas_ucode_init(struct wpa_global *gl)
+{
+ return -EINVAL;
+}
+static inline void wpas_ucode_free(void)
+{
+}
+static inline void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_update_state(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data)
+{
+}
+
+#endif
+
+#endif
diff --git a/package/network/services/ipset-dns/Makefile b/package/network/services/ipset-dns/Makefile
index 3f21d04c47c..f55281ef427 100644
--- a/package/network/services/ipset-dns/Makefile
+++ b/package/network/services/ipset-dns/Makefile
@@ -11,7 +11,7 @@ PKG_NAME:=ipset-dns
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
-PKG_SOURCE_URL:=http://git.zx2c4.com/ipset-dns
+PKG_SOURCE_URL:=https://git.zx2c4.com/ipset-dns
PKG_SOURCE_DATE:=2017-10-08
PKG_SOURCE_VERSION:=ade2cf88e933f4f90451e0a6171f0aa4a523f989
PKG_MIRROR_HASH:=34ad1f5c7d2eab90b795f2a512102891428216e3d439d918a8992846550e9697
diff --git a/package/network/services/lldpd/Makefile b/package/network/services/lldpd/Makefile
index 920e113e66e..1f8d1e546b0 100644
--- a/package/network/services/lldpd/Makefile
+++ b/package/network/services/lldpd/Makefile
@@ -8,18 +8,20 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=lldpd
-PKG_VERSION:=1.0.9
-PKG_RELEASE:=3
+PKG_VERSION:=1.0.17
+PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=https://media.luffy.cx/files/lldpd
-PKG_HASH:=6b64eb3125952b1e33472198b054e8aa0dee45f45d3d4be22789090a474949f5
+PKG_SOURCE_URL:=https://github.com/lldpd/lldpd/releases/download/$(PKG_VERSION)/
+PKG_HASH:=89ae691a4917ac9e0ec3b8b2c1e634cc402d43b804f98850c73bd1c7df380882
PKG_MAINTAINER:=Stijn Tintel <stijn@linux-ipv6.be>
PKG_LICENSE:=ISC
+PKG_CPE_ID:=cpe:/a:lldpd_project:lldpd
PKG_FIXUP:=autoreconf
PKG_BUILD_PARALLEL:=1
+PKG_BUILD_FLAGS:=lto
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
@@ -66,19 +68,28 @@ define Package/lldpd/install
$(INSTALL_BIN) ./files/lldpd.init $(1)/etc/init.d/lldpd
$(INSTALL_CONF) ./files/lldpd.config $(1)/etc/config/lldpd
ifneq ($(CONFIG_LLDPD_WITH_CDP),y)
- sed -i -e '/cdp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+ sed -i -e 's/CONFIG_LLDPD_WITH_CDP=y/CONFIG_LLDPD_WITH_CDP=n/g' $(1)/etc/init.d/lldpd
+ sed -i -e '/cdp/d' $(1)/etc/config/lldpd
endif
ifneq ($(CONFIG_LLDPD_WITH_FDP),y)
- sed -i -e '/fdp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+ sed -i -e 's/CONFIG_LLDPD_WITH_FDP=y/CONFIG_LLDPD_WITH_FDP=n/g' $(1)/etc/init.d/lldpd
+ sed -i -e '/fdp/d' $(1)/etc/config/lldpd
endif
ifneq ($(CONFIG_LLDPD_WITH_EDP),y)
- sed -i -e '/edp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+ sed -i -e 's/CONFIG_LLDPD_WITH_EDP=y/CONFIG_LLDPD_WITH_EDP=n/g' $(1)/etc/init.d/lldpd
+ sed -i -e '/edp/d' $(1)/etc/config/lldpd
endif
ifneq ($(CONFIG_LLDPD_WITH_SONMP),y)
- sed -i -e '/sonmp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+ sed -i -e 's/CONFIG_LLDPD_WITH_SONMP=y/CONFIG_LLDPD_WITH_SONMP=n/g' $(1)/etc/init.d/lldpd
+ sed -i -e '/sonmp/d' $(1)/etc/config/lldpd
endif
ifneq ($(CONFIG_LLDPD_WITH_SNMP),y)
- sed -i -e '/agentxsocket/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+ sed -i -e 's/CONFIG_LLDPD_WITH_SNMP=y/CONFIG_LLDPD_WITH_SNMP=n/g' $(1)/etc/init.d/lldpd
+ sed -i -e '/agentxsocket/d' $(1)/etc/config/lldpd
+endif
+ifneq ($(CONFIG_LLDPD_WITH_LLDPMED),y)
+ sed -i -e 's/CONFIG_LLDPD_WITH_LLDPMED=y/CONFIG_LLDPD_WITH_LLDPMED=n/g' $(1)/etc/init.d/lldpd
+ sed -i -e '/agentxsocket/d' $(1)/etc/config/lldpd
endif
endef
@@ -110,7 +121,6 @@ CONFIGURE_ARGS += \
$(if $(CONFIG_LLDPD_WITH_SNMP),--with-snmp,) \
$(if $(CONFIG_USE_GLIBC),,--without-libbsd)
-TARGET_CFLAGS += -flto
-TARGET_LDFLAGS += -flto -Wl,--gc-sections,--as-needed
+TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed
$(eval $(call BuildPackage,lldpd))
diff --git a/package/network/services/lldpd/files/lldpd.init b/package/network/services/lldpd/files/lldpd.init
index 7a5b25e0160..f90b4a237cd 100644
--- a/package/network/services/lldpd/files/lldpd.init
+++ b/package/network/services/lldpd/files/lldpd.init
@@ -4,12 +4,25 @@
START=90
STOP=01
+CONFIG_LLDPD_WITH_CDP=y
+CONFIG_LLDPD_WITH_EDP=y
+CONFIG_LLDPD_WITH_FDP=y
+CONFIG_LLDPD_WITH_LLDPMED=y
+CONFIG_LLDPD_WITH_SNMP=y
+CONFIG_LLDPD_WITH_SONMP=y
+
USE_PROCD=1
+LLDPDBIN=/usr/sbin/lldpd
LLDPCLI=/usr/sbin/lldpcli
LLDPSOCKET=/var/run/lldpd.socket
LLDPD_CONF=/tmp/lldpd.conf
LLDPD_CONFS_DIR=/tmp/lldpd.d
+LLDPD_RUN=/var/run/lldpd
+LLDPD_RESTART_HASH=${LLDPD_RUN}/lldpd.restart_hash
+
+. "$IPKG_INSTROOT/lib/functions/network.sh"
+
find_release_info()
{
[ -s /etc/os-release ] && . /etc/os-release
@@ -19,10 +32,64 @@ find_release_info()
echo "${PRETTY_NAME:-Unknown OpenWrt release} @ $(cat /proc/sys/kernel/hostname)"
}
+get_config_restart_hash() {
+ local var="$1"
+ local _string _hash v
+
+ config_load 'lldpd'
+
+ config_get v 'config' 'lldp_class'; append _string "$v" ","
+ if [ "$CONFIG_LLDPD_WITH_SNMP" == "y" ]; then
+ config_get v 'config' 'agentxsocket'; append _string "$v" ","
+ fi
+ config_get v 'config' 'cid_interface'; append _string "$v" ","
+ config_get v 'config' 'filter'; append _string "$v" ","
+ config_get_bool v 'config' 'readonly_mode'; append _string "$v" ","
+ config_get_bool v 'config' 'lldp_no_version'; append _string "$v" ","
+ if [ "$CONFIG_LLDPD_WITH_LLDPMED" == "y" ]; then
+ config_get_bool v 'config' 'lldpmed_no_inventory'; append _string "$v" ","
+ fi
+ config_get_bool v 'config' 'enable_lldp' 1; append _string "$v" ","
+ config_get_bool v 'config' 'force_lldp'; append _string "$v" ","
+ if [ "$CONFIG_LLDPD_WITH_CDP" == "y" ]; then
+ config_get_bool v 'config' 'enable_cdp'; append _string "$v" ","
+ config_get v 'config' 'cdp_version'; append _string "$v" ","
+ config_get_bool v 'config' 'force_cdp'; append _string "$v" ","
+ config_get_bool v 'config' 'force_cdpv2'; append _string "$v" ","
+ fi
+ if [ "$CONFIG_LLDPD_WITH_EDP" == "y" ]; then
+ config_get_bool v 'config' 'enable_edp'; append _string "$v" ","
+ config_get_bool v 'config' 'force_edp'; append _string "$v" ","
+ fi
+ if [ "$CONFIG_LLDPD_WITH_FDP" == "y" ]; then
+ config_get_bool v 'config' 'enable_fdp'; append _string "$v" ","
+ config_get_bool v 'config' 'force_fdp'; append _string "$v" ","
+ fi
+ if [ "$CONFIG_LLDPD_WITH_SONMP" == "y" ]; then
+ config_get_bool v 'config' 'enable_sonmp'; append _string "$v" ","
+ config_get_bool v 'config' 'force_sonmp'; append _string "$v" ","
+ fi
+
+ _hash=`echo -n "${_string}" | md5sum | awk '{ print \$1 }'`
+ export -n "$var=$_hash"
+}
+
+get_config_cid_ifaces() {
+ local _ifacesCONFIG_LLDPD_WITH_FDP
+
+ local _iface _ifnames=""
+ for _iface in $_ifaces; do
+ local _ifname=""
+ if network_get_device _ifname "$_iface" || [ -e "/sys/class/net/$_iface" ]; then
+ append _ifnames "${_ifname:-$_iface}" ","
+ fi
+ done
+
+ export -n "${1}=$_ifnames"
+}
+
write_lldpd_conf()
{
- . /lib/functions/network.sh
-
local lldp_description
config_load 'lldpd'
@@ -45,12 +112,51 @@ write_lldpd_conf()
local lldp_mgmt_ip
config_get lldp_mgmt_ip 'config' 'lldp_mgmt_ip'
+ local lldp_syscapabilities
+ config_get lldp_syscapabilities 'config' 'lldp_syscapabilities'
+
+ if [ "$CONFIG_LLDPD_WITH_LLDPMED" == "y" ]; then
+ local lldpmed_fast_start
+ config_get_bool lldpmed_fast_start 'config' 'lldpmed_fast_start' 0
+
+ local lldpmed_fast_start_tx_interval
+ config_get lldpmed_fast_start_tx_interval 'config' 'lldpmed_fast_start_tx_interval' 0
+ fi
+
+ local lldp_agenttype
+ config_get lldp_agenttype 'config' 'lldp_agenttype' 'nearest-bridge'
+
+ local lldp_portidsubtype
+ config_get lldp_portidsubtype 'config' 'lldp_portidsubtype' 'macaddress'
+
+ local lldp_platform
+ config_get lldp_platform 'config' 'lldp_platform' ""
+
+ local lldp_tx_interval
+ config_get lldp_tx_interval 'config' 'lldp_tx_interval' 0
+
+ local lldp_tx_hold
+ config_get lldp_tx_hold 'config' 'lldp_tx_hold' 0
+
# Clear out the config file first
echo -n > "$LLDPD_CONF"
[ -n "$ifnames" ] && echo "configure system interface pattern" "$ifnames" >> "$LLDPD_CONF"
[ -n "$lldp_description" ] && echo "configure system description" "\"$lldp_description\"" >> "$LLDPD_CONF"
[ -n "$lldp_hostname" ] && echo "configure system hostname" "\"$lldp_hostname\"" >> "$LLDPD_CONF"
[ -n "$lldp_mgmt_ip" ] && echo "configure system ip management pattern" "\"$lldp_mgmt_ip\"" >> "$LLDPD_CONF"
+ [ -n "$lldp_syscapabilities" ] && echo "configure system capabilities enabled" "\"$lldp_syscapabilities\"" >> "$LLDPD_CONF"
+ if [ "$CONFIG_LLDPD_WITH_LLDPMED" == "y" ] && [ $lldpmed_fast_start -gt 0 ]; then
+ if [ $lldpmed_fast_start_tx_interval -gt 0 ]; then
+ echo "configure med fast-start tx-interval" "\"$lldpmed_fast_start_tx_interval\"" >> "$LLDPD_CONF"
+ else
+ echo "configure med fast-start" "enable" >> "$LLDPD_CONF"
+ fi
+ fi
+ [ -n "$lldp_agenttype" ] && echo "configure lldp agent-type" "\"$lldp_agenttype\"" >> "$LLDPD_CONF"
+ [ -n "$lldp_portidsubtype" ] && echo "configure lldp portidsubtype" "\"$lldp_portidsubtype\"" >> "$LLDPD_CONF"
+ [ -n "$lldp_platform" ] && echo "configure system platform" "\"$lldp_platform\"" >> "$LLDPD_CONF"
+ [ $lldp_tx_interval -gt 0 ] && echo "configure lldp tx-interval" "$lldp_tx_interval" >> "$LLDPD_CONF"
+ [ $lldp_tx_hold -gt 0 ] && echo "configure lldp tx-hold" "$lldp_tx_hold" >> "$LLDPD_CONF"
# Since lldpd's sysconfdir is /tmp, we'll symlink /etc/lldpd.d to /tmp/$LLDPD_CONFS_DIR
[ -e $LLDPD_CONFS_DIR ] || ln -s /etc/lldpd.d $LLDPD_CONFS_DIR
@@ -58,50 +164,175 @@ write_lldpd_conf()
start_service() {
+ local enable_lldp
+ local force_lldp
local enable_cdp
+ local cdp_version
+ local force_cdp
+ local force_cdpv2
local enable_fdp
+ local force_fdp
local enable_sonmp
+ local force_sonmp
local enable_edp
+ local force_edp
local lldp_class
local lldp_location
+ local lldp_no_version
+ local lldpmed_no_inventory
local readonly_mode
local agentxsocket
+ local filter
config_load 'lldpd'
- config_get_bool enable_cdp 'config' 'enable_cdp' 0
- config_get_bool enable_fdp 'config' 'enable_fdp' 0
- config_get_bool enable_sonmp 'config' 'enable_sonmp' 0
- config_get_bool enable_edp 'config' 'enable_edp' 0
+ config_get_bool enable_lldp 'config' 'enable_lldp' 1
+ config_get_bool force_lldp 'config' 'force_lldp' 0
+ if [ "$CONFIG_LLDPD_WITH_CDP" == "y" ]; then
+ config_get_bool enable_cdp 'config' 'enable_cdp' 0
+ config_get cdp_version 'config' 'cdp_version' 'cdpv1v2'
+ config_get_bool force_cdp 'config' 'force_cdp' 0
+ config_get_bool force_cdpv2 'config' 'force_cdpv2' 0
+ fi
+ if [ "$CONFIG_LLDPD_WITH_FDP" == "y" ]; then
+ config_get_bool enable_fdp 'config' 'enable_fdp' 0
+ config_get_bool force_fdp 'config' 'force_fdp' 0
+ fi
+ if [ "$CONFIG_LLDPD_WITH_SONMP" == "y" ]; then
+ config_get_bool enable_sonmp 'config' 'enable_sonmp' 0
+ config_get_bool force_sonmp 'config' 'force_sonmp' 0
+ fi
+ if [ "$CONFIG_LLDPD_WITH_EDP" == "y" ]; then
+ config_get_bool enable_edp 'config' 'enable_edp' 0
+ config_get_bool force_edp 'config' 'force_edp' 0
+ fi
config_get lldp_class 'config' 'lldp_class'
config_get lldp_location 'config' 'lldp_location'
+ config_get_bool lldp_no_version 'config' 'lldp_no_version' 0
+ if [ "$CONFIG_LLDPD_WITH_LLDPMED" == "y" ]; then
+ config_get_bool lldpmed_no_inventory 'config' 'lldpmed_no_inventory' 0
+ fi
config_get_bool readonly_mode 'config' 'readonly_mode' 0
- config_get agentxsocket 'config' 'agentxsocket'
+ if [ "$CONFIG_LLDPD_WITH_SNMP" == "y" ]; then
+ config_get agentxsocket 'config' 'agentxsocket'
+ fi
+ config_get filter 'config' 'filter' 15
- mkdir -p /var/run/lldp
- chown lldp:lldp /var/run/lldp
+ mkdir -p ${LLDPD_RUN}
+ chown lldp:lldp ${LLDPD_RUN}
# When lldpd starts, it also loads up what we write in this config file
write_lldpd_conf
procd_open_instance
- procd_set_param command /usr/sbin/lldpd
- procd_append_param command -d # don't daemonize, procd will handle that for us
+ procd_set_param command ${LLDPDBIN}
+ procd_append_param command -d
+
+ if [ $enable_lldp -gt 0 ]; then
+ if [ $force_lldp -gt 0 ]; then
+ procd_append_param command '-l'
+ fi
+ else
+ # Disable LLDP
+ procd_append_param command '-ll'
+ fi
+
+ if [ "$CONFIG_LLDPD_WITH_CDP" == "y" ] && [ $enable_cdp -gt 0 ]; then
+ if [ $cdp_version == "cdpv2" ]; then
+ if [ $force_cdp -gt 0 ]; then
+ # CDPv1 disabled, CDPv2 forced
+ procd_append_param command '-ccccc'
+ else
+ # CDPv1 disabled, CDPv2 enabled
+ procd_append_param command '-cccc'
+ fi
+ elif [ $cdp_version == "cdpv1v2" ]; then
+ if [ $force_cdp -gt 0 ] && [ $force_cdpv2 -gt 0 ]; then
+ # CDPv1 enabled, CDPv2 forced
+ procd_append_param command '-ccc'
+ elif [ $force_cdp -gt 0 ]; then
+ # CDPv1 forced, CDPv2 enabled
+ procd_append_param command '-cc'
+ else
+ # CDPv1 and CDPv2 enabled
+ procd_append_param command '-c'
+ fi
+ fi
+ fi
+
+ if [ "$CONFIG_LLDPD_WITH_FDP" == "y" ] && [ $enable_fdp -gt 0 ]; then
+ if [ $force_fdp -gt 0 ]; then
+ # FDP enbled and forced
+ procd_append_param command '-ff'
+ else
+ # FDP enabled
+ procd_append_param command '-f'
+ fi
+ fi
+
+ if [ "$CONFIG_LLDPD_WITH_SONMP" == "y" ] && [ $enable_sonmp -gt 0 ]; then
+ if [ $force_sonmp -gt 0 ]; then
+ # SONMP enabled and forced
+ procd_append_param command '-ss'
+ else
+ # SONMP enabled
+ procd_append_param command '-s'
+ fi
+ fi
+
+ if [ "$CONFIG_LLDPD_WITH_EDP" == "y" ] && [ $enable_edp -gt 0 ]; then
+ if [ $force_edp -gt 0 ]; then
+ # EDP enbled and forced
+ procd_append_param command '-ee'
+ else
+ # EDP enbled
+ procd_append_param command '-e'
+ fi
+ fi
- [ $enable_cdp -gt 0 ] && procd_append_param command '-c'
- [ $enable_fdp -gt 0 ] && procd_append_param command '-f'
- [ $enable_sonmp -gt 0 ] && procd_append_param command '-s'
- [ $enable_edp -gt 0 ] && procd_append_param command '-e'
[ $readonly_mode -gt 0 ] && procd_append_param command '-r'
+ [ $lldp_no_version -gt 0 ] && procd_append_param commanpackage/network/services/lldpd/Makefile package/network/services/lldpd/files/lldpd.initd '-k'
+ [ "$CONFIG_LLDPD_WITH_LLDPMED" == "y" ] && [ $lldpmed_no_inventory -gt 0 ] && procd_append_param command '-i'
[ -n "$lldp_class" ] && procd_append_param command -M "$lldp_class"
- [ -n "$agentxsocket" ] && procd_append_param command -x -X "$agentxsocket"
+ [ "$CONFIG_LLDPD_WITH_SNMP" == "y" ] && [ -n "$agentxsocket" ] && procd_append_param command -x -X "$agentxsocket"
+ [ -n "$filter" ] && procd_append_param command -H "$filter"
+
+ # ChassisID interfaces
+ local ifnames
+ get_config_cid_ifaces ifnames
+ [ -n "$ifnames" ] && procd_append_param command -C "$ifnames"
+
+ # Overwrite default configuration locations processed by lldpcli at start
+ procd_append_param command -O "$LLDPD_CONF"
+
+ local restart_hash
+ get_config_restart_hash restart_hash
+ echo -n "$restart_hash" > $LLDPD_RESTART_HASH
# set auto respawn behavior
procd_set_param respawn
procd_close_instance
}
+service_triggers() {
+ procd_add_config_trigger "config.change" "lldpd" /etc/init.d/lldpd reload
+}
+
reload_service() {
running || return 1
+
+ local running_hash=""
+ local config_hash=""
+
+ get_config_restart_hash config_hash
+ if [ -f ${LLDPD_RESTART_HASH} ]; then running_hash=`cat $LLDPD_RESTART_HASH`; fi
+
+ if [ "x$running_hash" != "x$config_hash" ]; then
+ # Restart LLDPd
+ # Some parameters can't be configured at runtime
+ restart
+ return 0
+ fi
+
$LLDPCLI -u $LLDPSOCKET &> /dev/null <<-EOF
pause
unconfigure lldp custom-tlv
@@ -109,7 +340,14 @@ reload_service() {
unconfigure system description
unconfigure system hostname
unconfigure system ip management pattern
+ unconfigure system platform
EOF
+ if [ "$CONFIG_LLDPD_WITH_LLDPMED" == "y" ]; then
+ $LLDPCLI -u $LLDPSOCKET &> /dev/null <<-EOF
+ unconfigure med fast-start
+ EOF
+
+ fi
# Rewrite lldpd.conf
# If something changed it should be included by the lldpcli call
write_lldpd_conf
@@ -123,5 +361,6 @@ reload_service() {
}
stop_service() {
- rm -rf /var/run/lldp $LLDPSOCKET
+ rm -rf ${LLDPD_RUN} $LLDPSOCKET 2>/dev/null
}
+
diff --git a/package/network/services/odhcpd/Makefile b/package/network/services/odhcpd/Makefile
index d7919d68365..ba6358f7795 100644
--- a/package/network/services/odhcpd/Makefile
+++ b/package/network/services/odhcpd/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=odhcpd
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcpd.git
-PKG_SOURCE_DATE:=2021-07-18
-PKG_SOURCE_VERSION:=bc9d317f2921ae6b529f2c9f8de79b75992e206f
-PKG_MIRROR_HASH:=be96c4984821b8af95bfee1a29c082bb9eaa052cd3e03d8632ff02afd2debc81
+PKG_MIRROR_HASH:=9936331b64880260cf969cc5656e1e1a8b7dc0e0843d64621242c500a330b4d6
+PKG_SOURCE_DATE:=2023-10-24
+PKG_SOURCE_VERSION:=d8118f6e76e5519881f9a37137c3a06b3cb60fd2
PKG_MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
PKG_LICENSE:=GPL-2.0
diff --git a/package/network/services/omcproxy/Makefile b/package/network/services/omcproxy/Makefile
index 26c78933840..c5b2f3e67f4 100644
--- a/package/network/services/omcproxy/Makefile
+++ b/package/network/services/omcproxy/Makefile
@@ -12,9 +12,9 @@ PKG_RELEASE:=9
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/omcproxy.git
-PKG_SOURCE_DATE:=2018-12-14
-PKG_SOURCE_VERSION:=722151f04348cf1b759613c087bced52fb45790a
-PKG_MIRROR_HASH:=4d218923c149e2dc9010b8932ea92ab7e06f30df06814ffedaba7e081f2d4640
+PKG_MIRROR_HASH:=6443276368dc7d45ee58bd7067da6c3a85396d9996039232cae3bdd426382f0c
+PKG_SOURCE_DATE:=2021-11-04
+PKG_SOURCE_VERSION:=bfba2aa75802ff1a70ef2fd3eba53409a8c6e93a
PKG_MAINTAINER:=Steven Barth <cyrus@openwrt.org>
PKG_LICENSE:=Apache-2.0
diff --git a/package/network/services/ppp/Makefile b/package/network/services/ppp/Makefile
index 10e9bdfdfe1..40ec5c5cf12 100644
--- a/package/network/services/ppp/Makefile
+++ b/package/network/services/ppp/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=ppp
-PKG_RELEASE:=3
+PKG_RELEASE:=5
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/paulusmack/ppp
@@ -26,6 +26,7 @@ PKG_VERSION:=$(PKG_RELEASE_VERSION).git-$(PKG_SOURCE_DATE)
PKG_BUILD_DEPENDS:=libpcap
PKG_ASLR_PIE_REGULAR:=1
+PKG_BUILD_FLAGS:=gc-sections lto
PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1
@@ -192,9 +193,6 @@ $(call Build/Configure/Default,, \
$(PKG_BUILD_DIR)/pppd/plugins/pppoatm/linux/
endef
-TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
-TARGET_LDFLAGS += -Wl,--gc-sections -flto -fuse-linker-plugin
-
MAKE_FLAGS += COPTS="$(TARGET_CFLAGS)" \
PRECOMPILED_FILTER=1 \
STAGING_DIR="$(STAGING_DIR)"
diff --git a/package/network/services/ppp/files/ppp.sh b/package/network/services/ppp/files/ppp.sh
index 7bbc497c43b..6d3a8e29ffa 100755
--- a/package/network/services/ppp/files/ppp.sh
+++ b/package/network/services/ppp/files/ppp.sh
@@ -220,9 +220,7 @@ proto_pppoe_setup() {
local config="$1"
local iface="$2"
- for module in slhc ppp_generic pppox pppoe; do
- /sbin/insmod $module 2>&- >&-
- done
+ /sbin/modprobe -qa slhc ppp_generic pppox pppoe
json_get_var mtu mtu
mtu="${mtu:-1492}"
@@ -262,9 +260,7 @@ proto_pppoa_setup() {
local config="$1"
local iface="$2"
- for module in slhc ppp_generic pppox pppoatm; do
- /sbin/insmod $module 2>&- >&-
- done
+ /sbin/modprobe -qa slhc ppp_generic pppox pppoatm
json_get_vars atmdev vci vpi encaps
@@ -311,13 +307,8 @@ proto_pptp_setup() {
exit 1
}
- local load
- for module in slhc ppp_generic ppp_async ppp_mppe ip_gre gre pptp; do
- grep -q "^$module " /proc/modules && continue
- /sbin/insmod $module 2>&- >&-
- load=1
- done
- [ "$load" = "1" ] && sleep 1
+ /sbin/modprobe -qa slhc ppp_generic ppp_async ppp_mppe ip_gre gre pptp
+ sleep 1
ppp_generic_setup "$config" \
plugin pptp.so \
@@ -335,4 +326,3 @@ proto_pptp_teardown() {
[ -f /usr/lib/pppd/*/pppoatm.so ] && add_protocol pppoa
[ -f /usr/lib/pppd/*/pptp.so ] && add_protocol pptp
}
-
diff --git a/package/network/services/ppp/patches/140-pppd-Fix-compilation-with-older-glibc-or-kernel-head.patch b/package/network/services/ppp/patches/140-pppd-Fix-compilation-with-older-glibc-or-kernel-head.patch
new file mode 100644
index 00000000000..154ac7270bf
--- /dev/null
+++ b/package/network/services/ppp/patches/140-pppd-Fix-compilation-with-older-glibc-or-kernel-head.patch
@@ -0,0 +1,54 @@
+From 98ec18f098e5ef68e3a8cc6954fcaf5a7fb8b7be Mon Sep 17 00:00:00 2001
+From: pali <7141871+pali@users.noreply.github.com>
+Date: Mon, 15 Feb 2021 07:54:01 +0100
+Subject: [PATCH] pppd: Fix compilation with older glibc or kernel headers
+ (#248)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+glibc versions prior to 2.24 do not define SOL_NETLINK and linux kernel
+versions prior to 4.3 do not define NETLINK_CAP_ACK. So add fallback
+definitions for these macros into pppd/sys-linux.c file.
+
+Also extend description why we call SOL_NETLINK/NETLINK_CAP_ACK option.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+---
+ pppd/sys-linux.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -125,6 +125,14 @@
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/if_addr.h>
++/* glibc versions prior to 2.24 do not define SOL_NETLINK */
++#ifndef SOL_NETLINK
++#define SOL_NETLINK 270
++#endif
++/* linux kernel versions prior to 4.3 do not define/support NETLINK_CAP_ACK */
++#ifndef NETLINK_CAP_ACK
++#define NETLINK_CAP_ACK 10
++#endif
+ #endif
+
+ #include "pppd.h"
+@@ -2843,7 +2851,15 @@ static int append_peer_ipv6_address(unsi
+ if (fd < 0)
+ return 0;
+
+- /* do not ask for error message content */
++ /*
++ * Tell kernel to not send to us payload of acknowledgment error message.
++ * NETLINK_CAP_ACK option is supported since Linux kernel version 4.3 and
++ * older kernel versions always send full payload in acknowledgment netlink
++ * message. We ignore payload of this message as we need only error code,
++ * to check if our set remote peer address request succeeded or failed.
++ * So ignore return value from the following setsockopt() call as setting
++ * option NETLINK_CAP_ACK means for us just a kernel hint / optimization.
++ */
+ one = 1;
+ setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
+
diff --git a/package/network/services/ppp/patches/141-Expand-byte-count-statistics-to-64-bits-298.patch b/package/network/services/ppp/patches/141-Expand-byte-count-statistics-to-64-bits-298.patch
new file mode 100644
index 00000000000..e4de5c0aa21
--- /dev/null
+++ b/package/network/services/ppp/patches/141-Expand-byte-count-statistics-to-64-bits-298.patch
@@ -0,0 +1,518 @@
+From 81ad945630120cc1c27c8bb00503be42b76ff202 Mon Sep 17 00:00:00 2001
+From: Jaco Kroon <jaco@uls.co.za>
+Date: Thu, 13 Jan 2022 08:38:04 +0200
+Subject: [PATCH] Expand byte count statistics to 64 bits (#298)
+
+* Add Gigawords to radius packets where applicable.
+
+IMPORTANT NOTE: The ioctl() only supports 32-bit counters. In order t
+obtain 64-bit counters, these are now pulled in from sysfs (it's assumed
+to be mounted on /sys which I'm assuming is standard).
+
+It is unknown whether sysfs will be available everywhere, as such, keep
+the ioctl() method in place, but attempt to detect wrap-overs.
+
+If the sysfs mechanism fails, fail back to the ioctl().
+
+Given maximum data rates, the intervals between calling this needs to be
+such that no more than 4GB (2^32) bytes are sent or received in any
+given interval. Mostly important for radius plugin where data
+accounting may be in effect.
+
+Towards this, a timer interval on 25 seconds is set to force a ioctl()
+poll irrespective of the rate of stats update calls. This may be
+important for especially radius that needs to provide interim-update
+intervals, if the interim updates is too long and the counters could
+wrap-over twice in a single interval. At 25 seconds we should detect
+all wraps up to an effective data rate of 1.37Gbps, which for my
+purposes is adequate.
+
+Possible downsides, 4 files are opened, read and closed every time
+statistics is requested. This results in 12 system calls every single
+time statistics is required, compared to 1 for the ioctl. Efficiency is
+unknown, but as a rule of thumb fewer system calls are better, this is
+however not a critical path in my opinion, so should not be a problem.
+If required I can run a few benchmarks using gettimeofday() to measure
+actual impact.
+
+Signed-off-by: Jaco Kroon <jaco@uls.co.za>
+
+* Use netlink if possible to obtain 64-bit stats.
+
+This uses two system calls per round.
+
+This should be preferred where available. It seems the RTM_GETSTATS was
+only added from 2016 some point (4.7.0 as per pali), which is in my
+opinion old, but given experience with certain embedded systems does
+need to be supported.
+
+Signed-off-by: Jaco Kroon <jaco@uls.co.za>
+
+Co-authored-by: Jaco Kroon <jaco@iewc.co.za>
+---
+ pppd/main.c | 5 +-
+ pppd/plugins/radius/etc/dictionary | 2 +
+ pppd/plugins/radius/radius.c | 28 ++-
+ pppd/plugins/radius/radiusclient.h | 2 +
+ pppd/pppd.h | 9 +-
+ pppd/sys-linux.c | 281 ++++++++++++++++++++++++++++-
+ 6 files changed, 313 insertions(+), 14 deletions(-)
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -87,6 +87,7 @@
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
++#include <inttypes.h>
+
+ #include "pppd.h"
+ #include "magic.h"
+@@ -1230,9 +1231,9 @@ update_link_stats(int u)
+
+ slprintf(numbuf, sizeof(numbuf), "%u", link_connect_time);
+ script_setenv("CONNECT_TIME", numbuf, 0);
+- slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_out);
++ snprintf(numbuf, sizeof(numbuf), "%" PRIu64, link_stats.bytes_out);
+ script_setenv("BYTES_SENT", numbuf, 0);
+- slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_in);
++ snprintf(numbuf, sizeof(numbuf), "%" PRIu64, link_stats.bytes_in);
+ script_setenv("BYTES_RCVD", numbuf, 0);
+ }
+
+--- a/pppd/plugins/radius/etc/dictionary
++++ b/pppd/plugins/radius/etc/dictionary
+@@ -82,6 +82,8 @@ ATTRIBUTE Acct-Session-Time 46 integer
+ ATTRIBUTE Acct-Input-Packets 47 integer
+ ATTRIBUTE Acct-Output-Packets 48 integer
+ ATTRIBUTE Acct-Terminate-Cause 49 integer
++ATTRIBUTE Acct-Input-Gigawords 52 integer
++ATTRIBUTE Acct-Output-Gigawords 53 integer
+ ATTRIBUTE Chap-Challenge 60 string
+ ATTRIBUTE NAS-Port-Type 61 integer
+ ATTRIBUTE Port-Limit 62 integer
+--- a/pppd/plugins/radius/radius.c
++++ b/pppd/plugins/radius/radius.c
+@@ -1020,12 +1020,22 @@ radius_acct_stop(void)
+ av_type = link_connect_time;
+ rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE);
+
+- av_type = link_stats.bytes_out;
++ av_type = link_stats.bytes_out & 0xFFFFFFFF;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE);
+
+- av_type = link_stats.bytes_in;
++ if (link_stats.bytes_out > 0xFFFFFFFF) {
++ av_type = link_stats.bytes_out >> 32;
++ rc_avpair_add(&send, PW_ACCT_OUTPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
++ }
++
++ av_type = link_stats.bytes_in & 0xFFFFFFFF;
+ rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE);
+
++ if (link_stats.bytes_in > 0xFFFFFFFF) {
++ av_type = link_stats.bytes_in >> 32;
++ rc_avpair_add(&send, PW_ACCT_INPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
++ }
++
+ av_type = link_stats.pkts_out;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE);
+
+@@ -1172,12 +1182,22 @@ radius_acct_interim(void *ignored)
+ av_type = link_connect_time;
+ rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE);
+
+- av_type = link_stats.bytes_out;
++ av_type = link_stats.bytes_out & 0xFFFFFFFF;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE);
+
+- av_type = link_stats.bytes_in;
++ if (link_stats.bytes_out > 0xFFFFFFFF) {
++ av_type = link_stats.bytes_out >> 32;
++ rc_avpair_add(&send, PW_ACCT_OUTPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
++ }
++
++ av_type = link_stats.bytes_in & 0xFFFFFFFF;
+ rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE);
+
++ if (link_stats.bytes_in > 0xFFFFFFFF) {
++ av_type = link_stats.bytes_in >> 32;
++ rc_avpair_add(&send, PW_ACCT_INPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
++ }
++
+ av_type = link_stats.pkts_out;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE);
+
+--- a/pppd/plugins/radius/radiusclient.h
++++ b/pppd/plugins/radius/radiusclient.h
+@@ -184,6 +184,8 @@ typedef struct pw_auth_hdr
+ #define PW_ACCT_LINK_COUNT 51 /* integer */
+
+ /* From RFC 2869 */
++#define PW_ACCT_INPUT_GIGAWORDS 52 /* integer */
++#define PW_ACCT_OUTPUT_GIGAWORDS 53 /* integer */
+ #define PW_ACCT_INTERIM_INTERVAL 85 /* integer */
+
+ /* Merit Experimental Extensions */
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -53,6 +53,7 @@
+ #include <stdlib.h> /* for encrypt */
+ #include <unistd.h> /* for setkey */
+ #include <stdarg.h>
++#include <stdint.h>
+ #include <limits.h> /* for NGROUPS_MAX */
+ #include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+ #include <sys/types.h> /* for u_int32_t, if defined */
+@@ -173,8 +174,8 @@ struct permitted_ip {
+ * pppd needs.
+ */
+ struct pppd_stats {
+- unsigned int bytes_in;
+- unsigned int bytes_out;
++ uint64_t bytes_in;
++ uint64_t bytes_out;
+ unsigned int pkts_in;
+ unsigned int pkts_out;
+ };
+@@ -347,7 +348,7 @@ extern char *max_tls_version;
+ extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */
+ extern int maxoctets_dir; /* Direction :
+ 0 - in+out (default)
+- 1 - in
++ 1 - in
+ 2 - out
+ 3 - max(in,out) */
+ extern int maxoctets_timeout; /* Timeout for check of octets limit */
+@@ -356,7 +357,7 @@ extern int maxoctets_timeout; /*
+ #define PPP_OCTETS_DIRECTION_OUT 2
+ #define PPP_OCTETS_DIRECTION_MAXOVERAL 3
+ /* same as previos, but little different on RADIUS side */
+-#define PPP_OCTETS_DIRECTION_MAXSESSION 4
++#define PPP_OCTETS_DIRECTION_MAXSESSION 4
+ #endif
+
+ #ifdef PPP_FILTER
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -79,6 +79,7 @@
+ #include <sys/sysmacros.h>
+
+ #include <errno.h>
++#include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <syslog.h>
+@@ -92,6 +93,7 @@
+ #include <ctype.h>
+ #include <termios.h>
+ #include <unistd.h>
++#include <limits.h>
+
+ /* This is in netdevice.h. However, this compile will fail miserably if
+ you attempt to include netdevice.h because it has so many references
+@@ -121,9 +123,19 @@
+ #include <linux/ppp_defs.h>
+ #include <linux/if_ppp.h>
+
+-#ifdef INET6
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
++#include <linux/if_link.h>
++/* Attempt at retaining compile-support with older than 4.7 kernels, or kernels
++ * where RTM_NEWSTATS isn't defined for whatever reason.
++ */
++#ifndef RTM_NEWSTATS
++#define RTM_NEWSTATS 92
++#define RTM_GETSTATS 94
++#define IFLA_STATS_LINK_64 1
++#endif
++
++#ifdef INET6
+ #include <linux/if_addr.h>
+ /* glibc versions prior to 2.24 do not define SOL_NETLINK */
+ #ifndef SOL_NETLINK
+@@ -1407,11 +1419,17 @@ get_idle_time(int u, struct ppp_idle *ip
+
+ /********************************************************************
+ *
+- * get_ppp_stats - return statistics for the link.
++ * get_ppp_stats_iocl - return statistics for the link, using the ioctl() method,
++ * this only supports 32-bit counters, so need to count the wraps.
+ */
+-int
+-get_ppp_stats(int u, struct pppd_stats *stats)
++static int
++get_ppp_stats_ioctl(int u, struct pppd_stats *stats)
+ {
++ static u_int32_t previbytes = 0;
++ static u_int32_t prevobytes = 0;
++ static u_int32_t iwraps = 0;
++ static u_int32_t owraps = 0;
++
+ struct ifpppstatsreq req;
+
+ memset (&req, 0, sizeof (req));
+@@ -1426,7 +1444,262 @@ get_ppp_stats(int u, struct pppd_stats *
+ stats->bytes_out = req.stats.p.ppp_obytes;
+ stats->pkts_in = req.stats.p.ppp_ipackets;
+ stats->pkts_out = req.stats.p.ppp_opackets;
++
++ if (stats->bytes_in < previbytes)
++ ++iwraps;
++ if (stats->bytes_out < prevobytes)
++ ++owraps;
++
++ previbytes = stats->bytes_in;
++ prevobytes = stats->bytes_out;
++
++ stats->bytes_in += (uint64_t)iwraps << 32;
++ stats->bytes_out += (uint64_t)owraps << 32;
++
++ return 1;
++}
++
++/********************************************************************
++ * get_ppp_stats_rtnetlink - return statistics for the link, using rtnetlink
++ * This provides native 64-bit counters.
++ */
++static int
++get_ppp_stats_rtnetlink(int u, struct pppd_stats *stats)
++{
++ static int rtnl_fd = -1;
++
++ struct sockaddr_nl nladdr;
++ struct {
++ struct nlmsghdr nlh;
++ struct if_stats_msg ifsm;
++ } nlreq;
++ struct nlresp {
++ struct nlmsghdr nlh;
++ union {
++ struct {
++ struct nlmsgerr nlerr;
++ char __end_err[0];
++ };
++ struct {
++ struct rtmsg rth;
++ struct {
++ /* We only case about these first fields from rtnl_link_stats64 */
++ uint64_t rx_packets;
++ uint64_t tx_packets;
++ uint64_t rx_bytes;
++ uint64_t tx_bytes;
++ } stats;
++ char __end_stats[0];
++ };
++ };
++ } nlresp;
++ ssize_t nlresplen;
++ struct iovec iov;
++ struct msghdr msg;
++
++ memset(&nladdr, 0, sizeof(nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ if (rtnl_fd < 0) {
++ rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
++ if (rtnl_fd < 0) {
++ error("get_ppp_stats_rtnetlink: error creating NETLINK socket: %m (line %d)", __LINE__);
++ return 0;
++ }
++
++ if (bind(rtnl_fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
++ error("get_ppp_stats_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
++ goto err;
++ }
++ }
++
++ memset(&nlreq, 0, sizeof(nlreq));
++ nlreq.nlh.nlmsg_len = sizeof(nlreq);
++ nlreq.nlh.nlmsg_type = RTM_GETSTATS;
++ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST;
++
++ nlreq.ifsm.ifindex = if_nametoindex(ifname);
++ nlreq.ifsm.filter_mask = IFLA_STATS_LINK_64;
++
++ memset(&iov, 0, sizeof(iov));
++ iov.iov_base = &nlreq;
++ iov.iov_len = sizeof(nlreq);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_name = &nladdr;
++ msg.msg_namelen = sizeof(nladdr);
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ if (sendmsg(rtnl_fd, &msg, 0) < 0) {
++ error("get_ppp_stats_rtnetlink: sendmsg(RTM_GETSTATS): %m (line %d)", __LINE__);
++ goto err;
++ }
++
++ /* We just need to repoint to IOV ... everything else stays the same */
++ iov.iov_base = &nlresp;
++ iov.iov_len = sizeof(nlresp);
++
++ nlresplen = recvmsg(rtnl_fd, &msg, 0);
++
++ if (nlresplen < 0) {
++ error("get_ppp_stats_rtnetlink: recvmsg(RTM_GETSTATS): %m (line %d)", __LINE__);
++ goto err;
++ }
++
++ if (nlresplen < sizeof(nlresp.nlh)) {
++ error("get_ppp_stats_rtnetlink: Netlink response message was incomplete (line %d)", __LINE__);
++ goto err;
++ }
++
++ if (nlresp.nlh.nlmsg_type == NLMSG_ERROR) {
++ if (nlresplen < offsetof(struct nlresp, __end_err)) {
++ if (kernel_version >= KVERSION(4,7,0))
++ error("get_ppp_stats_rtnetlink: Netlink responded with error: %s (line %d)", strerror(-nlresp.nlerr.error), __LINE__);
++ } else {
++ error("get_ppp_stats_rtnetlink: Netlink responded with an error message, but the nlmsgerr structure is incomplete (line %d).",
++ __LINE__);
++ }
++ goto err;
++ }
++
++ if (nlresp.nlh.nlmsg_type != RTM_NEWSTATS) {
++ error("get_ppp_stats_rtnetlink: Expected RTM_NEWSTATS response, found something else (mlmsg_type %d, line %d)",
++ nlresp.nlh.nlmsg_type, __LINE__);
++ goto err;
++ }
++
++ if (nlresplen < offsetof(struct nlresp, __end_stats)) {
++ error("get_ppp_stats_rtnetlink: Obtained an insufficiently sized rtnl_link_stats64 struct from the kernel (line %d).", __LINE__);
++ goto err;
++ }
++
++ stats->bytes_in = nlresp.stats.rx_bytes;
++ stats->bytes_out = nlresp.stats.tx_bytes;
++ stats->pkts_in = nlresp.stats.rx_packets;
++ stats->pkts_out = nlresp.stats.tx_packets;
++
+ return 1;
++err:
++ close(rtnl_fd);
++ rtnl_fd = -1;
++ return 0;
++}
++
++/********************************************************************
++ * get_ppp_stats_sysfs - return statistics for the link, using the files in sysfs,
++ * this provides native 64-bit counters.
++ */
++static int
++get_ppp_stats_sysfs(int u, struct pppd_stats *stats)
++{
++ char fname[PATH_MAX+1];
++ char buf[21], *err; /* 2^64 < 10^20 */
++ int blen, fd, rlen;
++ unsigned long long val;
++
++ struct {
++ const char* fname;
++ void* ptr;
++ unsigned size;
++ } slist[] = {
++#define statfield(fn, field) { .fname = #fn, .ptr = &stats->field, .size = sizeof(stats->field) }
++ statfield(rx_bytes, bytes_in),
++ statfield(tx_bytes, bytes_out),
++ statfield(rx_packets, pkts_in),
++ statfield(tx_packets, pkts_out),
++#undef statfield
++ };
++
++ blen = snprintf(fname, sizeof(fname), "/sys/class/net/%s/statistics/", ifname);
++ if (blen >= sizeof(fname))
++ return 0; /* ifname max 15, so this should be impossible */
++
++ for (int i = 0; i < sizeof(slist) / sizeof(*slist); ++i) {
++ if (snprintf(fname + blen, sizeof(fname) - blen, "%s", slist[i].fname) >= sizeof(fname) - blen) {
++ fname[blen] = 0;
++ error("sysfs stats: filename %s/%s overflowed PATH_MAX", fname, slist[i].fname);
++ return 0;
++ }
++
++ fd = open(fname, O_RDONLY);
++ if (fd < 0) {
++ error("%s: %m", fname);
++ return 0;
++ }
++
++ rlen = read(fd, buf, sizeof(buf) - 1);
++ close(fd);
++ if (rlen < 0) {
++ error("%s: %m", fname);
++ return 0;
++ }
++ /* trim trailing \n if present */
++ while (rlen > 0 && buf[rlen-1] == '\n')
++ rlen--;
++ buf[rlen] = 0;
++
++ errno = 0;
++ val = strtoull(buf, &err, 10);
++ if (*buf < '0' || *buf > '9' || errno != 0 || *err) {
++ error("string to number conversion error converting %s (from %s) for remaining string %s%s%s",
++ buf, fname, err, errno ? ": " : "", errno ? strerror(errno) : "");
++ return 0;
++ }
++ switch (slist[i].size) {
++#define stattype(type) case sizeof(type): *(type*)slist[i].ptr = (type)val; break
++ stattype(uint64_t);
++ stattype(uint32_t);
++ stattype(uint16_t);
++ stattype(uint8_t);
++#undef stattype
++ default:
++ error("Don't know how to store stats for %s of size %u", slist[i].fname, slist[i].size);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ * Periodic timer function to be used to keep stats up to date in case of ioctl
++ * polling.
++ *
++ * Given the 25s interval this should be fine up to data rates of 1.37Gbps.
++ * If you do change the timer, remember to also bring the get_ppp_stats (which
++ * sets up the initial trigger) as well.
++ */
++static void
++ppp_stats_poller(void* u)
++{
++ struct pppd_stats dummy;
++ get_ppp_stats_ioctl((long)u, &dummy);
++ TIMEOUT(ppp_stats_poller, u, 25);
++}
++
++/********************************************************************
++ * get_ppp_stats - return statistics for the link.
++ */
++int get_ppp_stats(int u, struct pppd_stats *stats)
++{
++ static int (*func)(int, struct pppd_stats*) = NULL;
++
++ if (!func) {
++ if (get_ppp_stats_rtnetlink(u, stats)) {
++ func = get_ppp_stats_rtnetlink;
++ return 1;
++ }
++ if (get_ppp_stats_sysfs(u, stats)) {
++ func = get_ppp_stats_sysfs;
++ return 1;
++ }
++ warn("statistics falling back to ioctl which only supports 32-bit counters");
++ func = get_ppp_stats_ioctl;
++ TIMEOUT(ppp_stats_poller, (void*)(long)u, 25);
++ }
++
++ return func(u, stats);
+ }
+
+ /********************************************************************
diff --git a/package/network/services/ppp/patches/142-pppd-Add-support-for-registering-ppp-interface-via-L.patch b/package/network/services/ppp/patches/142-pppd-Add-support-for-registering-ppp-interface-via-L.patch
new file mode 100644
index 00000000000..9987d3dce9d
--- /dev/null
+++ b/package/network/services/ppp/patches/142-pppd-Add-support-for-registering-ppp-interface-via-L.patch
@@ -0,0 +1,299 @@
+From 4a54e34cf5629f9fed61f0b7d69ee3ba4d874bc6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Sat, 9 Jul 2022 13:40:24 +0200
+Subject: [PATCH] pppd: Add support for registering ppp interface via Linux
+ rtnetlink API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+pppd currently creates ppp network interface via PPPIOCNEWUNIT ioctl API.
+This API creates a new ppp network interface named "ppp<unit_id>". If user
+supply option "ifname" with custom network name then pppd calls SIOCSIFNAME
+ioctl to rename "ppp<unit_id>" to custom name immediately after successful
+PPPIOCNEWUNIT ioctl call. If custom name is already registered then
+SIOCSIFNAME ioctl fails and pppd close current channel (which destroy also
+network interface).
+
+This has side effect that in the first few miliseconds interface has
+different name as what user supplied.
+
+Tools like systemd, udev or NetworkManager are trying to query
+interface attributes based on interface name immediately when new
+network interface is created.
+
+But if interface is renamed immediately after creation then these tools
+fails. For example when running pppd with option "ifname ppp-wan" following
+error is reported by systemd / udev into dmesg log:
+
+ [ 35.718732] PPP generic driver version 2.4.2
+ [ 35.793914] NET: Registered protocol family 24
+ [ 35.889924] systemd-udevd[1852]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
+ [ 35.901450] ppp-wan: renamed from ppp0
+ [ 35.930332] systemd-udevd[1852]: link_config: could not get ethtool features for ppp0
+ [ 35.939473] systemd-udevd[1852]: Could not set offload features of ppp0: No such device
+
+There is an easy way to fix this issue: Use new rtnetlink API.
+
+Via rtnetlink API it is possible to create ppp network interface with
+custom ifname atomically. Just it is not possible to specify custom ppp
+unit id.
+
+So use new rtnetlink API when user requested custom ifname without custom
+ppp unit id. This will avoid system issues with interface renaming as ppp
+interface is directly registered with specified final name.
+
+This has also advantage that if requested interface name already exists
+then pppd fail during registering of networking interface and not during
+renaming network interface which happens after successful registration.
+
+If user supply custom ppp unit id then it is required to use old ioctl API
+as currently it is the only API which allows specifying ppp unit id.
+
+When user does not specify custom ifname stay also with old ioctl API.
+There is currently a bug in kernel which cause that when empty interface is
+specified in rtnetlink message for creating ppp interface then kernel
+creates ppp interface but with pseudo-random name, not derived from ppp
+unit id. And therefore it is not possible to retrieve what is the name of
+newly created network interface. So when user does not specify interface
+name via "ifname" option (which means that want from kernel to choose some
+"free" interface name) it is needed to use old ioctl API which do it
+correctly for now.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+---
+ pppd/sys-linux.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 192 insertions(+), 2 deletions(-)
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -126,6 +126,11 @@
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/if_link.h>
++
++#ifdef INET6
++#include <linux/if_addr.h>
++#endif
++
+ /* Attempt at retaining compile-support with older than 4.7 kernels, or kernels
+ * where RTM_NEWSTATS isn't defined for whatever reason.
+ */
+@@ -135,16 +140,20 @@
+ #define IFLA_STATS_LINK_64 1
+ #endif
+
+-#ifdef INET6
+-#include <linux/if_addr.h>
+ /* glibc versions prior to 2.24 do not define SOL_NETLINK */
+ #ifndef SOL_NETLINK
+ #define SOL_NETLINK 270
+ #endif
++
+ /* linux kernel versions prior to 4.3 do not define/support NETLINK_CAP_ACK */
+ #ifndef NETLINK_CAP_ACK
+ #define NETLINK_CAP_ACK 10
+ #endif
++
++/* linux kernel versions prior to 4.7 do not define/support IFLA_PPP_DEV_FD */
++#ifndef IFLA_PPP_MAX
++/* IFLA_PPP_DEV_FD is declared as enum when IFLA_PPP_MAX is defined */
++#define IFLA_PPP_DEV_FD 1
+ #endif
+
+ #include "pppd.h"
+@@ -657,6 +666,160 @@ void generic_disestablish_ppp(int dev_fd
+ }
+
+ /*
++ * make_ppp_unit_rtnetlink - register a new ppp network interface for ppp_dev_fd
++ * with specified req_ifname via rtnetlink. Interface name req_ifname must not
++ * be empty. Custom ppp unit id req_unit is ignored and kernel choose some free.
++ */
++static int make_ppp_unit_rtnetlink(void)
++{
++ struct {
++ struct nlmsghdr nlh;
++ struct ifinfomsg ifm;
++ struct {
++ struct rtattr rta;
++ char ifname[IFNAMSIZ];
++ } ifn;
++ struct {
++ struct rtattr rta;
++ struct {
++ struct rtattr rta;
++ char ifkind[sizeof("ppp")];
++ } ifik;
++ struct {
++ struct rtattr rta;
++ struct {
++ struct rtattr rta;
++ union {
++ int ppp_dev_fd;
++ } ppp;
++ } ifdata[1];
++ } ifid;
++ } ifli;
++ } nlreq;
++ struct {
++ struct nlmsghdr nlh;
++ struct nlmsgerr nlerr;
++ } nlresp;
++ struct sockaddr_nl nladdr;
++ struct iovec iov;
++ struct msghdr msg;
++ ssize_t nlresplen;
++ int one;
++ int fd;
++
++ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
++ if (fd < 0) {
++ error("make_ppp_unit_rtnetlink: socket(NETLINK_ROUTE): %m (line %d)", __LINE__);
++ return 0;
++ }
++
++ /* Tell kernel to not send to us payload of acknowledgment error message. */
++ one = 1;
++ setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
++
++ memset(&nladdr, 0, sizeof(nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
++ error("make_ppp_unit_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
++ close(fd);
++ return 0;
++ }
++
++ memset(&nlreq, 0, sizeof(nlreq));
++ nlreq.nlh.nlmsg_len = sizeof(nlreq);
++ nlreq.nlh.nlmsg_type = RTM_NEWLINK;
++ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
++ nlreq.ifm.ifi_family = AF_UNSPEC;
++ nlreq.ifm.ifi_type = ARPHRD_NETROM;
++ nlreq.ifn.rta.rta_len = sizeof(nlreq.ifn);
++ nlreq.ifn.rta.rta_type = IFLA_IFNAME;
++ strlcpy(nlreq.ifn.ifname, req_ifname, sizeof(nlreq.ifn.ifname));
++ nlreq.ifli.rta.rta_len = sizeof(nlreq.ifli);
++ nlreq.ifli.rta.rta_type = IFLA_LINKINFO;
++ nlreq.ifli.ifik.rta.rta_len = sizeof(nlreq.ifli.ifik);
++ nlreq.ifli.ifik.rta.rta_type = IFLA_INFO_KIND;
++ strcpy(nlreq.ifli.ifik.ifkind, "ppp");
++ nlreq.ifli.ifid.rta.rta_len = sizeof(nlreq.ifli.ifid);
++ nlreq.ifli.ifid.rta.rta_type = IFLA_INFO_DATA;
++ nlreq.ifli.ifid.ifdata[0].rta.rta_len = sizeof(nlreq.ifli.ifid.ifdata[0]);
++ nlreq.ifli.ifid.ifdata[0].rta.rta_type = IFLA_PPP_DEV_FD;
++ nlreq.ifli.ifid.ifdata[0].ppp.ppp_dev_fd = ppp_dev_fd;
++
++ memset(&nladdr, 0, sizeof(nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ memset(&iov, 0, sizeof(iov));
++ iov.iov_base = &nlreq;
++ iov.iov_len = sizeof(nlreq);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_name = &nladdr;
++ msg.msg_namelen = sizeof(nladdr);
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ if (sendmsg(fd, &msg, 0) < 0) {
++ error("make_ppp_unit_rtnetlink: sendmsg(RTM_NEWLINK/NLM_F_CREATE): %m (line %d)", __LINE__);
++ close(fd);
++ return 0;
++ }
++
++ memset(&iov, 0, sizeof(iov));
++ iov.iov_base = &nlresp;
++ iov.iov_len = sizeof(nlresp);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_name = &nladdr;
++ msg.msg_namelen = sizeof(nladdr);
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ nlresplen = recvmsg(fd, &msg, 0);
++
++ if (nlresplen < 0) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): %m (line %d)", __LINE__);
++ close(fd);
++ return 0;
++ }
++
++ close(fd);
++
++ if (nladdr.nl_family != AF_NETLINK) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not a netlink packet (line %d)", __LINE__);
++ return 0;
++ }
++
++ if ((size_t)nlresplen < sizeof(nlresp) || nlresp.nlh.nlmsg_len < sizeof(nlresp)) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Acknowledgment netlink packet too short (line %d)", __LINE__);
++ return 0;
++ }
++
++ /* acknowledgment packet for NLM_F_ACK is NLMSG_ERROR */
++ if (nlresp.nlh.nlmsg_type != NLMSG_ERROR) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not an acknowledgment netlink packet (line %d)", __LINE__);
++ return 0;
++ }
++
++ /* error == 0 indicates success, negative value is errno code */
++ if (nlresp.nlerr.error != 0) {
++ /*
++ * Linux kernel versions prior to 4.7 do not support creating ppp
++ * interfaces via rtnetlink API and therefore error response is
++ * expected. On older kernel versions do not show this error message.
++ * When error is different than EEXIST then pppd tries to fallback to
++ * the old ioctl method.
++ */
++ errno = (nlresp.nlerr.error < 0) ? -nlresp.nlerr.error : EINVAL;
++ if (kernel_version >= KVERSION(4,7,0))
++ error("Couldn't create ppp interface %s: %m", req_ifname);
++ return 0;
++ }
++
++ return 1;
++}
++
++/*
+ * make_ppp_unit - make a new ppp unit for ppp_dev_fd.
+ * Assumes new_style_driver.
+ */
+@@ -676,6 +839,33 @@ static int make_ppp_unit(void)
+ || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("Couldn't set /dev/ppp to nonblock: %m");
+
++ /*
++ * Via rtnetlink it is possible to create ppp network interface with
++ * custom ifname atomically. But it is not possible to specify custom
++ * ppp unit id.
++ *
++ * Tools like systemd, udev or NetworkManager are trying to query
++ * interface attributes based on interface name immediately when new
++ * network interface is created. And therefore immediate interface
++ * renaming is causing issues.
++ *
++ * So use rtnetlink API only when user requested custom ifname. It will
++ * avoid system issues with interface renaming.
++ */
++ if (req_unit == -1 && req_ifname[0] != '\0' && kernel_version >= KVERSION(2,1,16)) {
++ if (make_ppp_unit_rtnetlink()) {
++ if (ioctl(ppp_dev_fd, PPPIOCGUNIT, &ifunit))
++ fatal("Couldn't retrieve PPP unit id: %m");
++ return 0;
++ }
++ /*
++ * If interface with requested name already exist return error
++ * otherwise fallback to old ioctl method.
++ */
++ if (errno == EEXIST)
++ return -1;
++ }
++
+ ifunit = req_unit;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ if (x < 0 && req_unit >= 0 && errno == EEXIST) {
diff --git a/package/network/services/ppp/patches/143-pppd-Workaround-for-generating-ppp-unit-id-on-Linux-.patch b/package/network/services/ppp/patches/143-pppd-Workaround-for-generating-ppp-unit-id-on-Linux-.patch
new file mode 100644
index 00000000000..abe559e0748
--- /dev/null
+++ b/package/network/services/ppp/patches/143-pppd-Workaround-for-generating-ppp-unit-id-on-Linux-.patch
@@ -0,0 +1,59 @@
+From 44609bfc974bdafc0316d069aabf5e2903efa805 Mon Sep 17 00:00:00 2001
+From: pali <7141871+pali@users.noreply.github.com>
+Date: Tue, 9 Aug 2022 11:20:15 +0200
+Subject: [PATCH] pppd: Workaround for generating ppp unit id on Linux (#355)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Linux kernel has nasty bug / feature. If PPPIOCNEWUNIT is called with
+negative ppp unit id (which is default option when command line argument
+"unit" is not specified; and tells kernel to choose some free ppp unit id)
+and the lowest unused/free ppp unit id is present in some existing network
+interface name prefixed by "ppp" string then this PPPIOCNEWUNIT ioctl
+fails. In this case kernel is basically unable to create a new ppp
+interface via PPPIOCNEWUNIT ioctl when user does not specify some unused
+and non-conflicted unit id.
+
+Linux kernel should be fixed to choose usable ppp unit id when was
+requested via PPPIOCNEWUNIT parameter -1.
+
+Until this happens, add a workaround for pppd to help choosing some random
+ppp unit id when kernel returns this error.
+
+Simple test case (run on system when there is no ppp interface):
+
+ sudo ./pppd ifname ppp1 nodefaultroute noauth nolock local nodetach pty "./pppd nodefaultroute noauth nolock local nodetach notty"
+
+Second pppd process without this patch prints into syslog following error:
+
+ pppd 2.4.10-dev started by pali, uid 0
+ Couldn't create new ppp unit: File exists
+ Exit.
+
+With this patch it falls back to random ppp unit id and succeeds:
+
+ pppd 2.4.10-dev started by pali, uid 0
+ Using interface ppp1361
+ Connect: ppp1361 <--> /dev/pts/14
+ ...
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+---
+ pppd/sys-linux.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -873,6 +873,11 @@ static int make_ppp_unit(void)
+ ifunit = -1;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ }
++ if (x < 0 && errno == EEXIST) {
++ srand(time(NULL) * getpid());
++ ifunit = rand() % 10000;
++ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
++ }
+ if (x < 0)
+ error("Couldn't create new ppp unit: %m");
+
diff --git a/package/network/services/ppp/patches/144-pppd-Retry-registering-interface-when-on-rtnetlink-E.patch b/package/network/services/ppp/patches/144-pppd-Retry-registering-interface-when-on-rtnetlink-E.patch
new file mode 100644
index 00000000000..26c1e34683a
--- /dev/null
+++ b/package/network/services/ppp/patches/144-pppd-Retry-registering-interface-when-on-rtnetlink-E.patch
@@ -0,0 +1,218 @@
+From 089687fbcc6524809ae9f4b2f8145fe3c2a91147 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Sat, 7 Aug 2021 19:48:01 +0200
+Subject: [PATCH] pppd: Retry registering interface when on rtnetlink -EBUSY
+ error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Due to workaround in kernel module ppp_generic.ko in function
+ppp_nl_newlink(), kernel may return -EBUSY error to prevent possible
+mutex deadlock. In this case userspace needs to retry its request.
+
+Proper way would be to fix kernel module to order requests and mutex
+locking, so prevent deadlock in kernel and so never return this error to
+userspace. Until it happens we need retry code in userspace.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+[ backport to ppp 2.4.9 ]
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+---
+ pppd/sys-linux.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -707,99 +707,101 @@ static int make_ppp_unit_rtnetlink(void)
+ int one;
+ int fd;
+
+- fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+- if (fd < 0) {
+- error("make_ppp_unit_rtnetlink: socket(NETLINK_ROUTE): %m (line %d)", __LINE__);
+- return 0;
+- }
+-
+- /* Tell kernel to not send to us payload of acknowledgment error message. */
+- one = 1;
+- setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
++ do {
++ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
++ if (fd < 0) {
++ error("make_ppp_unit_rtnetlink: socket(NETLINK_ROUTE): %m (line %d)", __LINE__);
++ return 0;
++ }
++
++ /* Tell kernel to not send to us payload of acknowledgment error message. */
++ one = 1;
++ setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
++
++ memset(&nladdr, 0, sizeof(nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
++ error("make_ppp_unit_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
++ close(fd);
++ return 0;
++ }
++
++ memset(&nlreq, 0, sizeof(nlreq));
++ nlreq.nlh.nlmsg_len = sizeof(nlreq);
++ nlreq.nlh.nlmsg_type = RTM_NEWLINK;
++ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
++ nlreq.ifm.ifi_family = AF_UNSPEC;
++ nlreq.ifm.ifi_type = ARPHRD_NETROM;
++ nlreq.ifn.rta.rta_len = sizeof(nlreq.ifn);
++ nlreq.ifn.rta.rta_type = IFLA_IFNAME;
++ strlcpy(nlreq.ifn.ifname, req_ifname, sizeof(nlreq.ifn.ifname));
++ nlreq.ifli.rta.rta_len = sizeof(nlreq.ifli);
++ nlreq.ifli.rta.rta_type = IFLA_LINKINFO;
++ nlreq.ifli.ifik.rta.rta_len = sizeof(nlreq.ifli.ifik);
++ nlreq.ifli.ifik.rta.rta_type = IFLA_INFO_KIND;
++ strcpy(nlreq.ifli.ifik.ifkind, "ppp");
++ nlreq.ifli.ifid.rta.rta_len = sizeof(nlreq.ifli.ifid);
++ nlreq.ifli.ifid.rta.rta_type = IFLA_INFO_DATA;
++ nlreq.ifli.ifid.ifdata[0].rta.rta_len = sizeof(nlreq.ifli.ifid.ifdata[0]);
++ nlreq.ifli.ifid.ifdata[0].rta.rta_type = IFLA_PPP_DEV_FD;
++ nlreq.ifli.ifid.ifdata[0].ppp.ppp_dev_fd = ppp_dev_fd;
++
++ memset(&nladdr, 0, sizeof(nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ memset(&iov, 0, sizeof(iov));
++ iov.iov_base = &nlreq;
++ iov.iov_len = sizeof(nlreq);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_name = &nladdr;
++ msg.msg_namelen = sizeof(nladdr);
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ if (sendmsg(fd, &msg, 0) < 0) {
++ error("make_ppp_unit_rtnetlink: sendmsg(RTM_NEWLINK/NLM_F_CREATE): %m (line %d)", __LINE__);
++ close(fd);
++ return 0;
++ }
++
++ memset(&iov, 0, sizeof(iov));
++ iov.iov_base = &nlresp;
++ iov.iov_len = sizeof(nlresp);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_name = &nladdr;
++ msg.msg_namelen = sizeof(nladdr);
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ nlresplen = recvmsg(fd, &msg, 0);
++
++ if (nlresplen < 0) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): %m (line %d)", __LINE__);
++ close(fd);
++ return 0;
++ }
+
+- memset(&nladdr, 0, sizeof(nladdr));
+- nladdr.nl_family = AF_NETLINK;
+-
+- if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
+- error("make_ppp_unit_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
+ close(fd);
+- return 0;
+- }
+-
+- memset(&nlreq, 0, sizeof(nlreq));
+- nlreq.nlh.nlmsg_len = sizeof(nlreq);
+- nlreq.nlh.nlmsg_type = RTM_NEWLINK;
+- nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
+- nlreq.ifm.ifi_family = AF_UNSPEC;
+- nlreq.ifm.ifi_type = ARPHRD_NETROM;
+- nlreq.ifn.rta.rta_len = sizeof(nlreq.ifn);
+- nlreq.ifn.rta.rta_type = IFLA_IFNAME;
+- strlcpy(nlreq.ifn.ifname, req_ifname, sizeof(nlreq.ifn.ifname));
+- nlreq.ifli.rta.rta_len = sizeof(nlreq.ifli);
+- nlreq.ifli.rta.rta_type = IFLA_LINKINFO;
+- nlreq.ifli.ifik.rta.rta_len = sizeof(nlreq.ifli.ifik);
+- nlreq.ifli.ifik.rta.rta_type = IFLA_INFO_KIND;
+- strcpy(nlreq.ifli.ifik.ifkind, "ppp");
+- nlreq.ifli.ifid.rta.rta_len = sizeof(nlreq.ifli.ifid);
+- nlreq.ifli.ifid.rta.rta_type = IFLA_INFO_DATA;
+- nlreq.ifli.ifid.ifdata[0].rta.rta_len = sizeof(nlreq.ifli.ifid.ifdata[0]);
+- nlreq.ifli.ifid.ifdata[0].rta.rta_type = IFLA_PPP_DEV_FD;
+- nlreq.ifli.ifid.ifdata[0].ppp.ppp_dev_fd = ppp_dev_fd;
+-
+- memset(&nladdr, 0, sizeof(nladdr));
+- nladdr.nl_family = AF_NETLINK;
+-
+- memset(&iov, 0, sizeof(iov));
+- iov.iov_base = &nlreq;
+- iov.iov_len = sizeof(nlreq);
+-
+- memset(&msg, 0, sizeof(msg));
+- msg.msg_name = &nladdr;
+- msg.msg_namelen = sizeof(nladdr);
+- msg.msg_iov = &iov;
+- msg.msg_iovlen = 1;
+-
+- if (sendmsg(fd, &msg, 0) < 0) {
+- error("make_ppp_unit_rtnetlink: sendmsg(RTM_NEWLINK/NLM_F_CREATE): %m (line %d)", __LINE__);
+- close(fd);
+- return 0;
+- }
+-
+- memset(&iov, 0, sizeof(iov));
+- iov.iov_base = &nlresp;
+- iov.iov_len = sizeof(nlresp);
+-
+- memset(&msg, 0, sizeof(msg));
+- msg.msg_name = &nladdr;
+- msg.msg_namelen = sizeof(nladdr);
+- msg.msg_iov = &iov;
+- msg.msg_iovlen = 1;
+-
+- nlresplen = recvmsg(fd, &msg, 0);
+-
+- if (nlresplen < 0) {
+- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): %m (line %d)", __LINE__);
+- close(fd);
+- return 0;
+- }
+-
+- close(fd);
+
+- if (nladdr.nl_family != AF_NETLINK) {
+- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not a netlink packet (line %d)", __LINE__);
+- return 0;
+- }
+-
+- if ((size_t)nlresplen < sizeof(nlresp) || nlresp.nlh.nlmsg_len < sizeof(nlresp)) {
+- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Acknowledgment netlink packet too short (line %d)", __LINE__);
+- return 0;
+- }
+-
+- /* acknowledgment packet for NLM_F_ACK is NLMSG_ERROR */
+- if (nlresp.nlh.nlmsg_type != NLMSG_ERROR) {
+- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not an acknowledgment netlink packet (line %d)", __LINE__);
+- return 0;
+- }
++ if (nladdr.nl_family != AF_NETLINK) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not a netlink packet (line %d)", __LINE__);
++ return 0;
++ }
++
++ if ((size_t)nlresplen < sizeof(nlresp) || nlresp.nlh.nlmsg_len < sizeof(nlresp)) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Acknowledgment netlink packet too short (line %d)", __LINE__);
++ return 0;
++ }
++
++ /* acknowledgment packet for NLM_F_ACK is NLMSG_ERROR */
++ if (nlresp.nlh.nlmsg_type != NLMSG_ERROR) {
++ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not an acknowledgment netlink packet (line %d)", __LINE__);
++ return 0;
++ }
++ } while (nlresp.nlerr.error == -EBUSY);
+
+ /* error == 0 indicates success, negative value is errno code */
+ if (nlresp.nlerr.error != 0) {
diff --git a/package/network/services/ppp/patches/208-fix_status_code.patch b/package/network/services/ppp/patches/208-fix_status_code.patch
index 54e6c45e149..1d991e79490 100644
--- a/package/network/services/ppp/patches/208-fix_status_code.patch
+++ b/package/network/services/ppp/patches/208-fix_status_code.patch
@@ -12,7 +12,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/main.c
+++ b/pppd/main.c
-@@ -1034,7 +1034,8 @@ get_input(void)
+@@ -1035,7 +1035,8 @@ get_input(void)
}
notice("Modem hangup");
hungup = 1;
diff --git a/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch b/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch
index 0c4d7ea9d6c..0ae84ae1ed9 100644
--- a/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch
+++ b/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch
@@ -119,7 +119,7 @@ Signed-off-by: George Kashperko <george@znau.edu.ua>
&& memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
-@@ -706,6 +706,16 @@ void cfg_bundle(int mrru, int mtru, int
+@@ -923,6 +923,16 @@ void cfg_bundle(int mrru, int mtru, int
add_fd(ppp_dev_fd);
}
@@ -136,7 +136,7 @@ Signed-off-by: George Kashperko <george@znau.edu.ua>
/*
* make_new_bundle - create a new PPP unit (i.e. a bundle)
* and connect our channel to it. This should only get called
-@@ -724,6 +734,8 @@ void make_new_bundle(int mrru, int mtru,
+@@ -941,6 +951,8 @@ void make_new_bundle(int mrru, int mtru,
/* set the mrru and flags */
cfg_bundle(mrru, mtru, rssn, tssn);
diff --git a/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch b/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
index 6ccc4507b2b..3d2a815dbd9 100644
--- a/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
+++ b/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
@@ -12,7 +12,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
-@@ -1770,6 +1770,7 @@ int cifdefaultroute (int unit, u_int32_t
+@@ -2248,6 +2248,7 @@ int cifdefaultroute (int unit, u_int32_t
SIN_ADDR(rt.rt_genmask) = 0L;
}
diff --git a/package/network/services/ppp/patches/340-populate_default_gateway.patch b/package/network/services/ppp/patches/340-populate_default_gateway.patch
index 0f965c705d2..64d03fb5c47 100644
--- a/package/network/services/ppp/patches/340-populate_default_gateway.patch
+++ b/package/network/services/ppp/patches/340-populate_default_gateway.patch
@@ -13,7 +13,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
-@@ -1720,6 +1720,9 @@ int sifdefaultroute (int unit, u_int32_t
+@@ -2198,6 +2198,9 @@ int sifdefaultroute (int unit, u_int32_t
memset (&rt, 0, sizeof (rt));
SET_SA_FAMILY (rt.rt_dst, AF_INET);
@@ -23,7 +23,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
rt.rt_dev = ifname;
rt.rt_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
-@@ -1728,7 +1731,7 @@ int sifdefaultroute (int unit, u_int32_t
+@@ -2206,7 +2209,7 @@ int sifdefaultroute (int unit, u_int32_t
SIN_ADDR(rt.rt_genmask) = 0L;
}
diff --git a/package/network/services/ppp/patches/400-simplify_kernel_checks.patch b/package/network/services/ppp/patches/400-simplify_kernel_checks.patch
index 3c720483627..9d0ea9a0b84 100644
--- a/package/network/services/ppp/patches/400-simplify_kernel_checks.patch
+++ b/package/network/services/ppp/patches/400-simplify_kernel_checks.patch
@@ -10,7 +10,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
-@@ -206,7 +206,7 @@ static int driver_is_old = 0;
+@@ -235,7 +235,7 @@ static int driver_is_old = 0;
static int restore_term = 0; /* 1 => we've munged the terminal */
static struct termios inittermios; /* Initial TTY termios */
@@ -19,7 +19,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
static char loop_name[20];
static unsigned char inbuf[512]; /* buffer for chars read from loopback */
-@@ -225,8 +225,8 @@ static int looped; /* 1 if using loop
+@@ -254,8 +254,8 @@ static int looped; /* 1 if using loop
static int link_mtu; /* mtu for the link (not bundle) */
static struct utsname utsname; /* for the kernel version */
@@ -29,7 +29,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
#define MAX_IFS 100
-@@ -1455,11 +1455,12 @@ int ccp_fatal_error (int unit)
+@@ -1933,11 +1933,12 @@ int ccp_fatal_error (int unit)
*
* path_to_procfs - find the path to the proc file system mount point
*/
@@ -44,7 +44,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
struct mntent *mntent;
FILE *fp;
-@@ -1481,6 +1482,7 @@ static char *path_to_procfs(const char *
+@@ -1959,6 +1960,7 @@ static char *path_to_procfs(const char *
fclose (fp);
}
}
@@ -52,7 +52,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
strlcpy(proc_path + proc_path_len, tail,
sizeof(proc_path) - proc_path_len);
-@@ -2365,15 +2367,19 @@ int ppp_available(void)
+@@ -2843,15 +2845,19 @@ int ppp_available(void)
int my_version, my_modification, my_patch;
int osmaj, osmin, ospatch;
@@ -72,7 +72,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
/* XXX should get from driver */
driver_version = 2;
-@@ -2433,6 +2439,7 @@ int ppp_available(void)
+@@ -2911,6 +2917,7 @@ int ppp_available(void)
if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
ok = 0;
@@ -80,7 +80,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
/*
* This is the PPP device. Validate the version of the driver at this
-@@ -3106,6 +3113,7 @@ get_pty(int *master_fdp, int *slave_fdp,
+@@ -3592,6 +3599,7 @@ get_pty(int *master_fdp, int *slave_fdp,
}
#endif /* TIOCGPTN */
@@ -88,7 +88,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
if (sfd < 0) {
/* the old way - scan through the pty name space */
for (i = 0; i < 64; ++i) {
-@@ -3124,6 +3132,7 @@ get_pty(int *master_fdp, int *slave_fdp,
+@@ -3610,6 +3618,7 @@ get_pty(int *master_fdp, int *slave_fdp,
}
}
}
diff --git a/package/network/services/ppp/patches/401-no_record_file.patch b/package/network/services/ppp/patches/401-no_record_file.patch
index 78442606851..0304f36fe2b 100644
--- a/package/network/services/ppp/patches/401-no_record_file.patch
+++ b/package/network/services/ppp/patches/401-no_record_file.patch
@@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/pppd.h
+++ b/pppd/pppd.h
-@@ -317,7 +317,6 @@ extern int holdoff; /* Dead time before
+@@ -318,7 +318,6 @@ extern int holdoff; /* Dead time before
extern bool holdoff_specified; /* true if user gave a holdoff value */
extern bool notty; /* Stdin/out is not a tty */
extern char *pty_socket; /* Socket to connect to pty */
diff --git a/package/network/services/ppp/patches/403-no_wtmp.patch b/package/network/services/ppp/patches/403-no_wtmp.patch
index 772620ed722..90c2a8208a5 100644
--- a/package/network/services/ppp/patches/403-no_wtmp.patch
+++ b/package/network/services/ppp/patches/403-no_wtmp.patch
@@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
-@@ -2503,6 +2503,7 @@ int ppp_available(void)
+@@ -2981,6 +2981,7 @@ int ppp_available(void)
void logwtmp (const char *line, const char *name, const char *host)
{
@@ -15,7 +15,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
struct utmp ut, *utp;
pid_t mypid = getpid();
#if __GLIBC__ < 2
-@@ -2568,6 +2569,7 @@ void logwtmp (const char *line, const ch
+@@ -3046,6 +3047,7 @@ void logwtmp (const char *line, const ch
close (wtmp);
}
#endif
diff --git a/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch b/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch
index b9b6f0e593b..8bed425a5b3 100644
--- a/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch
+++ b/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch
@@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/main.c
+++ b/pppd/main.c
-@@ -866,14 +866,17 @@ struct protocol_list {
+@@ -867,14 +867,17 @@ struct protocol_list {
const char *name;
} protocol_list[] = {
{ 0x21, "IP" },
@@ -25,7 +25,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x33, "Stream Protocol ST-II" },
{ 0x35, "Banyan Vines" },
{ 0x39, "AppleTalk EDDP" },
-@@ -887,8 +890,11 @@ struct protocol_list {
+@@ -888,8 +891,11 @@ struct protocol_list {
{ 0x49, "Serial Data Transport Protocol (PPP-SDTP)" },
{ 0x4b, "SNA over 802.2" },
{ 0x4d, "SNA" },
@@ -37,7 +37,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x53, "Encryption" },
{ 0x55, "Individual Link Encryption" },
{ 0x57, "IPv6" },
-@@ -899,12 +905,15 @@ struct protocol_list {
+@@ -900,12 +906,15 @@ struct protocol_list {
{ 0x65, "RTP IPHC Compressed non-TCP" },
{ 0x67, "RTP IPHC Compressed UDP 8" },
{ 0x69, "RTP IPHC Compressed RTP 8" },
@@ -53,7 +53,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x0203, "IBM Source Routing BPDU" },
{ 0x0205, "DEC LANBridge100 Spanning Tree" },
{ 0x0207, "Cisco Discovery Protocol" },
-@@ -916,15 +925,19 @@ struct protocol_list {
+@@ -917,15 +926,19 @@ struct protocol_list {
{ 0x0231, "Luxcom" },
{ 0x0233, "Sigma Network Systems" },
{ 0x0235, "Apple Client Server Protocol" },
@@ -73,7 +73,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x4001, "Cray Communications Control Protocol" },
{ 0x4003, "CDPD Mobile Network Registration Protocol" },
{ 0x4005, "Expand accelerator protocol" },
-@@ -935,8 +948,10 @@ struct protocol_list {
+@@ -936,8 +949,10 @@ struct protocol_list {
{ 0x4023, "RefTek Protocol" },
{ 0x4025, "Fibre Channel" },
{ 0x4027, "EMIT Protocols" },
@@ -84,7 +84,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x8023, "OSI Network Layer Control Protocol" },
{ 0x8025, "Xerox NS IDP Control Protocol" },
{ 0x8027, "DECnet Phase IV Control Protocol" },
-@@ -945,7 +960,9 @@ struct protocol_list {
+@@ -946,7 +961,9 @@ struct protocol_list {
{ 0x8031, "Bridging NCP" },
{ 0x8033, "Stream Protocol Control Protocol" },
{ 0x8035, "Banyan Vines Control Protocol" },
@@ -94,7 +94,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x803f, "NETBIOS Framing Control Protocol" },
{ 0x8041, "Cisco Systems Control Protocol" },
{ 0x8043, "Ascom Timeplex" },
-@@ -954,18 +971,24 @@ struct protocol_list {
+@@ -955,18 +972,24 @@ struct protocol_list {
{ 0x8049, "Serial Data Control Protocol (PPP-SDCP)" },
{ 0x804b, "SNA over 802.2 Control Protocol" },
{ 0x804d, "SNA Control Protocol" },
@@ -119,7 +119,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x8207, "Cisco Discovery Protocol Control" },
{ 0x8209, "Netcs Twin Routing" },
{ 0x820b, "STP - Control Protocol" },
-@@ -974,24 +997,29 @@ struct protocol_list {
+@@ -975,24 +998,29 @@ struct protocol_list {
{ 0x8281, "MPLSCP" },
{ 0x8285, "IEEE p1284.4 standard - Protocol Control" },
{ 0x8287, "ETSI TETRA TNP1 Control Protocol" },
diff --git a/package/network/services/relayd/Makefile b/package/network/services/relayd/Makefile
index 64a08a96652..aba69399556 100644
--- a/package/network/services/relayd/Makefile
+++ b/package/network/services/relayd/Makefile
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_URL=$(PROJECT_GIT)/project/relayd.git
PKG_SOURCE_PROTO:=git
-PKG_SOURCE_DATE:=2020-04-25
-PKG_SOURCE_VERSION:=f4d759be54ceb37714e9a6ca320d5b50c95e9ce9
-PKG_MIRROR_HASH:=b1ff6e99072867be0975ba0be52ba9da3a876c8b8da893d68301e8238243a51e
+PKG_SOURCE_DATE:=2023-01-28
+PKG_SOURCE_VERSION:=f646ba40489371e69f624f2dee2fc4e19ceec00e
+PKG_MIRROR_HASH:=672d3115728d40ee6897a9f633d269d127496699a7bd45eba11844aa771f2501
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile
index 781512bd994..2a6ad535b41 100644
--- a/package/network/services/uhttpd/Makefile
+++ b/package/network/services/uhttpd/Makefile
@@ -8,19 +8,18 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=uhttpd
-PKG_RELEASE:=2
+PKG_RELEASE:=3
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/uhttpd.git
-PKG_SOURCE_DATE:=2021-03-21
-PKG_SOURCE_VERSION:=15346de8d3ba422002496526ee24c62a3601ab8c
-PKG_MIRROR_HASH:=819424d071ed7c8888f9ca66f679907831becc59a67dd4a5ec521d5fba0a3171
+PKG_SOURCE_DATE:=2023-06-25
+PKG_SOURCE_VERSION:=34a8a74dbdec3c0de38abc1b08f6a73c51263792
+PKG_MIRROR_HASH:=8206885eebed5d1827763bcc5bcf9ca3510ae22b0ad1f6432114f1136c32dde2
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=ISC
PKG_ASLR_PIE_REGULAR:=1
PKG_BUILD_DEPENDS = ustream-ssl
-PKG_CONFIG_DEPENDS:= CONFIG_uhttpd_lua
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
@@ -44,13 +43,13 @@ define Package/uhttpd/description
HTTP daemon.
endef
-define Package/uhttpd/config
- config uhttpd_lua
- depends on PACKAGE_uhttpd-mod-lua
- bool "Enable Integrated Lua interpreter"
- default y
+define Package/uhttpd/conffiles
+/etc/config/uhttpd
+/etc/uhttpd.crt
+/etc/uhttpd.key
endef
+
define Package/uhttpd-mod-lua
$(Package/uhttpd/default)
TITLE+= (Lua plugin)
@@ -73,27 +72,27 @@ define Package/uhttpd-mod-ubus/description
session.* namespace and procedures.
endef
-define Package/uhttpd/conffiles
-/etc/config/uhttpd
-/etc/uhttpd.crt
-/etc/uhttpd.key
+
+define Package/uhttpd-mod-ucode
+ $(Package/uhttpd/default)
+ TITLE+= (ucode plugin)
+ DEPENDS:=uhttpd +libucode
endef
+define Package/uhttpd-mod-ucode/description
+ The ucode plugin adds a CGI-like ucode runtime interface to uHTTPd.
+endef
+
+
ifneq ($(CONFIG_USE_GLIBC),)
TARGET_CFLAGS += -D_DEFAULT_SOURCE
endif
-TARGET_LDFLAGS += -lcrypt
-
-CMAKE_OPTIONS += -DTLS_SUPPORT=on
-
define Package/uhttpd/install
- $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/config $(1)/usr/sbin
$(INSTALL_BIN) ./files/uhttpd.init $(1)/etc/init.d/uhttpd
- $(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/uhttpd.config $(1)/etc/config/uhttpd
$(VERSION_SED_SCRIPT) $(1)/etc/config/uhttpd
- $(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd $(1)/usr/sbin/uhttpd
endef
@@ -108,7 +107,20 @@ define Package/uhttpd-mod-ubus/install
$(INSTALL_DATA) ./files/ubus.default $(1)/etc/uci-defaults/00_uhttpd_ubus
endef
+define Package/uhttpd-mod-ubus/postinst
+#!/bin/sh
+if [ -z "$${IPKG_INSTROOT}" ]; then
+ /etc/init.d/uhttpd reload
+fi
+endef
+
+define Package/uhttpd-mod-ucode/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_ucode.so $(1)/usr/lib/
+endef
+
$(eval $(call BuildPackage,uhttpd))
$(eval $(call BuildPackage,uhttpd-mod-lua))
$(eval $(call BuildPackage,uhttpd-mod-ubus))
+$(eval $(call BuildPackage,uhttpd-mod-ucode))
diff --git a/package/network/services/uhttpd/files/ubus.default b/package/network/services/uhttpd/files/ubus.default
index 474016c1c55..d0a218a0ad9 100644
--- a/package/network/services/uhttpd/files/ubus.default
+++ b/package/network/services/uhttpd/files/ubus.default
@@ -1,17 +1,11 @@
#!/bin/sh
-commit=0
-
if [ -z "$(uci -q get uhttpd.main.ubus_prefix)" ]; then
uci set uhttpd.main.ubus_prefix=/ubus
- commit=1
fi
[ "$(uci -q get uhttpd.main.ubus_socket)" = "/var/run/ubus.sock" ] && {
uci set uhttpd.main.ubus_socket='/var/run/ubus/ubus.sock'
- commit=1
}
-[ "$commit" = 1 ] && uci commit uhttpd && /etc/init.d/uhttpd reload
-
exit 0
diff --git a/package/network/services/uhttpd/files/uhttpd.config b/package/network/services/uhttpd/files/uhttpd.config
index 40ce67fd010..a9b8ff3d15d 100644
--- a/package/network/services/uhttpd/files/uhttpd.config
+++ b/package/network/services/uhttpd/files/uhttpd.config
@@ -57,6 +57,14 @@ config uhttpd main
# matches have precedence over the CGI prefix.
list lua_prefix "/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua"
+ # List of prefix->ucode handler mappings.
+ # Any request to an URL beneath the prefix
+ # will be dispatched to the associated ucode
+ # handler script. Ucode support is disabled when
+ # no handler mappings are specified. Ucode prefix
+ # matches have precedence over the CGI prefix.
+# list ucode_prefix "/ucode/example=/usr/share/example.uc"
+
# Specify the ubus-rpc prefix and socket path.
# option ubus_prefix /ubus
# option ubus_socket /var/run/ubus/ubus.sock
diff --git a/package/network/services/uhttpd/files/uhttpd.init b/package/network/services/uhttpd/files/uhttpd.init
index e7709941c22..c4d0025d699 100755
--- a/package/network/services/uhttpd/files/uhttpd.init
+++ b/package/network/services/uhttpd/files/uhttpd.init
@@ -91,6 +91,18 @@ append_lua_prefix() {
fi
}
+append_ucode_prefix() {
+ local v="$1"
+ local prefix="${v%%=*}"
+ local handler="${v#*=}"
+
+ if [ "$prefix" != "$handler" ] && [ -n "$prefix" ] && [ -f "$handler" ]; then
+ procd_append_param command -o "$prefix" -O "$handler"
+ else
+ echo "Skipping invalid ucode prefix \"$v\"" >&2
+ fi
+}
+
start_instance()
{
UHTTPD_CERT=""
@@ -142,6 +154,9 @@ start_instance()
append_arg "$cfg" ubus_socket "-U"
append_bool "$cfg" ubus_cors "-X" 0
}
+ [ -f /usr/lib/uhttpd_ucode.so ] && {
+ config_list_foreach "$cfg" ucode_prefix append_ucode_prefix
+ }
append_arg "$cfg" script_timeout "-t"
append_arg "$cfg" network_timeout "-T"
append_arg "$cfg" http_keepalive "-k"
@@ -196,16 +211,84 @@ start_instance()
append_bool "$cfg" redirect_https "-q" 0
}
- for file in /etc/uhttpd/*.json; do
+ config_get json_script "$cfg" json_script
+ for file in $json_script; do
[ -s "$file" ] && procd_append_param command -H "$file"
done
procd_close_instance
}
+uhttpd_interfaces()
+{
+ local cfg="$1"
+ local http https listen ips
+
+ config_get http "$cfg" listen_http
+ config_get https "$cfg" listen_https
+ for listen in $http $https; do
+ case "$listen" in
+ "" |\
+ "0.0.0.0:"* |\
+ "[::]:"* )
+ continue
+ ;;
+ *.*.*.*:*)
+ ips="$ips ${listen%%:*}
+"
+ ;;
+ \[*\]:* )
+ listen="${listen:1}"
+ ips="$ips ${listen%%]:*}
+"
+ ;;
+ esac
+ done
+ ips="$( echo "$ips" | sort -u )"
+ echo "$ips"
+}
+
+resolve_iface()
+{
+ local cfg="$1"
+ local ipaddr ipaddrs testip="$2"
+
+ config_get ipaddrs "$cfg" ipaddr
+ for ipaddr in $ipaddrs; do
+ [ "$ipaddr" = "$testip" ] && echo "$cfg"
+ done
+}
+
+get_interface_by_ip()
+{
+ config_load network
+ config_foreach resolve_iface interface "$@"
+}
+
service_triggers()
{
+ local iface ifaces all=0
+
procd_add_reload_trigger "uhttpd"
+ procd_add_raw_trigger acme.renew 5000 /etc/init.d/uhttpd reload
+
+ config_load uhttpd
+ ips="$(config_foreach uhttpd_interfaces uhttpd)"
+ [ -z "$ips" ] && return 0
+
+ for ip in $ips; do
+ iface="$(get_interface_by_ip $ip)"
+ [ -z "$iface" ] && all=1
+ ifaces="$ifaces $iface"
+ done
+
+ if [ "$all" = "1" ]; then
+ procd_add_raw_trigger "interface.*.up" 1000 /etc/init.d/uhttpd start
+ else
+ for iface in $ifaces; do
+ procd_add_raw_trigger "interface.$iface.up" 1000 /etc/init.d/uhttpd start
+ done
+ fi
}
start_service() {
diff --git a/package/network/services/umdns/Makefile b/package/network/services/umdns/Makefile
index a25233ad5ab..5689a6d78d2 100644
--- a/package/network/services/umdns/Makefile
+++ b/package/network/services/umdns/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2014-2021 OpenWrt.org
+# Copyright (C) 2014-2023 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=umdns
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=1
PKG_SOURCE_URL=$(PROJECT_GIT)/project/mdnsd.git
PKG_SOURCE_PROTO:=git
-PKG_SOURCE_DATE:=2021-05-13
-PKG_SOURCE_VERSION:=b777a0b53f7d89ab2a60e3eed7d98036806da9a4
-PKG_MIRROR_HASH:=54992acf7edd32610de7bcb0ea7c58b20f69bf1ac20be69e76abcff41f25e775
+PKG_SOURCE_DATE:=2023-11-21
+PKG_SOURCE_VERSION:=b1e023eda3584da4a5dfbc33016839f977a02040
+PKG_MIRROR_HASH:=e0619afc3b8e1b8a627b35bbe0734746303db02e6d62fd8a3ff047d4fbaa0522
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=LGPL-2.1
@@ -27,7 +27,7 @@ define Package/umdns
SECTION:=net
CATEGORY:=Network
TITLE:=OpenWrt Multicast DNS Daemon
- DEPENDS:=+libubox +libubus +libblobmsg-json
+ DEPENDS:=+libubox +libubus +libblobmsg-json +libudebug
endef
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
diff --git a/package/network/services/umdns/files/umdns.json b/package/network/services/umdns/files/umdns.json
index 5533b7c5121..032b498e680 100644
--- a/package/network/services/umdns/files/umdns.json
+++ b/package/network/services/umdns/files/umdns.json
@@ -6,6 +6,7 @@
"bind",
"brk",
"clock_gettime",
+ "clock_gettime64",
"close",
"connect",
"epoll_create",
@@ -18,8 +19,16 @@
"fcntl",
"fcntl64",
"fstat",
+ "ftruncate",
+ "getdents64",
"getsockname",
+ "getrandom",
"ioctl",
+ "madvise",
+ "mmap",
+ "mmap2",
+ "munmap",
+ "newfstatat",
"open",
"openat",
"pipe",
@@ -37,8 +46,10 @@
"setsockopt",
"sigreturn",
"socket",
+ "statx",
"time",
"uname",
+ "unlinkat",
"write",
"writev"
],
diff --git a/package/network/services/unetd/Makefile b/package/network/services/unetd/Makefile
new file mode 100644
index 00000000000..7d8ed9a144c
--- /dev/null
+++ b/package/network/services/unetd/Makefile
@@ -0,0 +1,113 @@
+#
+# Copyright (C) 2022 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=unetd
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(PROJECT_GIT)/project/unetd.git
+PKG_SOURCE_DATE:=2023-05-31
+PKG_SOURCE_VERSION:=7d3986b7a5a20b9af0dacd053b2657210385e7bb
+PKG_MIRROR_HASH:=07f0a4cbae3e80c6309bb8aa27fcef19fbc56093a9c7e426e0d527227af09429
+
+PKG_LICENSE:=GPL-2.0
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_DEPENDS:=HAS_BPF_TOOLCHAIN:bpf-headers
+
+PKG_BUILD_PARALLEL:=1
+
+PKG_CONFIG_DEPENDS += CONFIG_UNETD_VXLAN_SUPPORT
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+include $(INCLUDE_DIR)/bpf.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/unetd
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=WireGuard based VPN connection manager for OpenWrt
+ DEPENDS:=+libubox +libubus +libblobmsg-json +libnl-tiny +kmod-wireguard +UNETD_VXLAN_SUPPORT:libbpf
+endef
+
+define Package/unetd/config
+ config UNETD_VXLAN_SUPPORT
+ bool "VXLAN support"
+ depends on PACKAGE_unetd
+ depends on HAS_BPF_TOOLCHAIN
+ default y
+
+endef
+
+define Package/unet-dht
+ SECTION:=net
+ CATEGORY:=Network
+ DEPENDS:=unetd
+ TITLE:=unetd DHT discovery support
+endef
+
+define Package/unet-cli
+ SECTION:=net
+ CATEGORY:=Network
+ DEPENDS:=+unetd +ucode +ucode-mod-fs
+ TITLE:=unetd administration command line utility
+endef
+
+TARGET_CFLAGS += \
+ -I$(STAGING_DIR)/usr/include/libnl-tiny \
+ -I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS += \
+ -DLIBNL_LIBS=-lnl-tiny \
+ -DVXLAN_SUPPORT=$(if $(CONFIG_UNETD_VXLAN_SUPPORT),ON,OFF)
+
+ifdef CONFIG_UNETD_VXLAN_SUPPORT
+ define Build/Compile
+ $(call CompileBPF,$(PKG_BUILD_DIR)/mss-bpf.c)
+ $(call Build/Compile/Default,)
+ endef
+endif
+
+define Package/unetd/conffiles
+/etc/unetd
+endef
+
+define Package/unetd/install
+ $(INSTALL_DIR) \
+ $(1)/etc/unetd \
+ $(1)/lib/bpf \
+ $(1)/etc/init.d \
+ $(1)/lib/netifd/proto \
+ $(1)/usr/sbin \
+ $(1)/usr/lib
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libunet.so* $(1)/usr/lib/
+ $(INSTALL_BIN) \
+ $(PKG_INSTALL_DIR)/usr/sbin/unetd \
+ $(PKG_INSTALL_DIR)/usr/sbin/unet-tool \
+ $(1)/usr/sbin/
+ $(if $(CONFIG_UNETD_VXLAN_SUPPORT),$(INSTALL_DATA) $(PKG_BUILD_DIR)/mss-bpf.o $(1)/lib/bpf/mss.o)
+ $(INSTALL_BIN) ./files/unetd.init $(1)/etc/init.d/unetd
+ $(INSTALL_BIN) ./files/unetd.sh $(1)/lib/netifd/proto
+endef
+
+define Package/unet-dht/install
+ $(INSTALL_DIR) \
+ $(1)/etc/init.d \
+ $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/unet-dht $(1)/usr/sbin
+ $(INSTALL_BIN) ./files/unet-dht.init $(1)/etc/init.d/unet-dht
+endef
+
+define Package/unet-cli/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/scripts/unet-cli $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,unetd))
+$(eval $(call BuildPackage,unet-dht))
+$(eval $(call BuildPackage,unet-cli))
diff --git a/package/network/services/unetd/files/unet-dht.init b/package/network/services/unetd/files/unet-dht.init
new file mode 100644
index 00000000000..272626a933e
--- /dev/null
+++ b/package/network/services/unetd/files/unet-dht.init
@@ -0,0 +1,24 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2022 OpenWrt.org
+
+START=19
+
+USE_PROCD=1
+PROG=/usr/sbin/unet-dht
+
+unet_dht_id() {
+ cat \
+ /sys/class/net/eth?/address \
+ /sys/class/ieee80211/phy*/macaddress \
+ /etc/board.json | md5sum | awk '{ print $1 }'
+}
+
+start_service() {
+ mkdir -p /var/run/unetd /etc/unetd
+
+ procd_open_instance
+ procd_set_param command "$PROG" -u /var/run/unetd/socket -n /var/run/unetd/nodes.dat $(unet_dht_id)
+ procd_set_param respawn
+ procd_set_param limits core="unlimited"
+ procd_close_instance
+}
diff --git a/package/network/services/unetd/files/unetd.init b/package/network/services/unetd/files/unetd.init
new file mode 100644
index 00000000000..c1124821ee8
--- /dev/null
+++ b/package/network/services/unetd/files/unetd.init
@@ -0,0 +1,17 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2022 OpenWrt.org
+
+START=19
+
+USE_PROCD=1
+PROG=/usr/sbin/unetd
+
+start_service() {
+ mkdir -p /var/run/unetd /etc/unetd
+
+ procd_open_instance
+ procd_set_param command "$PROG" -h /var/run/unetd/hosts -u /var/run/unetd/socket
+ procd_set_param respawn
+ procd_set_param limits core="unlimited"
+ procd_close_instance
+}
diff --git a/package/network/services/unetd/files/unetd.sh b/package/network/services/unetd/files/unetd.sh
new file mode 100644
index 00000000000..2f0f0c478c7
--- /dev/null
+++ b/package/network/services/unetd/files/unetd.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+[ -x /usr/sbin/unetd ] || exit 0
+
+. /lib/functions.sh
+. /lib/functions/network.sh
+. ../netifd-proto.sh
+
+init_proto "$@"
+
+proto_unet_init_config() {
+ proto_config_add_string device
+ proto_config_add_string type
+ proto_config_add_string auth_key
+ proto_config_add_string key
+ proto_config_add_string file
+ proto_config_add_int keepalive
+ proto_config_add_string domain
+ proto_config_add_boolean dht
+ proto_config_add_array "tunnels:list(string)"
+ proto_config_add_array "connect:list(string)"
+ proto_config_add_array "peer_data:list(string)"
+ no_device=1
+ available=1
+ no_proto_task=1
+}
+
+proto_unet_setup() {
+ local config="$1"
+
+ local device type key file keepalive domain tunnels
+ json_get_vars device type auth_key key file keepalive domain dht
+ json_get_values tunnels tunnels
+ json_get_values connect connect
+ json_get_values peer_data peer_data
+ device="${device:-$config}"
+
+ [ -n "$auth_key" ] && type="${type:-dynamic}"
+ [ -n "$file" ] && type="${type:-file}"
+
+ json_init
+ json_add_string name "$device"
+ json_add_string type "$type"
+ json_add_string interface "$config"
+ json_add_string auth_key "$auth_key"
+ json_add_string key "$key"
+ json_add_string file "$file"
+ [ -n "$keepalive" ] && json_add_int keepalive "$keepalive"
+ [ -n "$dht" ] && json_add_boolean dht "$dht"
+ json_add_string domain "$domain"
+
+ json_add_object tunnels
+ for t in $tunnels; do
+ local ifname="${t%%=*}"
+ local service="${t#*=}"
+ [ -n "$ifname" -a -n "$service" -a "$ifname" != "$t" ] || continue
+ json_add_string "$ifname" "$service"
+ done
+ json_close_object
+
+ json_add_array auth_connect
+ for c in $connect; do
+ json_add_string "" "$c"
+ done
+ json_close_array
+
+ json_add_array peer_data
+ for c in $peer_data; do
+ json_add_string "" "$c"
+ done
+ json_close_array
+
+ ip link del dev "$device" >/dev/null 2>&1
+ ip link add dev "$device" type wireguard || {
+ echo "Could not create wireguard device $device"
+ proto_setup_failed "$config"
+ exit 1
+ }
+
+ ubus call unetd network_add "$(json_dump)"
+}
+
+proto_unet_teardown() {
+ local config="$1"
+ local iface="$2"
+
+ local device
+ json_get_vars device
+ device="${device:-$iface}"
+
+ json_init
+ json_add_string name "$device"
+
+ ip link del dev "$device"
+
+ ubus call unetd network_del "$(json_dump)"
+}
+
+add_protocol unet
diff --git a/package/network/services/ustp/Makefile b/package/network/services/ustp/Makefile
new file mode 100644
index 00000000000..2cdd0337549
--- /dev/null
+++ b/package/network/services/ustp/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2021 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ustp
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL=$(PROJECT_GIT)/project/ustp.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_DATE:=2021-09-21
+PKG_SOURCE_VERSION:=462b3a491347e452c15220861949b1d6371fa59e
+PKG_MIRROR_HASH:=0e96edc983cf437b95874e5715d743f30bb826d8757dc3771ff872ab9cf18f35
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0
+
+PKG_BUILD_FLAGS:=lto
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/ustp
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=OpenWrt STP/RSTP daemon
+ DEPENDS:=+libubox +libubus
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+define Package/ustp/install
+ $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ipkg-install/sbin/* $(1)/sbin/
+ $(INSTALL_BIN) ./files/ustpd.init $(1)/etc/init.d/ustpd
+endef
+
+$(eval $(call BuildPackage,ustp))
diff --git a/package/network/services/ustp/files/ustpd.init b/package/network/services/ustp/files/ustpd.init
new file mode 100644
index 00000000000..9b741fec785
--- /dev/null
+++ b/package/network/services/ustp/files/ustpd.init
@@ -0,0 +1,14 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2021 OpenWrt.org
+
+START=50
+
+USE_PROCD=1
+PROG=/sbin/ustpd
+
+start_service() {
+ procd_open_instance
+ procd_set_param command "$PROG"
+ procd_set_param respawn
+ procd_close_instance
+}
diff --git a/package/network/utils/arptables/Makefile b/package/network/utils/arptables/Makefile
index d1168ae68f0..7f32ed13954 100644
--- a/package/network/utils/arptables/Makefile
+++ b/package/network/utils/arptables/Makefile
@@ -1,40 +1,42 @@
-# Copyright (C) 2006-2016 OpenWrt.org
+# SPDX-License-Identifier: GPL-2.0-only
#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
+# Copyright (C) 2006-2016 OpenWrt.org
#
include $(TOPDIR)/rules.mk
PKG_NAME:=arptables
+PKG_VERSION:=0.0.5
PKG_RELEASE:=1
-PKG_SOURCE_URL:=https://git.netfilter.org/arptables
-PKG_SOURCE_PROTO:=git
-PKG_SOURCE_DATE:=2015-05-20
-PKG_SOURCE_VERSION:=f4ab8f63f11a72f14687a6646d04ae1bae3fa45f
-PKG_MIRROR_HASH:=84bc660be4c9f70be91046acfd87785add930eceab7c543036058e1a9de2e9d9
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://ftp.netfilter.org/pub/arptables
+PKG_HASH:=4f9a0656ce5c90868f551cd4deeb2d04f33899667e1fb2818b64e432fe8f629c
PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
include $(INCLUDE_DIR)/package.mk
-define Package/arptables
+define Package/arptables-legacy
SECTION:=net
CATEGORY:=Network
SUBMENU:=Firewall
TITLE:=ARP firewalling software
DEPENDS:=+kmod-arptables
URL:=https://git.netfilter.org/arptables/
+ PROVIDES:=arptables
+ ALTERNATIVES:=\
+ 200:/usr/sbin/arptables:/usr/sbin/arptables-legacy
endef
MAKE_FLAGS += \
COPT_FLAGS="$(TARGET_CFLAGS) -D__OPTIMIZE__=1" \
KERNEL_DIR="$(LINUX_DIR)"
-define Package/arptables/install
+define Package/arptables-legacy/install
$(INSTALL_DIR) $(1)/usr/sbin
- $(CP) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/sbin/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/arptables-legacy $(1)/usr/sbin/arptables-legacy
endef
-$(eval $(call BuildPackage,arptables))
+$(eval $(call BuildPackage,arptables-legacy))
diff --git a/package/network/utils/bpftool/Makefile b/package/network/utils/bpftool/Makefile
new file mode 100644
index 00000000000..2782a307353
--- /dev/null
+++ b/package/network/utils/bpftool/Makefile
@@ -0,0 +1,99 @@
+#
+# Copyright (C) 2020-2023 Tony Ambardar <itugrok@yahoo.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bpftools
+PKG_VERSION:=7.3.0
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL:=https://github.com/libbpf/bpftool
+PKG_MIRROR_HASH:=c8fe336005019fee4d4fd416ce68a749fb479786dead69d6a0b3b04bcd903b98
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=v7.3.0
+
+PKG_MAINTAINER:=Tony Ambardar <itugrok@yahoo.com>
+
+PKG_BUILD_FLAGS:=no-mips16
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/bpftool/Default
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=bpftool - eBPF subsystem utility
+ LICENSE:=GPL-2.0-only OR BSD-2-Clause
+ URL:=http://www.kernel.org
+ DEPENDS:=+libelf
+endef
+
+define Package/bpftool-minimal
+ $(call Package/bpftool/Default)
+ TITLE+= (Minimal)
+ VARIANT:=minimal
+ DEFAULT_VARIANT:=1
+ PROVIDES:=bpftool
+ ALTERNATIVES:=200:/usr/sbin/bpftool:/usr/libexec/bpftool-minimal
+endef
+
+define Package/bpftool-full
+ $(call Package/bpftool/Default)
+ TITLE+= (Full)
+ VARIANT:=full
+ PROVIDES:=bpftool
+ ALTERNATIVES:=300:/usr/sbin/bpftool:/usr/libexec/bpftool-full
+ DEPENDS+= +libbfd +libopcodes
+endef
+
+define Package/bpftool-minimal/description
+ A tool for inspection and simple manipulation of eBPF programs and maps.
+endef
+
+define Package/bpftool-full/description
+ A tool for inspection and simple manipulation of eBPF programs and maps.
+ This full version uses libbfd and libopcodes to support disassembly of
+ eBPF programs and jited code.
+endef
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
+TARGET_LDFLAGS += -Wl,--gc-sections -flto
+
+ifeq ($(BUILD_VARIANT),full)
+ full:=1
+else
+ full:=0
+endif
+
+MAKE_VARS = \
+ EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
+ LDFLAGS="$(TARGET_LDFLAGS)"
+
+MAKE_FLAGS += \
+ OUTPUT="$(PKG_BUILD_DIR)/" \
+ prefix="/usr" \
+ $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \
+ check_feat=0 \
+ feature-clang-bpf-co-re=0 \
+ feature-libbfd=$(full) \
+ feature-llvm=0 \
+ feature-libcap=0 \
+ feature-disassembler-four-args=1 \
+ feature-disassembler-init-styled=1
+
+MAKE_PATH = src
+
+define Package/bpftool-$(BUILD_VARIANT)/install
+ $(INSTALL_DIR) $(1)/usr/libexec
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/bpftool \
+ $(1)/usr/libexec/bpftool-$(BUILD_VARIANT)
+endef
+
+$(eval $(call BuildPackage,bpftool-full))
+$(eval $(call BuildPackage,bpftool-minimal))
diff --git a/package/network/utils/bpftool/patches/001-cflags.patch b/package/network/utils/bpftool/patches/001-cflags.patch
new file mode 100644
index 00000000000..39cef10c72a
--- /dev/null
+++ b/package/network/utils/bpftool/patches/001-cflags.patch
@@ -0,0 +1,10 @@
+--- a/libbpf/src/Makefile
++++ b/libbpf/src/Makefile
+@@ -34,6 +34,7 @@ ALL_CFLAGS := $(INCLUDES)
+
+ SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
+
++CFLAGS = $(EXTRA_CFLAGS)
+ CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89
+ ALL_CFLAGS += $(CFLAGS) \
+ -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \
diff --git a/package/network/utils/bpftool/patches/002-includes.patch b/package/network/utils/bpftool/patches/002-includes.patch
new file mode 100644
index 00000000000..ac1b5fcc228
--- /dev/null
+++ b/package/network/utils/bpftool/patches/002-includes.patch
@@ -0,0 +1,26 @@
+--- a/libbpf/include/linux/list.h
++++ b/libbpf/include/linux/list.h
+@@ -3,6 +3,8 @@
+ #ifndef __LINUX_LIST_H
+ #define __LINUX_LIST_H
+
++#include <linux/types.h>
++
+ #define LIST_HEAD_INIT(name) { &(name), &(name) }
+ #define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -73,10 +73,10 @@ CFLAGS += -W -Wall -Wextra -Wno-unused-p
+ CFLAGS += $(filter-out -Wswitch-enum -Wnested-externs,$(EXTRA_WARNINGS))
+ CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \
+ -I$(or $(OUTPUT),.) \
+- -I$(LIBBPF_INCLUDE) \
+ -I$(srctree)/src/kernel/bpf/ \
+ -I$(srctree)/include \
+- -I$(srctree)/include/uapi
++ -I$(srctree)/include/uapi \
++ -I$(LIBBPF_INCLUDE)
+ ifneq ($(BPFTOOL_VERSION),)
+ CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"'
+ endif
diff --git a/package/network/utils/bpftools/Makefile b/package/network/utils/bpftools/Makefile
deleted file mode 100644
index f044cc81f85..00000000000
--- a/package/network/utils/bpftools/Makefile
+++ /dev/null
@@ -1,169 +0,0 @@
-#
-# Copyright (C) 2020 Tony Ambardar <itugrok@yahoo.com>
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=bpftools
-PKG_VERSION:=5.11.16
-PKG_RELEASE:=1
-
-PKG_SOURCE:=linux-$(PKG_VERSION).tar.xz
-PKG_SOURCE_URL:=@KERNEL/linux/kernel/v5.x
-PKG_HASH:=21163681d130cbce5a6be39019e2c69e44f284855ddd70b1a3bd039249540f43
-
-PKG_MAINTAINER:=Tony Ambardar <itugrok@yahoo.com>
-
-PKG_USE_MIPS16:=0
-PKG_BUILD_PARALLEL:=1
-PKG_INSTALL:=1
-
-LINUX_VERSION:=$(PKG_VERSION)
-LINUX_TLD:=linux-$(LINUX_VERSION)
-
-BPF_FILES:= \
- kernel/bpf scripts tools/Makefile tools/bpf tools/perf/perf-sys.h \
- tools/arch tools/build tools/include tools/lib tools/scripts
-TAR_OPTIONS+= \
- --transform="s;$(LINUX_TLD)/;$(PKG_NAME)-$(PKG_VERSION)/;" \
- $(addprefix $(LINUX_TLD)/,$(BPF_FILES))
-
-include $(INCLUDE_DIR)/package.mk
-include $(INCLUDE_DIR)/nls.mk
-
-define Package/bpftool/Default
- SECTION:=net
- CATEGORY:=Network
- TITLE:=bpftool - eBPF subsystem utility
- LICENSE:=GPL-2.0-only OR BSD-2-Clause
- URL:=http://www.kernel.org
- DEPENDS:=+libelf
-endef
-
-define Package/bpftool-minimal
- $(call Package/bpftool/Default)
- TITLE+= (Minimal)
- VARIANT:=minimal
- DEFAULT_VARIANT:=1
- PROVIDES:=bpftool
- ALTERNATIVES:=200:/usr/sbin/bpftool:/usr/libexec/bpftool-minimal
-endef
-
-define Package/bpftool-full
- $(call Package/bpftool/Default)
- TITLE+= (Full)
- VARIANT:=full
- PROVIDES:=bpftool
- ALTERNATIVES:=300:/usr/sbin/bpftool:/usr/libexec/bpftool-full
- DEPENDS+= +libbfd +libopcodes
-endef
-
-define Package/bpftool-minimal/description
- A tool for inspection and simple manipulation of eBPF programs and maps.
-endef
-
-define Package/bpftool-full/description
- A tool for inspection and simple manipulation of eBPF programs and maps.
- This full version uses libbfd and libopcodes to support disassembly of
- eBPF programs and jited code.
-endef
-
-define Package/libbpf
- SECTION:=libs
- CATEGORY:=Libraries
- TITLE:=libbpf - eBPF helper library
- VARIANT:=lib
- LICENSE:=LGPL-2.1 OR BSD-2-Clause
- ABI_VERSION:=0
- URL:=http://www.kernel.org
- DEPENDS:=+libelf
-endef
-
-define Package/libbpf/description
- libbpf is a library for loading eBPF programs and reading and manipulating eBPF objects from user-space.
-endef
-
-
-# LTO not compatible with DSO using PIC
-ifneq ($(BUILD_VARIANT),lib)
- TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
- TARGET_LDFLAGS += -Wl,--gc-sections
-endif
-
-MAKE_VARS = \
- EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
- LDFLAGS="$(TARGET_LDFLAGS)"
-
-MAKE_FLAGS += \
- BPFTOOL_VERSION="$(LINUX_VERSION)" \
- FEATURES_DUMP="$(PKG_BUILD_DIR)/FEATURE-DUMP.openwrt" \
- OUTPUT="$(PKG_BUILD_DIR)/" \
- prefix="/usr" \
- $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='')
-
-ifeq ($(BUILD_VARIANT),full)
- HAVE_LIBBFD:=1
- HAVE_LIBCAP:=0
- HAVE_CLANG:=0
- MAKE_PATH:=tools/bpf/bpftool
-else ifeq ($(BUILD_VARIANT),minimal)
- HAVE_LIBBFD:=0
- HAVE_LIBCAP:=0
- HAVE_CLANG:=0
- MAKE_PATH:=tools/bpf/bpftool
-else ifeq ($(BUILD_VARIANT),lib)
- HAVE_LIBBFD:=0
- HAVE_LIBCAP:=0
- HAVE_CLANG:=0
- MAKE_PATH:=tools/lib/bpf
-endif
-
-# Perform a "throw-away" make to create a FEATURE-DUMP.* file to edit later.
-# The "//" in the make target is actually needed, very unPOSIXly.
-define Build/Configure
- +$(MAKE_VARS) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/tools/bpf/bpftool \
- $(MAKE_FLAGS) FEATURES_DUMP= $(PKG_BUILD_DIR)//libbpf/libbpf.a
- (cd $(PKG_BUILD_DIR); cat FEATURE-DUMP.bpftool libbpf/FEATURE-DUMP.libbpf \
- | sort | uniq > FEATURE-DUMP.openwrt)
- $(SED) 's/feature-libbfd=1/feature-libbfd=$(HAVE_LIBBFD)/' \
- -e 's/feature-libcap=1/feature-libcap=$(HAVE_LIBCAP)/' \
- -e 's/feature-clang-bpf-co-re=1/feature-clang-bpf-co-re=$(HAVE_CLANG)/' \
- $(PKG_BUILD_DIR)/FEATURE-DUMP.openwrt
-endef
-
-define Build/InstallDev/libbpf
- $(INSTALL_DIR) $(1)/usr/include/bpf
- $(CP) $(PKG_INSTALL_DIR)/usr/include/bpf/*.h $(1)/usr/include/bpf/
- $(INSTALL_DIR) $(1)/usr/lib
- $(CP) $(PKG_INSTALL_DIR)/usr/lib$(LIB_SUFFIX)/libbpf.{a,so*} \
- $(1)/usr/lib/
- $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
- $(CP) $(PKG_INSTALL_DIR)/usr/lib$(LIB_SUFFIX)/pkgconfig/libbpf.pc \
- $(1)/usr/lib/pkgconfig/
- $(SED) 's,/usr/include,$$$${prefix}/include,g' \
- $(1)/usr/lib/pkgconfig/libbpf.pc
- $(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \
- $(1)/usr/lib/pkgconfig/libbpf.pc
-endef
-
-ifeq ($(BUILD_VARIANT),lib)
- Build/InstallDev=$(Build/InstallDev/libbpf)
-endif
-
-define Package/bpftool-$(BUILD_VARIANT)/install
- $(INSTALL_DIR) $(1)/usr/libexec
- $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/bpftool \
- $(1)/usr/libexec/bpftool-$(BUILD_VARIANT)
-endef
-
-define Package/libbpf/install
- $(INSTALL_DIR) $(1)/usr/lib
- $(CP) $(PKG_INSTALL_DIR)/usr/lib$(LIB_SUFFIX)/libbpf.so.* $(1)/usr/lib/
-endef
-
-$(eval $(call BuildPackage,libbpf))
-$(eval $(call BuildPackage,bpftool-full))
-$(eval $(call BuildPackage,bpftool-minimal))
diff --git a/package/network/utils/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch b/package/network/utils/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch
deleted file mode 100644
index 996ffc43ee5..00000000000
--- a/package/network/utils/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From afe3f4c765b17ced23811fe652c7f7adf7a0c0cf Mon Sep 17 00:00:00 2001
-From: Tony Ambardar <Tony.Ambardar@gmail.com>
-Date: Mon, 14 Sep 2020 23:05:26 -0700
-Subject: [PATCH] tools/arch/powerpc: fix EDEADLOCK redefinition errors in
- errno.h
-
-A few archs like powerpc have different errno.h values for macros
-EDEADLOCK and EDEADLK. In code including both libc and linux versions of
-errno.h, this can result in multiple definitions of EDEADLOCK in the
-include chain. Definitions to the same value (e.g. seen with mips) do
-not raise warnings, but on powerpc there are redefinitions changing the
-value, which raise warnings and errors (with "-Werror").
-
-Guard against these redefinitions to avoid build errors like the following,
-first seen cross-compiling libbpf v5.8.9 for powerpc using GCC 8.4.0 with
-musl 1.1.24:
-
- In file included from ../../arch/powerpc/include/uapi/asm/errno.h:5,
- from ../../include/linux/err.h:8,
- from libbpf.c:29:
- ../../include/uapi/asm-generic/errno.h:40: error: "EDEADLOCK" redefined [-Werror]
- #define EDEADLOCK EDEADLK
-
- In file included from toolchain-powerpc_8540_gcc-8.4.0_musl/include/errno.h:10,
- from libbpf.c:26:
- toolchain-powerpc_8540_gcc-8.4.0_musl/include/bits/errno.h:58: note: this is the location of the previous definition
- #define EDEADLOCK 58
-
- cc1: all warnings being treated as errors
- make[5]: *** [target-powerpc_8540_musl/bpftools-5.8.9/tools/build/Makefile.build:97: /home/kodidev/openwrt-project/build_dir/target-powerpc_8540_musl/bpftools-minimal/bpftools-5.8.9//libbpf/staticobjs/libbpf.o] Error 1
-
-Fixes: 95f28190aa01 ("tools include arch: Grab a copy of errno.h for arch's
- supported by perf")
-Fixes: c3617f72036c ("UAPI: (Scripted) Disintegrate arch/powerpc/include/asm")
-
-Reported-by: Rosen Penev <rosenp@gmail.com>
-Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
----
- tools/arch/powerpc/include/uapi/asm/errno.h | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/tools/arch/powerpc/include/uapi/asm/errno.h
-+++ b/tools/arch/powerpc/include/uapi/asm/errno.h
-@@ -2,6 +2,7 @@
- #ifndef _ASM_POWERPC_ERRNO_H
- #define _ASM_POWERPC_ERRNO_H
-
-+#undef EDEADLOCK
- #include <asm-generic/errno.h>
-
- #undef EDEADLOCK
diff --git a/package/network/utils/comgt/Makefile b/package/network/utils/comgt/Makefile
index db5ea574735..429c9386027 100644
--- a/package/network/utils/comgt/Makefile
+++ b/package/network/utils/comgt/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=comgt
PKG_VERSION:=0.32
-PKG_RELEASE:=33
+PKG_RELEASE:=35
PKG_SOURCE:=$(PKG_NAME).$(PKG_VERSION).tgz
PKG_SOURCE_URL:=@SF/comgt
@@ -79,6 +79,7 @@ define Package/comgt/install
$(INSTALL_DATA) ./files/getcarrier.gcom $(1)/etc/gcom/getcarrier.gcom
$(INSTALL_DATA) ./files/getcnum.gcom $(1)/etc/gcom/getcnum.gcom
$(INSTALL_DATA) ./files/getimsi.gcom $(1)/etc/gcom/getimsi.gcom
+ $(INSTALL_DATA) ./files/runcommand.gcom $(1)/etc/gcom/runcommand.gcom
$(INSTALL_DIR) $(1)/etc/hotplug.d/tty
$(INSTALL_CONF) ./files/3g.usb $(1)/etc/hotplug.d/tty/30-3g
$(INSTALL_DIR) $(1)/lib/netifd/proto
@@ -96,7 +97,6 @@ endef
define Package/comgt-ncm/install
$(INSTALL_DIR) $(1)/etc/gcom
$(INSTALL_DATA) ./files/ncm.json $(1)/etc/gcom/ncm.json
- $(INSTALL_DATA) ./files/runcommand.gcom $(1)/etc/gcom/runcommand.gcom
$(INSTALL_DIR) $(1)/lib/netifd/proto
$(INSTALL_BIN) ./files/ncm.sh $(1)/lib/netifd/proto/ncm.sh
endef
diff --git a/package/network/utils/comgt/files/3g.sh b/package/network/utils/comgt/files/3g.sh
index 9220cbf5a0a..42ba894e595 100644
--- a/package/network/utils/comgt/files/3g.sh
+++ b/package/network/utils/comgt/files/3g.sh
@@ -72,6 +72,8 @@ proto_3g_setup() {
*) CODE="2,2";;
esac
export MODE="AT^SYSCFG=${CODE},3FFFFFFF,2,4"
+ elif echo "$cardinfo" | grep -q "MikroTik"; then
+ COMMAND="AT+CFUN=1" gcom -d "$device" -s /etc/gcom/runcommand.gcom || return 1
fi
if [ -n "$pincode" ]; then
diff --git a/package/network/utils/comgt/files/ncm.json b/package/network/utils/comgt/files/ncm.json
index bbdb30c5eeb..5f68b134967 100644
--- a/package/network/utils/comgt/files/ncm.json
+++ b/package/network/utils/comgt/files/ncm.json
@@ -74,5 +74,67 @@
"connect": "AT+CGACT=1,${profile}",
"finalize": "AT+CGDATA=\\\"M-MBIM\\\",${profile},1",
"disconnect": "AT+CGACT=0,${profile}"
+ },
+ "quectel": {
+ "initialize": [
+ "AT+CFUN=1"
+ ],
+ "configure": [
+ "at+qicsgp=${profile},${context_type},\\\"${apn}\\\",\\\"${username}\\\",\\\"${password}\\\",0"
+ ],
+ "modes": {
+ "lte": "AT+QCFG=\\\"nwscanmode\\\",3",
+ "umts": "AT+QCFG=\\\"nwscanmode\\\",2",
+ "gsm": "AT+QCFG=\\\"nwscanmode\\\",1",
+ "auto": "AT+QCFG=\\\"nwscanmode\\\",0"
+ },
+ "connect": "AT+qnetdevctl=1,${profile},1",
+ "disconnect": "AT+qnetdevctl=0,${profile},0"
+ },
+ "\"zte": {
+ "initialize": [
+ "AT+CFUN=1"
+ ],
+ "configure": [
+ "AT+ZGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",\\\"\\\",0,0",
+ "AT+ZGPCOAUTH=${profile},\\\"${username}\\\",\\\"${password}\\\",0"
+ ],
+ "connect": "AT+ZGACT=1,${profile}",
+ "disconnect": "AT+ZGACT=0,${profile}"
+ },
+ "\"marvell\"": {
+ "initialize": [
+ "AT+CFUN=1"
+ ],
+ "configure": [
+ "AT+ZGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",\\\"\\\",0,0",
+ "AT+ZGPCOAUTH=${profile},\\\"${username}\\\",\\\"${password}\\\",0"
+ ],
+ "connect": "AT+ZGACT=1,${profile}",
+ "disconnect": "AT+ZGACT=0,${profile}"
+ },
+ "\"mikrotik\"": {
+ "configure": [
+ "AT+CFUN=4",
+ "AT+ZGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",0",
+ "AT+ZDHCPLEASE=10",
+ "AT+CFUN=1"
+ ],
+ "waitforconnect": "\\\"+ZCONSTAT: 1,${context_type}\\\",\\\"+ZGIPDNS: ${context_type}\\\"",
+ "connect": "AT+ZGACT=1,${context_type}",
+ "finalize": "AT+ZDHCPLEASE=0",
+ "disconnect": "AT+ZGACT=0,1"
+ },
+ "spreadtrum": {
+ "initialize": [
+ "AT+CFUN=1",
+ "AT+CCED=2,8",
+ "AT+SPTTYROUTER=1"
+ ],
+ "configure": [
+ "AT+CGDCONT=${profile},\\\"${pdptype}\\\"${apn:+,\\\"$apn\\\"}"
+ ],
+ "connect": "AT+SPTZCMD=\\\"Y29ubm1hbmN0bCBuZGlzZGlhbCBBVF5ORElTRFVOPSJ1c2IwIiwxLDE=\\\"",
+ "disconnect": "AT+SPTZCMD=\\\"Y29ubm1hbmN0bCBuZGlzZGlhbCBBVF5ORElTRFVOPSJ1c2IwIiwwLDE=\\\""
}
}
diff --git a/package/network/utils/comgt/files/ncm.sh b/package/network/utils/comgt/files/ncm.sh
index 6545091c82f..dec058712d0 100644
--- a/package/network/utils/comgt/files/ncm.sh
+++ b/package/network/utils/comgt/files/ncm.sh
@@ -10,6 +10,7 @@ proto_ncm_init_config() {
no_device=1
available=1
proto_config_add_string "device:device"
+ proto_config_add_string ifname
proto_config_add_string apn
proto_config_add_string auth
proto_config_add_string username
@@ -25,10 +26,12 @@ proto_ncm_init_config() {
proto_ncm_setup() {
local interface="$1"
- local manufacturer initialize setmode connect finalize ifname devname devpath
+ local manufacturer initialize setmode connect finalize devname devpath ifpath
- local device apn auth username password pincode delay mode pdptype profile $PROTO_DEFAULT_OPTIONS
- json_get_vars device apn auth username password pincode delay mode pdptype profile $PROTO_DEFAULT_OPTIONS
+ local device ifname apn auth username password pincode delay mode pdptype profile $PROTO_DEFAULT_OPTIONS
+ json_get_vars device ifname apn auth username password pincode delay mode pdptype profile $PROTO_DEFAULT_OPTIONS
+
+ local context_type
[ "$metric" = "" ] && metric="0"
@@ -37,6 +40,10 @@ proto_ncm_setup() {
pdptype=$(echo "$pdptype" | awk '{print toupper($0)}')
[ "$pdptype" = "IP" -o "$pdptype" = "IPV6" -o "$pdptype" = "IPV4V6" ] || pdptype="IP"
+ [ "$pdptype" = "IPV4V6" ] && context_type=3
+ [ -z "$context_type" -a "$pdptype" = "IPV6" ] && context_type=2
+ [ -n "$context_type" ] || context_type=1
+
[ -n "$ctl_device" ] && device=$ctl_device
[ -n "$device" ] || {
@@ -53,17 +60,25 @@ proto_ncm_setup() {
return 1
}
- devname="$(basename "$device")"
- case "$devname" in
- 'tty'*)
- devpath="$(readlink -f /sys/class/tty/$devname/device)"
- ifname="$( ls "$devpath"/../../*/net )"
- ;;
- *)
- devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
- ifname="$( ls "$devpath"/net )"
- ;;
- esac
+ [ -z "$ifname" ] && {
+ devname="$(basename "$device")"
+ case "$devname" in
+ 'ttyACM'*)
+ devpath="$(readlink -f /sys/class/tty/$devname/device)"
+ ifpath="$devpath/../*/net"
+ ;;
+ 'tty'*)
+ devpath="$(readlink -f /sys/class/tty/$devname/device)"
+ ifpath="$devpath/../../*/net"
+ ;;
+ *)
+ devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
+ ifpath="$devpath/net"
+ ;;
+ esac
+ ifname="$(ls $(ls -1 -d $ifpath | head -n 1))"
+ }
+
[ -n "$ifname" ] || {
echo "The interface could not be found."
proto_notify_error "$interface" NO_IFACE
@@ -71,10 +86,25 @@ proto_ncm_setup() {
return 1
}
- [ -n "$delay" ] && sleep "$delay"
-
- manufacturer=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | awk 'NF && $0 !~ /AT\+CGMI/ { sub(/\+CGMI: /,""); print tolower($1); exit; }')
- [ $? -ne 0 -o -z "$manufacturer" ] && {
+ start=$(date +%s)
+ while true; do
+ manufacturer=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | awk 'NF && $0 !~ /AT\+CGMI/ { sub(/\+CGMI: /,""); print tolower($1); exit; }')
+ [ "$manufacturer" = "error" ] && {
+ manufacturer=""
+ }
+ [ -n "$manufacturer" ] && {
+ break
+ }
+ [ -z "$delay" ] && {
+ break
+ }
+ sleep 1
+ elapsed=$(($(date +%s) - start))
+ [ "$elapsed" -gt "$delay" ] && {
+ break
+ }
+ done
+ [ -z "$manufacturer" ] && {
echo "Failed to get modem information"
proto_notify_error "$interface" GETINFO_FAILED
return 1
diff --git a/package/network/utils/ebtables/Makefile b/package/network/utils/ebtables/Makefile
index 732e9bf2b54..f35b768b437 100644
--- a/package/network/utils/ebtables/Makefile
+++ b/package/network/utils/ebtables/Makefile
@@ -17,33 +17,40 @@ PKG_SOURCE_VERSION:=48cff25dfea5b37e16ba5dc6601e98ab140f5f99
PKG_MIRROR_HASH:=1327cdc3402e5e3056819e4e9b6f9d4a5bfd401f2c4f58447afb2c3c73fc8aac
PKG_LICENSE:=GPL-2.0
+PKG_CPE_ID:=cpe:/a:netfilter:ebtables
include $(INCLUDE_DIR)/package.mk
-define Package/ebtables
+define Package/ebtables-legacy
SECTION:=net
CATEGORY:=Network
SUBMENU:=Firewall
DEPENDS:=+kmod-ebtables
TITLE:=Ethernet bridge firewall administration utility
URL:=http://ebtables.sourceforge.net/
+ PROVIDES:=ebtables
+ ALTERNATIVES:=\
+ 200:/usr/sbin/ebtables:/usr/sbin/ebtables-legacy
endef
-define Package/ebtables-utils
- $(call Package/ebtables)
- DEPENDS += ebtables
+define Package/ebtables-legacy-utils
+ $(call Package/ebtables-legacy)
+ DEPENDS:=ebtables-legacy
TITLE:=ebtables save/restore utilities
+ PROVIDES:=ebtables-utils
+ ALTERNATIVES:=\
+ 200:/usr/sbin/ebtables-restore:/usr/sbin/ebtables-legacy-restore
endef
-define Package/ebtables/description
+define Package/ebtables-legacy/description
The ebtables program is a filtering tool for a bridging firewall. The
filtering is focussed on the Link Layer Ethernet frame fields. Apart
from filtering, it also gives the ability to alter the Ethernet MAC
addresses and implement a brouter.
endef
-define Package/ebtables-utils/description
- $(call Package/ebtables/description)
+define Package/ebtables-legacy-utils/description
+ $(call Package/ebtables-legacy/description)
endef
MAKE_VARS += EXT_LIBSI="$(LIBGCC_S)"
@@ -52,21 +59,22 @@ MAKE_FLAGS += \
CFLAGS="$(TARGET_CFLAGS)" \
LIBDIR="/usr/lib/ebtables"
-define Package/ebtables/install
+define Package/ebtables-legacy/install
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DATA) $(PKG_BUILD_DIR)/ethertypes $(1)/etc/
$(INSTALL_DIR) $(1)/usr/lib/ebtables
$(INSTALL_BIN) $(PKG_BUILD_DIR)/lib*.so $(1)/usr/lib/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/extensions/*.so $(1)/usr/lib/ebtables/
$(INSTALL_DIR) $(1)/usr/sbin
- $(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables $(1)/usr/sbin/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables $(1)/usr/sbin/ebtables-legacy
endef
-define Package/ebtables-utils/install
+define Package/ebtables-legacy-utils/install
$(INSTALL_DIR) $(1)/usr/sbin
- $(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables-save $(1)/usr/sbin/
- $(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables-restore $(1)/usr/sbin/
+ #ebtables-save depends on perl and is just broken
+ #$(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables-save $(1)/usr/sbin/ebtables-legacy-save
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables-restore $(1)/usr/sbin/ebtables-legacy-restore
endef
-$(eval $(call BuildPackage,ebtables))
-$(eval $(call BuildPackage,ebtables-utils))
+$(eval $(call BuildPackage,ebtables-legacy))
+$(eval $(call BuildPackage,ebtables-legacy-utils))
diff --git a/package/network/utils/ethtool/Makefile b/package/network/utils/ethtool/Makefile
index d645cf9bbb1..bc2b13e4234 100644
--- a/package/network/utils/ethtool/Makefile
+++ b/package/network/utils/ethtool/Makefile
@@ -8,23 +8,22 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ethtool
-PKG_VERSION:=5.12
+PKG_VERSION:=6.6
PKG_RELEASE:=1
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@KERNEL/software/network/ethtool
-PKG_HASH:=f5ddfa9c75053d8011b8c8c99ec4e2d3c83cd1972f638692d62e37fa3ef36f07
+PKG_HASH:=833a8493cb9cd5809ab59743092d9a38742c282290800e9626407511bbcebf9e
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
+PKG_CPE_ID:=cpe:/a:kernel:ethtool
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
-PKG_CONFIG_DEPENDS:=CONFIG_ETHTOOL_PRETTY_DUMP
-
include $(INCLUDE_DIR)/package.mk
define Package/ethtool
@@ -32,6 +31,17 @@ define Package/ethtool
CATEGORY:=Network
TITLE:=Display or change ethernet card settings
URL:=http://www.kernel.org/pub/software/network/ethtool/
+ VARIANT:=tiny
+ CONFLICTS:=ethtool-full
+endef
+
+define Package/ethtool-full
+ $(Package/ethtool)
+ TITLE += (full)
+ VARIANT:=full
+ PROVIDES:=ethtool
+ DEPENDS:=+libmnl
+ CONFLICTS:=
endef
define Package/ethtool/description
@@ -39,18 +49,12 @@ define Package/ethtool/description
network interface
endef
-define Package/ethtool/config
- config ETHTOOL_PRETTY_DUMP
- depends on PACKAGE_ethtool
- bool "Enable pretty printing"
-endef
-
-CONFIGURE_ARGS += --disable-netlink
+Package/ethtool-full/description:=$(Package/ethtool/description)
-ifeq ($(CONFIG_ETHTOOL_PRETTY_DUMP),y)
-CONFIGURE_ARGS += --enable-pretty-dump
+ifeq ($(BUILD_VARIANT),full)
+CONFIGURE_ARGS += --enable-netlink --enable-pretty-dump
else
-CONFIGURE_ARGS += --disable-pretty-dump
+CONFIGURE_ARGS += --disable-netlink --disable-pretty-dump
endif
define Package/ethtool/install
@@ -58,4 +62,7 @@ define Package/ethtool/install
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ethtool $(1)/usr/sbin
endef
+Package/ethtool-full/install=$(Package/ethtool/install)
+
$(eval $(call BuildPackage,ethtool))
+$(eval $(call BuildPackage,ethtool-full))
diff --git a/package/network/utils/iproute2/Makefile b/package/network/utils/iproute2/Makefile
index 54165636c7c..2f9d2f2bc98 100644
--- a/package/network/utils/iproute2/Makefile
+++ b/package/network/utils/iproute2/Makefile
@@ -8,17 +8,19 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=iproute2
-PKG_VERSION:=5.11.0
-PKG_RELEASE:=4
+PKG_VERSION:=6.7.0
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@KERNEL/linux/utils/net/iproute2
-PKG_HASH:=c5e2ea108212b3445051b35953ec267f9f3469e1d5c67ac034ab559849505c54
+PKG_HASH:=ff942dd9828d7d1f867f61fe72ce433078c31e5d8e4a78e20f02cb5892e8841d
PKG_BUILD_PARALLEL:=1
PKG_BUILD_DEPENDS:=iptables
PKG_LICENSE:=GPL-2.0
PKG_CPE_ID:=cpe:/a:iproute2_project:iproute2
+PKG_BUILD_FLAGS:=gc-sections lto
+
include $(INCLUDE_DIR)/kernel.mk
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/nls.mk
@@ -57,7 +59,16 @@ $(call Package/iproute2/Default)
DEFAULT_VARIANT:=1
PROVIDES:=tc
ALTERNATIVES:=200:/sbin/tc:/usr/libexec/tc-tiny
- DEPENDS:=+kmod-sched-core +libxtables +tc-mod-iptables +(PACKAGE_devlink||PACKAGE_rdma):libmnl
+ DEPENDS:=+kmod-sched-core +(PACKAGE_devlink||PACKAGE_rdma):libmnl
+endef
+
+define Package/tc-bpf
+$(call Package/iproute2/Default)
+ TITLE:=Traffic control utility (bpf)
+ VARIANT:=tcbpf
+ PROVIDES:=tc
+ ALTERNATIVES:=300:/sbin/tc:/usr/libexec/tc-bpf
+ DEPENDS:=+kmod-sched-core +(PACKAGE_devlink||PACKAGE_rdma):libmnl +libbpf
endef
define Package/tc-full
@@ -65,14 +76,15 @@ $(call Package/iproute2/Default)
TITLE:=Traffic control utility (full)
VARIANT:=tcfull
PROVIDES:=tc
- ALTERNATIVES:=300:/sbin/tc:/usr/libexec/tc-full
- DEPENDS:=+kmod-sched-core +libxtables +tc-mod-iptables +libbpf +(PACKAGE_devlink||PACKAGE_rdma):libmnl
+ ALTERNATIVES:=400:/sbin/tc:/usr/libexec/tc-full
+ DEPENDS:=+kmod-sched-core +(PACKAGE_devlink||PACKAGE_rdma):libmnl +libbpf +libxtables +tc-mod-iptables
endef
define Package/tc-mod-iptables
$(call Package/iproute2/Default)
TITLE:=Traffic control module - iptables action
- DEPENDS:=+libxtables
+ VARIANT:=tcfull
+ DEPENDS:=+libxtables +libbpf
endef
define Package/genl
@@ -123,13 +135,29 @@ endif
ifeq ($(BUILD_VARIANT),tctiny)
LIBBPF_FORCE:=off
+endif
+
+ifeq ($(BUILD_VARIANT),tcbpf)
+ HAVE_ELF:=y
+ LIBBPF_FORCE:=on
SHARED_LIBS:=y
endif
ifeq ($(BUILD_VARIANT),tcfull)
+ #enable iptables/xtables requirement only if tciptables variant is selected
+ TC_CONFIG_XT:=y
+ TC_CONFIG_XT_OLD:=y
+ TC_CONFIG_XT_OLD_H:=y
+ TC_CONFIG_IPSET:=y
HAVE_ELF:=y
LIBBPF_FORCE:=on
SHARED_LIBS:=y
+else
+ #disable iptables requirement by default
+ TC_CONFIG_XT:=n
+ TC_CONFIG_XT_OLD:=n
+ TC_CONFIG_XT_OLD_H:=n
+ TC_CONFIG_IPSET:=n
endif
ifdef CONFIG_PACKAGE_devlink
@@ -145,12 +173,11 @@ define Build/Configure
> $(PKG_BUILD_DIR)/include/SNAPSHOT.h
endef
-TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
-TARGET_LDFLAGS += -Wl,--gc-sections -Wl,--as-needed
+TARGET_LDFLAGS += -Wl,--as-needed
TARGET_CPPFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny
MAKE_FLAGS += \
- KERNEL_INCLUDE="$(LINUX_DIR)/user_headers/include" \
+ KERNEL_INCLUDE="$(LINUX_DIR)/include/uapi" \
SHARED_LIBS=$(SHARED_LIBS) \
IP_CONFIG_TINY=$(IP_CONFIG_TINY) \
BUILD_VARIANT=$(BUILD_VARIANT) \
@@ -158,8 +185,13 @@ MAKE_FLAGS += \
HAVE_ELF=$(HAVE_ELF) \
HAVE_MNL=$(HAVE_MNL) \
HAVE_CAP=$(HAVE_CAP) \
+ HAVE_TIRPC=n \
IPT_LIB_DIR=/usr/lib/iptables \
XT_LIB_DIR=/usr/lib/iptables \
+ TC_CONFIG_XT=$(TC_CONFIG_XT) \
+ TC_CONFIG_XT_OLD=$(TC_CONFIG_XT_OLD) \
+ TC_CONFIG_XT_OLD_H=$(TC_CONFIG_XT_OLD_H) \
+ TC_CONFIG_IPSET=$(TC_CONFIG_IPSET) \
FPIC="$(FPIC)" \
$(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='')
@@ -190,6 +222,11 @@ define Package/tc-tiny/install
$(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/libexec/tc-tiny
endef
+define Package/tc-bpf/install
+ $(INSTALL_DIR) $(1)/usr/libexec
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/libexec/tc-bpf
+endef
+
define Package/tc-full/install
$(INSTALL_DIR) $(1)/usr/libexec
$(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/libexec/tc-full
@@ -232,9 +269,12 @@ endef
$(eval $(call BuildPackage,ip-tiny))
$(eval $(call BuildPackage,ip-full))
+# build tc-mod-iptables before its dependents, to avoid
+# spurious rebuilds when building multiple variants.
+$(eval $(call BuildPackage,tc-mod-iptables))
$(eval $(call BuildPackage,tc-tiny))
+$(eval $(call BuildPackage,tc-bpf))
$(eval $(call BuildPackage,tc-full))
-$(eval $(call BuildPackage,tc-mod-iptables))
$(eval $(call BuildPackage,genl))
$(eval $(call BuildPackage,ip-bridge))
$(eval $(call BuildPackage,ss))
diff --git a/package/network/utils/iproute2/patches/100-configure.patch b/package/network/utils/iproute2/patches/100-configure.patch
deleted file mode 100644
index f70b7199b66..00000000000
--- a/package/network/utils/iproute2/patches/100-configure.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- a/configure
-+++ b/configure
-@@ -39,7 +39,8 @@ int main(int argc, char **argv) {
- }
- EOF
-
-- if $CC -I$INCLUDE -o $TMPDIR/atmtest $TMPDIR/atmtest.c -latm >/dev/null 2>&1; then
-+# OpenWrt: disable ATM support even if present on host system
-+ if [ 1 -eq 0 ]; then
- echo "TC_CONFIG_ATM:=y" >>$CONFIG
- echo yes
- else
diff --git a/package/network/utils/iproute2/patches/110-darwin_fixes.patch b/package/network/utils/iproute2/patches/110-darwin_fixes.patch
index 1f3eb101ea4..06ae59f8b4d 100644
--- a/package/network/utils/iproute2/patches/110-darwin_fixes.patch
+++ b/package/network/utils/iproute2/patches/110-darwin_fixes.patch
@@ -1,6 +1,6 @@
--- a/netem/maketable.c
+++ b/netem/maketable.c
-@@ -10,7 +10,9 @@
+@@ -11,7 +11,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
@@ -12,7 +12,7 @@
#include <sys/stat.h>
--- a/netem/normal.c
+++ b/netem/normal.c
-@@ -8,8 +8,12 @@
+@@ -9,8 +9,12 @@
#include <string.h>
#include <limits.h>
@@ -27,7 +27,7 @@
#define TABLEFACTOR NETEM_DIST_SCALE
--- a/netem/pareto.c
+++ b/netem/pareto.c
-@@ -7,8 +7,12 @@
+@@ -8,8 +8,12 @@
#include <math.h>
#include <limits.h>
@@ -42,7 +42,7 @@
#define TABLESIZE 16384
--- a/netem/paretonormal.c
+++ b/netem/paretonormal.c
-@@ -14,10 +14,13 @@
+@@ -15,10 +15,13 @@
#include <string.h>
#include <math.h>
#include <limits.h>
diff --git a/package/network/utils/iproute2/patches/115-add-config-xtlibdir.patch b/package/network/utils/iproute2/patches/115-add-config-xtlibdir.patch
index 8702d5fd2d1..c32863c3648 100644
--- a/package/network/utils/iproute2/patches/115-add-config-xtlibdir.patch
+++ b/package/network/utils/iproute2/patches/115-add-config-xtlibdir.patch
@@ -1,6 +1,6 @@
--- a/tc/Makefile
+++ b/tc/Makefile
-@@ -128,6 +128,9 @@ CFLAGS += -DCONFIG_GACT -DCONFIG_GACT_PR
+@@ -119,6 +119,9 @@ CFLAGS += -DCONFIG_GACT -DCONFIG_GACT_PR
ifneq ($(IPT_LIB_DIR),)
CFLAGS += -DIPT_LIB_DIR=\"$(IPT_LIB_DIR)\"
endif
diff --git a/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man.patch b/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man.patch
deleted file mode 100644
index e3faee0d8ff..00000000000
--- a/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/Makefile
-+++ b/Makefile
-@@ -55,7 +55,7 @@ WFLAGS += -Wmissing-declarations -Wold-s
- CFLAGS := $(WFLAGS) $(CCOPTS) -I../include -I../include/uapi $(DEFINES) $(CFLAGS)
- YACCFLAGS = -d -t -v
-
--SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma dcb man
-+SUBDIRS=lib ip tc bridge misc genl devlink rdma
-
- LIBNETLINK=../lib/libutil.a ../lib/libnetlink.a
- LDLIBS += $(LIBNETLINK)
diff --git a/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch b/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch
new file mode 100644
index 00000000000..8c70c144891
--- /dev/null
+++ b/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch
@@ -0,0 +1,14 @@
+--- a/Makefile
++++ b/Makefile
+@@ -68,9 +68,9 @@ WFLAGS += -Wmissing-declarations -Wold-s
+ CFLAGS := $(WFLAGS) $(CCOPTS) -I../include -I../include/uapi $(DEFINES) $(CFLAGS)
+ YACCFLAGS = -d -t -v
+
+-SUBDIRS=lib ip tc bridge misc netem genl man
++SUBDIRS=lib ip tc bridge misc genl
+ ifeq ($(HAVE_MNL),y)
+-SUBDIRS += tipc devlink rdma dcb vdpa
++SUBDIRS += devlink rdma
+ endif
+
+ LIBNETLINK=../lib/libutil.a ../lib/libnetlink.a
diff --git a/package/network/utils/iproute2/patches/140-allow_pfifo_fast.patch b/package/network/utils/iproute2/patches/140-allow_pfifo_fast.patch
index 13de48f4128..8f5a7d352e5 100644
--- a/package/network/utils/iproute2/patches/140-allow_pfifo_fast.patch
+++ b/package/network/utils/iproute2/patches/140-allow_pfifo_fast.patch
@@ -1,6 +1,6 @@
--- a/tc/q_fifo.c
+++ b/tc/q_fifo.c
-@@ -95,5 +95,6 @@ struct qdisc_util pfifo_head_drop_qdisc_
+@@ -90,5 +90,6 @@ struct qdisc_util pfifo_head_drop_qdisc_
struct qdisc_util pfifo_fast_qdisc_util = {
.id = "pfifo_fast",
diff --git a/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch b/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch
index a11a2a3fab2..0d228757517 100644
--- a/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch
+++ b/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch
@@ -1,6 +1,6 @@
--- a/configure
+++ b/configure
-@@ -367,7 +367,7 @@ check_selinux()
+@@ -391,7 +391,7 @@ check_tirpc()
check_mnl()
{
diff --git a/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch b/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch
index c780022d1ad..bffacddb217 100644
--- a/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch
+++ b/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch
@@ -1,6 +1,6 @@
--- a/configure
+++ b/configure
-@@ -235,7 +235,7 @@ EOF
+@@ -246,7 +246,7 @@ EOF
check_elf()
{
diff --git a/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch b/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch
index 8cd4e4ae6aa..570e9c7038b 100644
--- a/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch
+++ b/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch
@@ -1,6 +1,6 @@
--- a/configure
+++ b/configure
-@@ -425,7 +425,7 @@ EOF
+@@ -449,7 +449,7 @@ EOF
check_cap()
{
diff --git a/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch b/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch
new file mode 100644
index 00000000000..4d7fb763086
--- /dev/null
+++ b/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch
@@ -0,0 +1,11 @@
+--- a/configure
++++ b/configure
+@@ -378,7 +378,7 @@ check_selinux()
+
+ check_tirpc()
+ {
+- if ${PKG_CONFIG} libtirpc --exists; then
++ if [ "${HAVE_TIRPC}" = "y" ] && ${PKG_CONFIG} libtirpc --exists; then
+ echo "HAVE_RPC:=y" >>$CONFIG
+ echo "yes"
+
diff --git a/package/network/utils/iproute2/patches/170-ip_tiny.patch b/package/network/utils/iproute2/patches/170-ip_tiny.patch
index d5e5b36936e..71081c36bcc 100644
--- a/package/network/utils/iproute2/patches/170-ip_tiny.patch
+++ b/package/network/utils/iproute2/patches/170-ip_tiny.patch
@@ -1,6 +1,6 @@
--- a/ip/Makefile
+++ b/ip/Makefile
-@@ -17,6 +17,13 @@ RTMONOBJ=rtmon.o
+@@ -19,6 +19,13 @@ RTMONOBJ=rtmon.o
include ../config.mk
@@ -12,9 +12,9 @@
+STATIC_SYM_SOURCES:=$(filter-out $(STATIC_SYM_FILTER),$(wildcard *.c))
+
ALLOBJ=$(IPOBJ) $(RTMONOBJ)
- SCRIPTS=ifcfg rtpr routel routef
+ SCRIPTS=routel
TARGETS=ip rtmon
-@@ -46,7 +53,7 @@ else
+@@ -48,7 +55,7 @@ else
ip: static-syms.o
static-syms.o: static-syms.h
@@ -25,24 +25,25 @@
sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \
--- a/ip/ip.c
+++ b/ip/ip.c
-@@ -64,10 +64,16 @@ static void usage(void)
+@@ -61,11 +61,17 @@ static void usage(void)
fprintf(stderr,
"Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
" ip [ -force ] -batch filename\n"
+#ifndef IPROUTE2_TINY
- "where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n"
- " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n"
- " netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n"
- " vrf | sr | nexthop | mptcp }\n"
+ "where OBJECT := { address | addrlabel | amt | fou | help | ila | ioam | l2tp |\n"
+ " link | macsec | maddress | monitor | mptcp | mroute | mrule |\n"
+ " neighbor | neighbour | netconf | netns | nexthop | ntable |\n"
+ " ntbl | route | rule | sr | tap | tcpmetrics |\n"
+ " token | tunnel | tuntap | vrf | xfrm }\n"
+#else
-+ "where OBJECT := { link | address | route | rule | neigh | tunnel | maddress |\n"
-+ " mroute | mrule | monitor | netns | macsec | token | ila |\n"
-+ " vrf | sr }\n"
++ "where OBJECT := { address | link | maddress | monitor |\n"
++ " neighbor | neighbour | netns | route |\n"
++ " rule | token | tunnel }\n"
+#endif
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
" -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
" -f[amily] { inet | inet6 | mpls | bridge | link } |\n"
-@@ -90,36 +96,50 @@ static const struct cmd {
+@@ -88,37 +94,49 @@ static const struct cmd {
int (*func)(int argc, char **argv);
} cmds[] = {
{ "address", do_ipaddr },
@@ -62,9 +63,9 @@
+#ifndef IPROUTE2_TINY
{ "l2tp", do_ipl2tp },
{ "fou", do_ipfou },
-+#endif
{ "ila", do_ipila },
{ "macsec", do_ipmacsec },
++#endif
{ "tunnel", do_iptunnel },
{ "tunl", do_iptunnel },
+#ifndef IPROUTE2_TINY
@@ -77,22 +78,21 @@
{ "monitor", do_ipmonitor },
+#ifndef IPROUTE2_TINY
{ "xfrm", do_xfrm },
-+#endif
{ "mroute", do_multiroute },
{ "mrule", do_multirule },
++#endif
{ "netns", do_netns },
+#ifndef IPROUTE2_TINY
{ "netconf", do_ipnetconf },
-+#endif
{ "vrf", do_ipvrf},
{ "sr", do_seg6 },
-+#ifndef IPROUTE2_TINY
{ "nexthop", do_ipnh },
{ "mptcp", do_mptcp },
+ { "ioam", do_ioam6 },
+#endif
{ "help", do_help },
+ { "stats", do_ipstats },
{ 0 }
- };
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -3,6 +3,10 @@ include ../config.mk
@@ -105,4 +105,4 @@
+
UTILOBJ = utils.o utils_math.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \
inet_proto.o namespace.o json_writer.o json_print.o json_print_math.o \
- names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o
+ names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o ppp_proto.o
diff --git a/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch b/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch
index da961a183bd..aef51395a95 100644
--- a/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch
+++ b/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch
@@ -1,6 +1,6 @@
--- a/tc/Makefile
+++ b/tc/Makefile
-@@ -114,7 +114,7 @@ LDLIBS += -L. -lm
+@@ -106,7 +106,7 @@ LDLIBS += -L. -lm
ifeq ($(SHARED_LIBS),y)
LDLIBS += -ldl
@@ -9,7 +9,7 @@
endif
TCLIB := tc_core.o
-@@ -144,7 +144,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc
+@@ -135,7 +135,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc
all: tc $(TCSO)
tc: $(TCOBJ) $(LIBNETLINK) libtc.a
@@ -18,21 +18,22 @@
libtc.a: $(TCLIB)
$(QUIET_AR)$(AR) rcs $@ $^
-@@ -166,6 +166,7 @@ install: all
+@@ -157,6 +157,7 @@ install: all
clean:
rm -f $(TCOBJ) $(TCLIB) libtc.a tc *.so emp_ematch.tab.h; \
rm -f emp_ematch.tab.*
+ rm -f dynsyms.list
- q_atm.so: q_atm.c
- $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm
-@@ -205,4 +206,15 @@ static-syms.h: $(wildcard *.c)
+ m_xt.so: m_xt.c
+ $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fpic -o m_xt.so m_xt.c $$($(PKG_CONFIG) xtables --cflags --libs)
+@@ -193,4 +194,16 @@ static-syms.h: $(wildcard *.c)
sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \
done > $@
+else
+
+tc: dynsyms.list
++m_xt.so: dynsyms.list
+dynsyms.list: $(wildcard *.c)
+ files="$(filter-out $(patsubst %.so,%.c,$(TCSO)), $^)" ; \
+ echo "{" > $@ ; \
diff --git a/package/network/utils/iproute2/patches/180-drop_FAILED_POLICY.patch b/package/network/utils/iproute2/patches/180-drop_FAILED_POLICY.patch
index 95b37ae4426..9ce7dd9a13e 100644
--- a/package/network/utils/iproute2/patches/180-drop_FAILED_POLICY.patch
+++ b/package/network/utils/iproute2/patches/180-drop_FAILED_POLICY.patch
@@ -11,7 +11,7 @@ Subject: [PATCH] add support for dropping with FAILED_POLICY
--- a/ip/rtm_map.c
+++ b/ip/rtm_map.c
-@@ -54,6 +54,8 @@ char *rtnl_rtntype_n2a(int id, char *buf
+@@ -49,6 +49,8 @@ char *rtnl_rtntype_n2a(int id, char *buf
return "nat";
case RTN_XRESOLVE:
return "xresolve";
@@ -20,7 +20,7 @@ Subject: [PATCH] add support for dropping with FAILED_POLICY
default:
snprintf(buf, len, "%d", id);
return buf;
-@@ -89,6 +91,8 @@ int rtnl_rtntype_a2n(int *id, char *arg)
+@@ -84,6 +86,8 @@ int rtnl_rtntype_a2n(int *id, char *arg)
res = RTN_UNICAST;
else if (strcmp(arg, "throw") == 0)
res = RTN_THROW;
@@ -31,7 +31,7 @@ Subject: [PATCH] add support for dropping with FAILED_POLICY
if (!end || end == arg || *end || res > 255)
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
-@@ -249,6 +249,7 @@ enum {
+@@ -265,6 +265,7 @@ enum {
RTN_THROW, /* Not in this table */
RTN_NAT, /* Translate this address */
RTN_XRESOLVE, /* Use external resolver */
diff --git a/package/network/utils/iproute2/patches/185-libbpf-add-limits-h.patch b/package/network/utils/iproute2/patches/185-libbpf-add-limits-h.patch
deleted file mode 100644
index 07dbbc65b9f..00000000000
--- a/package/network/utils/iproute2/patches/185-libbpf-add-limits-h.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From c77310119f9a5f99221dd967c5eb0c7a26094b41 Mon Sep 17 00:00:00 2001
-From: Tony Ambardar <Tony.Ambardar@gmail.com>
-Date: Wed, 3 Mar 2021 10:29:24 -0800
-Subject: [PATCH] lib/bpf: add missing limits.h includes
-
-Several functions in bpf_glue.c and bpf_libbpf.c rely on PATH_MAX, which is
-normally included from <limits.h> in other iproute2 source files.
-
-It fixes errors seen using gcc 10.2.0, binutils 2.35.1 and musl 1.1.24:
-
-bpf_glue.c: In function 'get_libbpf_version':
-bpf_glue.c:46:11: error: 'PATH_MAX' undeclared (first use in this function);
-did you mean 'AF_MAX'?
- 46 | char buf[PATH_MAX], *s;
- | ^~~~~~~~
- | AF_MAX
-
-Reported-by: Rui Salvaterra <rsalvaterra@gmail.com>
-Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
----
- lib/bpf_glue.c | 2 ++
- lib/bpf_libbpf.c | 1 +
- 2 files changed, 3 insertions(+)
-
---- a/lib/bpf_glue.c
-+++ b/lib/bpf_glue.c
-@@ -4,6 +4,8 @@
- * Authors: Hangbin Liu <haliu@redhat.com>
- *
- */
-+#include <limits.h>
-+
- #include "bpf_util.h"
- #ifdef HAVE_LIBBPF
- #include <bpf/bpf.h>
---- a/lib/bpf_libbpf.c
-+++ b/lib/bpf_libbpf.c
-@@ -13,6 +13,7 @@
- #include <stdint.h>
- #include <errno.h>
- #include <fcntl.h>
-+#include <limits.h>
-
- #include <libelf.h>
- #include <gelf.h>
diff --git a/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch b/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch
index d0f8cec6331..765e4ad2e87 100644
--- a/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch
+++ b/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch
@@ -1,6 +1,6 @@
--- a/configure
+++ b/configure
-@@ -259,7 +259,7 @@ int main(int argc, char **argv) {
+@@ -270,7 +270,7 @@ int main(int argc, char **argv) {
}
EOF
@@ -9,7 +9,7 @@
local ret=$?
rm -f $TMPDIR/libbpf_test.c $TMPDIR/libbpf_test
-@@ -277,7 +277,7 @@ int main(int argc, char **argv) {
+@@ -288,7 +288,7 @@ int main(int argc, char **argv) {
}
EOF
diff --git a/package/network/utils/iproute2/patches/195-build_variant_ip_tc.patch b/package/network/utils/iproute2/patches/195-build_variant_ip_tc.patch
index 13418662eea..8156adbf050 100644
--- a/package/network/utils/iproute2/patches/195-build_variant_ip_tc.patch
+++ b/package/network/utils/iproute2/patches/195-build_variant_ip_tc.patch
@@ -1,9 +1,9 @@
--- a/ip/Makefile
+++ b/ip/Makefile
-@@ -26,7 +26,7 @@ STATIC_SYM_SOURCES:=$(filter-out $(STATI
+@@ -28,7 +28,7 @@ STATIC_SYM_SOURCES:=$(filter-out $(STATI
ALLOBJ=$(IPOBJ) $(RTMONOBJ)
- SCRIPTS=ifcfg rtpr routel routef
+ SCRIPTS=routel
-TARGETS=ip rtmon
+TARGETS=$(findstring ip,$(BUILD_VARIANT)) rtmon
@@ -11,7 +11,7 @@
--- a/tc/Makefile
+++ b/tc/Makefile
-@@ -141,7 +141,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc
+@@ -132,7 +132,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc
$(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fpic $< -o $@
diff --git a/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch b/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch
index bf335e08009..92bf5cb66d8 100644
--- a/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch
+++ b/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch
@@ -1,12 +1,12 @@
--- a/configure
+++ b/configure
-@@ -411,14 +411,8 @@ EOF
+@@ -435,14 +435,8 @@ EOF
if $CC -I$INCLUDE -o $TMPDIR/strtest $TMPDIR/strtest.c >/dev/null 2>&1; then
echo "no"
else
- if ${PKG_CONFIG} libbsd --exists; then
-- echo 'CFLAGS += -DHAVE_LIBBSD' `${PKG_CONFIG} libbsd --cflags` >>$CONFIG
-- echo 'LDLIBS +=' `${PKG_CONFIG} libbsd --libs` >> $CONFIG
+- echo 'CFLAGS += -DHAVE_LIBBSD' "$(${PKG_CONFIG} libbsd --cflags)" >>$CONFIG
+- echo 'LDLIBS +=' "$(${PKG_CONFIG} libbsd --libs)" >> $CONFIG
- echo "no"
- else
- echo 'CFLAGS += -DNEED_STRLCPY' >>$CONFIG
diff --git a/package/network/utils/iproute2/patches/300-selinux-configurable.patch b/package/network/utils/iproute2/patches/300-selinux-configurable.patch
index 33c5279aec9..a611ba75f0f 100644
--- a/package/network/utils/iproute2/patches/300-selinux-configurable.patch
+++ b/package/network/utils/iproute2/patches/300-selinux-configurable.patch
@@ -1,6 +1,6 @@
--- a/configure
+++ b/configure
-@@ -354,7 +354,7 @@ check_libbpf()
+@@ -365,7 +365,7 @@ check_libbpf()
check_selinux()
# SELinux is a compile time option in the ss utility
{
diff --git a/package/network/utils/ipset/Makefile b/package/network/utils/ipset/Makefile
index bc4945e0f6c..b0aac8fe36e 100644
--- a/package/network/utils/ipset/Makefile
+++ b/package/network/utils/ipset/Makefile
@@ -9,15 +9,16 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=ipset
-PKG_VERSION:=7.6
+PKG_VERSION:=7.17
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
-PKG_SOURCE_URL:=http://ipset.netfilter.org
-PKG_HASH:=0e7d44caa9c153d96a9b5f12644fbe35a632537a5a7f653792b72e53d9d5c2db
+PKG_SOURCE_URL:=https://ipset.netfilter.org
+PKG_HASH:=be49c9ff489dd6610cad6541e743c3384eac96e9f24707da7b3929d8f2ac64d8
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=GPL-2.0
+PKG_CPE_ID:=cpe:/a:netfilter:ipset
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
@@ -62,6 +63,7 @@ endef
define Package/ipset/install
$(INSTALL_DIR) $(1)/usr/sbin
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/ipset $(1)/usr/sbin/
+ $(CP) $(PKG_INSTALL_DIR)/usr/sbin/ipset-translate $(1)/usr/sbin/
endef
define Package/libipset/install
diff --git a/package/network/utils/iptables/Makefile b/package/network/utils/iptables/Makefile
index 42d9af14b07..45a2b49070e 100644
--- a/package/network/utils/iptables/Makefile
+++ b/package/network/utils/iptables/Makefile
@@ -9,17 +9,18 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=iptables
-PKG_VERSION:=1.8.7
-PKG_RELEASE:=1
+PKG_VERSION:=1.8.8
+PKG_RELEASE:=2
PKG_SOURCE_URL:=https://netfilter.org/projects/iptables/files
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
-PKG_HASH:=c109c96bb04998cd44156622d36f8e04b140701ec60531a10668cfdff5e8d8f0
+PKG_HASH:=71c75889dc710676631553eb1511da0177bbaaf1b551265b912d236c3f51859f
PKG_FIXUP:=autoreconf
PKG_FLAGS:=nonshared
PKG_INSTALL:=1
+PKG_BUILD_FLAGS:=gc-sections no-lto
PKG_BUILD_PARALLEL:=1
PKG_LICENSE:=GPL-2.0
PKG_CPE_ID:=cpe:/a:netfilter_core_team:iptables
@@ -41,31 +42,27 @@ endef
define Package/iptables/Module
$(call Package/iptables/Default)
- DEPENDS:=iptables $(1)
+ DEPENDS:=+libxtables $(1)
endef
-define Package/iptables
+define Package/xtables-legacy
$(call Package/iptables/Default)
TITLE:=IP firewall administration tool
- MENU:=1
- DEPENDS+= +kmod-ipt-core +libip4tc +IPV6:libip6tc +libxtables
+ DEPENDS+= +kmod-ipt-core +libip4tc +IPV6:libip6tc +libiptext +IPV6:libiptext6 +libxtables
endef
-define Package/iptables/config
- config IPTABLES_CONNLABEL
- bool "Enable Connlabel support"
- default n
- help
- This enable connlabel support in iptables.
-
- config IPTABLES_NFTABLES
- bool "Enable Nftables support"
- default n
- help
- This enable nftables support in iptables.
+define Package/iptables-zz-legacy
+$(call Package/iptables/Default)
+ TITLE:=IP firewall administration tool
+ DEPENDS+= +xtables-legacy
+ PROVIDES:=iptables iptables-legacy
+ ALTERNATIVES:=\
+ 200:/usr/sbin/iptables:/usr/sbin/xtables-legacy-multi \
+ 200:/usr/sbin/iptables-restore:/usr/sbin/xtables-legacy-multi \
+ 200:/usr/sbin/iptables-save:/usr/sbin/xtables-legacy-multi
endef
-define Package/iptables/description
+define Package/iptables-zz-legacy/description
IP firewall administration tool.
Matches:
@@ -105,10 +102,43 @@ IP firewall administration tool.
endef
+define Package/xtables-nft
+$(call Package/iptables/Default)
+ TITLE:=IP firewall administration tool nft
+ DEPENDS:=+libnftnl +libiptext +IPV6:libiptext6 +libiptext-nft +kmod-nft-compat
+endef
+
+define Package/arptables-nft
+$(call Package/iptables/Default)
+ DEPENDS:=+kmod-nft-arp +xtables-nft +kmod-arptables
+ TITLE:=ARP firewall administration tool nft
+ PROVIDES:=arptables
+ ALTERNATIVES:=\
+ 300:/usr/sbin/arptables:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/arptables-restore:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/arptables-save:/usr/sbin/xtables-nft-multi
+endef
+
+define Package/ebtables-nft
+$(call Package/iptables/Default)
+ DEPENDS:=+kmod-nft-bridge +xtables-nft +kmod-ebtables
+ TITLE:=Bridge firewall administration tool nft
+ PROVIDES:=ebtables
+ ALTERNATIVES:=\
+ 300:/usr/sbin/ebtables:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/ebtables-restore:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/ebtables-save:/usr/sbin/xtables-nft-multi
+endef
+
define Package/iptables-nft
$(call Package/iptables/Default)
TITLE:=IP firewall administration tool nft
- DEPENDS:=iptables @IPTABLES_NFTABLES +libxtables-nft
+ DEPENDS:=+kmod-ipt-core +xtables-nft
+ PROVIDES:=iptables
+ ALTERNATIVES:=\
+ 300:/usr/sbin/iptables:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/iptables-restore:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/iptables-save:/usr/sbin/xtables-nft-multi
endef
define Package/iptables-nft/description
@@ -121,7 +151,7 @@ Extra iptables nftables nft binaries.
endef
define Package/iptables-mod-conntrack-extra
-$(call Package/iptables/Module, +kmod-ipt-conntrack-extra +kmod-ipt-raw)
+$(call Package/iptables/Module, +kmod-ipt-conntrack-extra)
TITLE:=Extra connection tracking extensions
endef
@@ -222,19 +252,6 @@ iptables extensions for extra NAT targets.
- NETMAP
endef
-define Package/iptables-mod-ulog
-$(call Package/iptables/Module, +kmod-ipt-ulog)
- TITLE:=user-space packet logging
-endef
-
-define Package/iptables-mod-ulog/description
-iptables extensions for user-space packet logging.
-
- Targets:
- - ULOG
-
-endef
-
define Package/iptables-mod-nflog
$(call Package/iptables/Module, +kmod-nfnetlink-log +kmod-ipt-nflog)
TITLE:=Netfilter NFLOG target
@@ -393,6 +410,19 @@ iptables extension for triggering a LED.
endef
+define Package/iptables-mod-socket
+$(call Package/iptables/Module, +kmod-ipt-socket)
+ TITLE:=Socket match iptables extensions
+endef
+
+define Package/iptables-mod-socket/description
+Socket match iptables extensions.
+
+ Matches:
+ - socket
+
+endef
+
define Package/iptables-mod-tproxy
$(call Package/iptables/Module, +kmod-ipt-tproxy)
TITLE:=Transparent proxy iptables extensions
@@ -401,9 +431,6 @@ endef
define Package/iptables-mod-tproxy/description
Transparent proxy iptables extensions.
- Matches:
- - socket
-
Targets:
- TPROXY
@@ -444,42 +471,51 @@ define Package/iptables-mod-checksum/description
iptables extension for the CHECKSUM calculation target
endef
-define Package/ip6tables
+define Package/ip6tables-zz-legacy
$(call Package/iptables/Default)
- DEPENDS:=@IPV6 +kmod-ip6tables +iptables
+ DEPENDS:=@IPV6 +kmod-ip6tables +xtables-legacy
CATEGORY:=Network
TITLE:=IPv6 firewall administration tool
- MENU:=1
+ PROVIDES:=ip6tables ip6tables-legacy
+ ALTERNATIVES:=\
+ 200:/usr/sbin/ip6tables:/usr/sbin/xtables-legacy-multi \
+ 200:/usr/sbin/ip6tables-restore:/usr/sbin/xtables-legacy-multi \
+ 200:/usr/sbin/ip6tables-save:/usr/sbin/xtables-legacy-multi
endef
define Package/ip6tables-nft
$(call Package/iptables/Default)
- DEPENDS:=ip6tables @IPTABLES_NFTABLES +libxtables-nft
+ DEPENDS:=@IPV6 +kmod-ip6tables +xtables-nft
TITLE:=IP firewall administration tool nft
+ PROVIDES:=ip6tables
+ ALTERNATIVES:=\
+ 300:/usr/sbin/ip6tables:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/ip6tables-restore:/usr/sbin/xtables-nft-multi \
+ 300:/usr/sbin/ip6tables-save:/usr/sbin/xtables-nft-multi
endef
define Package/ip6tables-nft/description
Extra ip6tables nftables nft binaries.
- iptables-nft
- iptables-nft-restore
- iptables-nft-save
- iptables-translate
- iptables-restore-translate
+ ip6tables-nft
+ ip6tables-nft-restore
+ ip6tables-nft-save
+ ip6tables-translate
+ ip6tables-restore-translate
endef
define Package/ip6tables-extra
$(call Package/iptables/Default)
- DEPENDS:=ip6tables +kmod-ip6tables-extra
+ DEPENDS:=+libxtables +kmod-ip6tables-extra
TITLE:=IPv6 header matching modules
endef
-define Package/ip6tables-mod-extra/description
+define Package/ip6tables-extra/description
iptables header matching modules for IPv6
endef
define Package/ip6tables-mod-nat
$(call Package/iptables/Default)
- DEPENDS:=ip6tables +kmod-ipt-nat6
+ DEPENDS:=+libxtables +kmod-ipt-nat6
TITLE:=IPv6 NAT extensions
endef
@@ -493,7 +529,6 @@ $(call Package/iptables/Default)
CATEGORY:=Libraries
TITLE:=IPv4 firewall - shared libiptc library
ABI_VERSION:=2
- DEPENDS:=+libxtables
endef
define Package/libip6tc
@@ -502,27 +537,51 @@ $(call Package/iptables/Default)
CATEGORY:=Libraries
TITLE:=IPv6 firewall - shared libiptc library
ABI_VERSION:=2
- DEPENDS:=+libxtables
endef
-define Package/libxtables
+define Package/libiptext
$(call Package/iptables/Default)
SECTION:=libs
CATEGORY:=Libraries
- TITLE:=IPv4/IPv6 firewall - shared xtables library
- ABI_VERSION:=12
- DEPENDS:= \
- +IPTABLES_CONNLABEL:libnetfilter-conntrack \
- +IPTABLES_NFTABLES:libnftnl
+ TITLE:=IPv4 firewall - shared libiptext library
+ ABI_VERSION:=0
+ DEPENDS:=+libxtables
+endef
+
+define Package/libiptext6
+ $(call Package/iptables/Default)
+ SECTION:=libs
+ CATEGORY:=Libraries
+ TITLE:=IPv6 firewall - shared libiptext library
+ ABI_VERSION:=0
+ DEPENDS:=+libxtables
+endef
+
+define Package/libiptext-nft
+ $(call Package/iptables/Default)
+ SECTION:=libs
+ CATEGORY:=Libraries
+ TITLE:=IPv4/IPv6 firewall - shared libiptext nft library
+ ABI_VERSION:=0
+ DEPENDS:=+libxtables
endef
-define Package/libxtables-nft
+define Package/libxtables
$(call Package/iptables/Default)
SECTION:=libs
CATEGORY:=Libraries
- TITLE:=IPv4/IPv6 firewall - shared xtables nft library
+ TITLE:=IPv4/IPv6 firewall - shared xtables library
+ MENU:=1
ABI_VERSION:=12
- DEPENDS:=libxtables
+ DEPENDS:=+IPTABLES_CONNLABEL:libnetfilter-conntrack
+endef
+
+define Package/libxtables/config
+ config IPTABLES_CONNLABEL
+ bool "Enable Connlabel support"
+ default n
+ help
+ This enable connlabel support in iptables.
endef
TARGET_CPPFLAGS := \
@@ -533,12 +592,8 @@ TARGET_CPPFLAGS := \
TARGET_CFLAGS += \
-I$(PKG_BUILD_DIR)/include \
-I$(LINUX_DIR)/user_headers/include \
- -ffunction-sections -fdata-sections \
-DNO_LEGACY
-TARGET_LDFLAGS += \
- -Wl,--gc-sections
-
CONFIGURE_ARGS += \
--enable-shared \
--enable-static \
@@ -547,7 +602,6 @@ CONFIGURE_ARGS += \
--with-xtlibdir=/usr/lib/iptables \
--with-xt-lock-name=/var/run/xtables.lock \
$(if $(CONFIG_IPTABLES_CONNLABEL),,--disable-connlabel) \
- $(if $(CONFIG_IPTABLES_NFTABLES),,--disable-nftables) \
$(if $(CONFIG_IPV6),,--disable-ipv6)
MAKE_FLAGS := \
@@ -580,7 +634,6 @@ define Build/InstallDev
$(CP) $(PKG_BUILD_DIR)/include/iptables/*.h $(1)/usr/include/iptables/
$(CP) $(PKG_BUILD_DIR)/include/iptables.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/include/ip6tables.h $(1)/usr/include/
- $(CP) $(PKG_BUILD_DIR)/include/libipulog $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/include/libiptc $(1)/usr/include/
$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
@@ -595,23 +648,45 @@ define Build/InstallDev
$(CP) $(PKG_BUILD_DIR)/extensions/libiptext*.so $(1)/usr/lib/
endef
-define Package/iptables/install
+define Package/xtables-legacy/install
$(INSTALL_DIR) $(1)/usr/sbin
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/xtables-legacy-multi $(1)/usr/sbin/
- $(CP) $(PKG_INSTALL_DIR)/usr/sbin/iptables{,-restore,-save} $(1)/usr/sbin/
+endef
+
+define Package/iptables-zz-legacy/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(CP) $(PKG_INSTALL_DIR)/usr/sbin/iptables-legacy{,-restore,-save} $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/usr/lib/iptables
endef
-define Package/iptables-nft/install
+define Package/xtables-nft/install
$(INSTALL_DIR) $(1)/usr/sbin
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/xtables-nft-multi $(1)/usr/sbin/
+endef
+
+define Package/arptables-nft/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(CP) $(PKG_INSTALL_DIR)/usr/sbin/arptables-nft{,-restore,-save} $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/usr/lib/iptables
+ $(CP) $(PKG_BUILD_DIR)/extensions/libarpt_*.so $(1)/usr/lib/iptables/
+endef
+
+define Package/ebtables-nft/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(CP) $(PKG_INSTALL_DIR)/usr/sbin/ebtables-nft{,-restore,-save} $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/usr/lib/iptables
+ $(CP) $(PKG_BUILD_DIR)/extensions/libebt_*.so $(1)/usr/lib/iptables/
+endef
+
+define Package/iptables-nft/install
+ $(INSTALL_DIR) $(1)/usr/sbin
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/iptables-nft{,-restore,-save} $(1)/usr/sbin/
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/iptables{,-restore}-translate $(1)/usr/sbin/
endef
-define Package/ip6tables/install
+define Package/ip6tables-zz-legacy/install
$(INSTALL_DIR) $(1)/usr/sbin
- $(CP) $(PKG_INSTALL_DIR)/usr/sbin/ip6tables{,-restore,-save} $(1)/usr/sbin/
+ $(CP) $(PKG_INSTALL_DIR)/usr/sbin/ip6tables-legacy{,-restore,-save} $(1)/usr/sbin/
endef
define Package/ip6tables-nft/install
@@ -623,26 +698,34 @@ endef
define Package/libip4tc/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libip4tc.so.* $(1)/usr/lib/
- $(CP) $(PKG_BUILD_DIR)/extensions/libiptext4.so $(1)/usr/lib/
endef
define Package/libip6tc/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libip6tc.so.* $(1)/usr/lib/
- $(CP) $(PKG_BUILD_DIR)/extensions/libiptext6.so $(1)/usr/lib/
endef
-define Package/libxtables/install
+define Package/libiptext/install
$(INSTALL_DIR) $(1)/usr/lib
- $(CP) $(PKG_INSTALL_DIR)/usr/lib/libxtables.so.* $(1)/usr/lib/
$(CP) $(PKG_BUILD_DIR)/extensions/libiptext.so $(1)/usr/lib/
+ $(CP) $(PKG_BUILD_DIR)/extensions/libiptext4.so $(1)/usr/lib/
+endef
+
+define Package/libiptext6/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_BUILD_DIR)/extensions/libiptext6.so $(1)/usr/lib/
endef
-define Package/libxtables-nft/install
+define Package/libiptext-nft/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_BUILD_DIR)/extensions/libiptext_*.so $(1)/usr/lib/
endef
+define Package/libxtables/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libxtables.so.* $(1)/usr/lib/
+endef
+
define BuildPlugin
define Package/$(1)/install
$(INSTALL_DIR) $$(1)/usr/lib/iptables
@@ -658,11 +741,17 @@ define BuildPlugin
endef
$(eval $(call BuildPackage,libxtables))
-$(eval $(call BuildPackage,libxtables-nft))
$(eval $(call BuildPackage,libip4tc))
$(eval $(call BuildPackage,libip6tc))
-$(eval $(call BuildPackage,iptables))
+$(eval $(call BuildPackage,libiptext))
+$(eval $(call BuildPackage,libiptext6))
+$(eval $(call BuildPackage,libiptext-nft))
+$(eval $(call BuildPackage,xtables-legacy))
+$(eval $(call BuildPackage,xtables-nft))
+$(eval $(call BuildPackage,arptables-nft))
+$(eval $(call BuildPackage,ebtables-nft))
$(eval $(call BuildPackage,iptables-nft))
+$(eval $(call BuildPackage,iptables-zz-legacy))
$(eval $(call BuildPlugin,iptables-mod-conntrack-extra,$(IPT_CONNTRACK_EXTRA-m)))
$(eval $(call BuildPlugin,iptables-mod-conntrack-label,$(IPT_CONNTRACK_LABEL-m)))
$(eval $(call BuildPlugin,iptables-mod-extra,$(IPT_EXTRA-m)))
@@ -674,10 +763,10 @@ $(eval $(call BuildPlugin,iptables-mod-nat-extra,$(IPT_NAT_EXTRA-m)))
$(eval $(call BuildPlugin,iptables-mod-iprange,$(IPT_IPRANGE-m)))
$(eval $(call BuildPlugin,iptables-mod-cluster,$(IPT_CLUSTER-m)))
$(eval $(call BuildPlugin,iptables-mod-clusterip,$(IPT_CLUSTERIP-m)))
-$(eval $(call BuildPlugin,iptables-mod-ulog,$(IPT_ULOG-m)))
$(eval $(call BuildPlugin,iptables-mod-hashlimit,$(IPT_HASHLIMIT-m)))
$(eval $(call BuildPlugin,iptables-mod-rpfilter,$(IPT_RPFILTER-m)))
$(eval $(call BuildPlugin,iptables-mod-led,$(IPT_LED-m)))
+$(eval $(call BuildPlugin,iptables-mod-socket,$(IPT_SOCKET-m)))
$(eval $(call BuildPlugin,iptables-mod-tproxy,$(IPT_TPROXY-m)))
$(eval $(call BuildPlugin,iptables-mod-tee,$(IPT_TEE-m)))
$(eval $(call BuildPlugin,iptables-mod-u32,$(IPT_U32-m)))
@@ -685,8 +774,8 @@ $(eval $(call BuildPlugin,iptables-mod-nflog,$(IPT_NFLOG-m)))
$(eval $(call BuildPlugin,iptables-mod-trace,$(IPT_DEBUG-m)))
$(eval $(call BuildPlugin,iptables-mod-nfqueue,$(IPT_NFQUEUE-m)))
$(eval $(call BuildPlugin,iptables-mod-checksum,$(IPT_CHECKSUM-m)))
-$(eval $(call BuildPackage,ip6tables))
$(eval $(call BuildPackage,ip6tables-nft))
+$(eval $(call BuildPackage,ip6tables-zz-legacy))
$(eval $(call BuildPlugin,ip6tables-extra,$(IPT_IPV6_EXTRA-m)))
$(eval $(call BuildPlugin,ip6tables-mod-nat,$(IPT_NAT6-m)))
diff --git a/package/network/utils/iptables/patches/020-treewide-use-uint-instead-of-u_int.patch b/package/network/utils/iptables/patches/020-treewide-use-uint-instead-of-u_int.patch
new file mode 100644
index 00000000000..e4b0cd92dea
--- /dev/null
+++ b/package/network/utils/iptables/patches/020-treewide-use-uint-instead-of-u_int.patch
@@ -0,0 +1,144 @@
+From f319389525b066b7dc6d389c88f16a0df3b8f189 Mon Sep 17 00:00:00 2001
+From: Nick Hainke <vincent@systemli.org>
+Date: Mon, 16 May 2022 18:16:41 +0200
+Subject: treewide: use uint* instead of u_int*
+
+Gcc complains about missing types. Some commits introduced u_int* instead
+of uint*. Use uint treewide.
+
+Fixes errors in the form of:
+In file included from xtables-legacy-multi.c:5:
+xshared.h:83:56: error: unknown type name 'u_int16_t'; did you mean 'uint16_t'?
+ 83 | set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
+ | ^~~~~~~~~
+ | uint16_t
+make[6]: *** [Makefile:712: xtables_legacy_multi-xtables-legacy-multi.o] Error 1
+
+Avoid libipq API breakage by adjusting libipq.h include accordingly. For
+arpt_mangle.h kernel uAPI header, apply same change as in kernel commit
+e91ded8db5747 ("uapi: netfilter_arp: use __u8 instead of u_int8_t").
+
+Signed-off-by: Nick Hainke <vincent@systemli.org>
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ extensions/libxt_conntrack.c | 2 +-
+ include/libipq/libipq.h | 8 ++++----
+ include/libiptc/libxtc.h | 2 +-
+ include/linux/netfilter_arp/arpt_mangle.h | 2 +-
+ iptables/xshared.c | 2 +-
+ iptables/xshared.h | 2 +-
+ libipq/ipq_create_handle.3 | 2 +-
+ libipq/ipq_set_mode.3 | 2 +-
+ 8 files changed, 11 insertions(+), 11 deletions(-)
+
+--- a/extensions/libxt_conntrack.c
++++ b/extensions/libxt_conntrack.c
+@@ -778,7 +778,7 @@ matchinfo_print(const void *ip, const st
+
+ static void
+ conntrack_dump_ports(const char *prefix, const char *opt,
+- u_int16_t port_low, u_int16_t port_high)
++ uint16_t port_low, uint16_t port_high)
+ {
+ if (port_high == 0 || port_low == port_high)
+ printf(" %s%s %u", prefix, opt, port_low);
+--- a/include/libipq/libipq.h
++++ b/include/libipq/libipq.h
+@@ -24,7 +24,7 @@
+ #include <errno.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+-#include <sys/types.h>
++#include <stdint.h>
+ #include <sys/socket.h>
+ #include <sys/uio.h>
+ #include <asm/types.h>
+@@ -48,19 +48,19 @@ typedef unsigned long ipq_id_t;
+ struct ipq_handle
+ {
+ int fd;
+- u_int8_t blocking;
++ uint8_t blocking;
+ struct sockaddr_nl local;
+ struct sockaddr_nl peer;
+ };
+
+-struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol);
++struct ipq_handle *ipq_create_handle(uint32_t flags, uint32_t protocol);
+
+ int ipq_destroy_handle(struct ipq_handle *h);
+
+ ssize_t ipq_read(const struct ipq_handle *h,
+ unsigned char *buf, size_t len, int timeout);
+
+-int ipq_set_mode(const struct ipq_handle *h, u_int8_t mode, size_t len);
++int ipq_set_mode(const struct ipq_handle *h, uint8_t mode, size_t len);
+
+ ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf);
+
+--- a/include/libiptc/libxtc.h
++++ b/include/libiptc/libxtc.h
+@@ -10,7 +10,7 @@ extern "C" {
+ #endif
+
+ #ifndef XT_MIN_ALIGN
+-/* xt_entry has pointers and u_int64_t's in it, so if you align to
++/* xt_entry has pointers and uint64_t's in it, so if you align to
+ it, you'll also align to any crazy matches and targets someone
+ might write */
+ #define XT_MIN_ALIGN (__alignof__(struct xt_entry))
+--- a/include/linux/netfilter_arp/arpt_mangle.h
++++ b/include/linux/netfilter_arp/arpt_mangle.h
+@@ -13,7 +13,7 @@ struct arpt_mangle
+ union {
+ struct in_addr tgt_ip;
+ } u_t;
+- u_int8_t flags;
++ __u8 flags;
+ int target;
+ };
+
+--- a/iptables/xshared.c
++++ b/iptables/xshared.c
+@@ -1025,7 +1025,7 @@ static const int inverse_for_options[NUM
+ };
+
+ void
+-set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
++set_option(unsigned int *options, unsigned int option, uint16_t *invflg,
+ bool invert)
+ {
+ if (*options & option)
+--- a/iptables/xshared.h
++++ b/iptables/xshared.h
+@@ -80,7 +80,7 @@ struct xtables_target;
+ #define IPT_INV_ARPHRD 0x0800
+
+ void
+-set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
++set_option(unsigned int *options, unsigned int option, uint16_t *invflg,
+ bool invert);
+
+ /**
+--- a/libipq/ipq_create_handle.3
++++ b/libipq/ipq_create_handle.3
+@@ -24,7 +24,7 @@ ipq_create_handle, ipq_destroy_handle \(
+ .br
+ .B #include <libipq.h>
+ .sp
+-.BI "struct ipq_handle *ipq_create_handle(u_int32_t " flags ", u_int32_t " protocol ");"
++.BI "struct ipq_handle *ipq_create_handle(uint32_t " flags ", uint32_t " protocol ");"
+ .br
+ .BI "int ipq_destroy_handle(struct ipq_handle *" h );
+ .SH DESCRIPTION
+--- a/libipq/ipq_set_mode.3
++++ b/libipq/ipq_set_mode.3
+@@ -24,7 +24,7 @@ ipq_set_mode \(em set the ip_queue queui
+ .br
+ .B #include <libipq.h>
+ .sp
+-.BI "int ipq_set_mode(const struct ipq_handle *" h ", u_int8_t " mode ", size_t " range );
++.BI "int ipq_set_mode(const struct ipq_handle *" h ", uint8_t " mode ", size_t " range );
+ .SH DESCRIPTION
+ The
+ .B ipq_set_mode
diff --git a/package/network/utils/iptables/patches/030-revert-fix-build-for-missing-ETH_ALEN-definition.patch b/package/network/utils/iptables/patches/030-revert-fix-build-for-missing-ETH_ALEN-definition.patch
new file mode 100644
index 00000000000..6c8e3deb5c3
--- /dev/null
+++ b/package/network/utils/iptables/patches/030-revert-fix-build-for-missing-ETH_ALEN-definition.patch
@@ -0,0 +1,60 @@
+From 0e7cf0ad306cdf95dc3c28d15a254532206a888e Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 18 May 2022 16:04:09 +0200
+Subject: Revert "fix build for missing ETH_ALEN definition"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit c5d9a723b5159a28f547b577711787295a14fd84 as it broke
+compiling against musl libc. Might be a bug in the latter, but for the
+time being try to please both by avoiding the include and instead
+defining ETH_ALEN if unset.
+
+While being at it, move netinet/ether.h include up.
+
+Fixes: 1bdb5535f561a ("libxtables: Extend MAC address printing/parsing support")
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Reviewed-by: Maciej Żenczykowski <maze@google.com>
+---
+ libxtables/xtables.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/libxtables/xtables.c
++++ b/libxtables/xtables.c
+@@ -28,6 +28,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <netinet/ether.h>
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ #include <sys/statfs.h>
+@@ -45,7 +46,6 @@
+
+ #include <xtables.h>
+ #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
+-#include <linux/if_ether.h> /* ETH_ALEN */
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv6/ip6_tables.h>
+ #include <libiptc/libxtc.h>
+@@ -72,6 +72,10 @@
+ #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
+ #endif
+
++#ifndef ETH_ALEN
++#define ETH_ALEN 6
++#endif
++
+ /* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the
+ * current line of the input file, in order to give a more precise error
+ * message. ip6?tables itself doesn't need this, so it is initialized to the
+@@ -2245,8 +2249,6 @@ void xtables_print_num(uint64_t number,
+ printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
+ }
+
+-#include <netinet/ether.h>
+-
+ static const unsigned char mac_type_unicast[ETH_ALEN] = {};
+ static const unsigned char msk_type_unicast[ETH_ALEN] = {1};
+ static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
diff --git a/package/network/utils/iptables/patches/040-xshared-Fix-build-for-Werror-format-security.patch b/package/network/utils/iptables/patches/040-xshared-Fix-build-for-Werror-format-security.patch
new file mode 100644
index 00000000000..f7e5e34c731
--- /dev/null
+++ b/package/network/utils/iptables/patches/040-xshared-Fix-build-for-Werror-format-security.patch
@@ -0,0 +1,23 @@
+From b72eb12ea5a61df0655ad99d5048994e916be83a Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Fri, 13 May 2022 16:51:58 +0200
+Subject: [PATCH] xshared: Fix build for -Werror=format-security
+
+Gcc complains about the omitted format string.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ iptables/xshared.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/iptables/xshared.c
++++ b/iptables/xshared.c
+@@ -1307,7 +1307,7 @@ static void check_empty_interface(struct
+ return;
+
+ if (args->family != NFPROTO_ARP)
+- xtables_error(PARAMETER_PROBLEM, msg);
++ xtables_error(PARAMETER_PROBLEM, "%s", msg);
+
+ fprintf(stderr, "%s", msg);
+ }
diff --git a/package/network/utils/iptables/patches/050-build-fix-error-during-out-of-tree-build.patch b/package/network/utils/iptables/patches/050-build-fix-error-during-out-of-tree-build.patch
new file mode 100644
index 00000000000..acfca96e0fe
--- /dev/null
+++ b/package/network/utils/iptables/patches/050-build-fix-error-during-out-of-tree-build.patch
@@ -0,0 +1,28 @@
+From 0ebf52fc951b2a4d98a166afb34af4f364bbeece Mon Sep 17 00:00:00 2001
+From: Ben Brown <ben@demerara.io>
+Date: Wed, 25 May 2022 16:26:13 +0100
+Subject: build: Fix error during out of tree build
+
+Fixes the following error:
+
+ ../../libxtables/xtables.c:52:10: fatal error: libiptc/linux_list.h: No such file or directory
+ 52 | #include <libiptc/linux_list.h>
+
+Fixes: f58b0d7406451 ("libxtables: Implement notargets hash table")
+Signed-off-by: Ben Brown <ben@demerara.io>
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ libxtables/Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/libxtables/Makefile.am
++++ b/libxtables/Makefile.am
+@@ -1,7 +1,7 @@
+ # -*- Makefile -*-
+
+ AM_CFLAGS = ${regular_CFLAGS}
+-AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables ${kinclude_CPPFLAGS}
++AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables -I${top_srcdir} ${kinclude_CPPFLAGS}
+
+ lib_LTLIBRARIES = libxtables.la
+ libxtables_la_SOURCES = xtables.c xtoptions.c getethertype.c
diff --git a/package/network/utils/iptables/patches/060-libxtables-unexport-init_extensions-declarations.patch b/package/network/utils/iptables/patches/060-libxtables-unexport-init_extensions-declarations.patch
new file mode 100644
index 00000000000..559b93eea43
--- /dev/null
+++ b/package/network/utils/iptables/patches/060-libxtables-unexport-init_extensions-declarations.patch
@@ -0,0 +1,82 @@
+From ef108943f69a6e20533d58823740d3f0534ea8ec Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 1 Jun 2022 19:15:06 +0200
+Subject: libxtables: Unexport init_extensions*() declarations
+
+The functions are used for static builds to initialize extensions after
+libxtables init. Regular library users should not need them, but the
+empty declarations introduced in #else case (and therefore present in
+user's env) may clash with existing symbol names.
+
+Avoid problems and guard the whole block declaring the function
+prototypes and mangling extensions' _init functions by XTABLES_INTERNAL.
+
+Reported-by: Nick Hainke <vincent@systemli.org>
+Fixes: 6c689b639cf8e ("Simplify static build extension loading")
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ include/xtables.h | 44 ++++++++++++++++++++++----------------------
+ 1 file changed, 22 insertions(+), 22 deletions(-)
+
+--- a/include/xtables.h
++++ b/include/xtables.h
+@@ -585,27 +585,6 @@ static inline void xtables_print_mark_ma
+ xtables_print_val_mask(mark, mask, NULL);
+ }
+
+-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+-# ifdef _INIT
+-# undef _init
+-# define _init _INIT
+-# endif
+- extern void init_extensions(void);
+- extern void init_extensions4(void);
+- extern void init_extensions6(void);
+- extern void init_extensionsa(void);
+- extern void init_extensionsb(void);
+-#else
+-# define _init __attribute__((constructor)) _INIT
+-# define EMPTY_FUNC_DEF(x) static inline void x(void) {}
+- EMPTY_FUNC_DEF(init_extensions)
+- EMPTY_FUNC_DEF(init_extensions4)
+- EMPTY_FUNC_DEF(init_extensions6)
+- EMPTY_FUNC_DEF(init_extensionsa)
+- EMPTY_FUNC_DEF(init_extensionsb)
+-# undef EMPTY_FUNC_DEF
+-#endif
+-
+ extern const struct xtables_pprot xtables_chain_protos[];
+ extern uint16_t xtables_parse_protocol(const char *s);
+
+@@ -663,9 +642,30 @@ void xtables_announce_chain(const char *
+ # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+ # endif
+
++#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
++# ifdef _INIT
++# undef _init
++# define _init _INIT
++# endif
++ extern void init_extensions(void);
++ extern void init_extensions4(void);
++ extern void init_extensions6(void);
++ extern void init_extensionsa(void);
++ extern void init_extensionsb(void);
++#else
++# define _init __attribute__((constructor)) _INIT
++# define EMPTY_FUNC_DEF(x) static inline void x(void) {}
++ EMPTY_FUNC_DEF(init_extensions)
++ EMPTY_FUNC_DEF(init_extensions4)
++ EMPTY_FUNC_DEF(init_extensions6)
++ EMPTY_FUNC_DEF(init_extensionsa)
++ EMPTY_FUNC_DEF(init_extensionsb)
++# undef EMPTY_FUNC_DEF
++#endif
++
+ extern void _init(void);
+
+-#endif
++#endif /* XTABLES_INTERNAL */
+
+ #ifdef __cplusplus
+ } /* extern "C" */
diff --git a/package/network/utils/iptables/patches/070-extensions-string-Review-parse_string-function.patch b/package/network/utils/iptables/patches/070-extensions-string-Review-parse_string-function.patch
new file mode 100644
index 00000000000..cfcb6c77f38
--- /dev/null
+++ b/package/network/utils/iptables/patches/070-extensions-string-Review-parse_string-function.patch
@@ -0,0 +1,40 @@
+From da5b32fb4656ab69fe1156eb7e36c7c961839e8a Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 8 Jun 2022 13:45:13 +0200
+Subject: [PATCH] extensions: string: Review parse_string() function
+
+* Compare against sizeof(info->pattern) which is more clear than having
+ to know that this buffer is of size XT_STRING_MAX_PATTERN_SIZE
+
+* Invert the check and error early to reduce indenting
+
+* Pass info->patlen to memcpy() to avoid reading past end of 's'
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ extensions/libxt_string.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/extensions/libxt_string.c
++++ b/extensions/libxt_string.c
+@@ -78,14 +78,13 @@ static void string_init(struct xt_entry_
+
+ static void
+ parse_string(const char *s, struct xt_string_info *info)
+-{
++{
+ /* xt_string does not need \0 at the end of the pattern */
+- if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
+- memcpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
+- info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
+- return;
+- }
+- xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
++ if (strlen(s) > sizeof(info->pattern))
++ xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
++
++ info->patlen = strnlen(s, sizeof(info->pattern));
++ memcpy(info->pattern, s, info->patlen);
+ }
+
+ static void
diff --git a/package/network/utils/iptables/patches/101-remove-check-already.patch b/package/network/utils/iptables/patches/101-remove-check-already.patch
index 16afafec2d5..bd49224c70b 100644
--- a/package/network/utils/iptables/patches/101-remove-check-already.patch
+++ b/package/network/utils/iptables/patches/101-remove-check-already.patch
@@ -1,6 +1,6 @@
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
-@@ -968,12 +968,6 @@ void xtables_register_match(struct xtabl
+@@ -1093,12 +1093,6 @@ void xtables_register_match(struct xtabl
struct xtables_match **pos;
bool seen_myself = false;
@@ -13,7 +13,7 @@
if (me->version == NULL) {
fprintf(stderr, "%s: match %s<%u> is missing a version\n",
xt_params->program_name, me->name, me->revision);
-@@ -1152,12 +1146,6 @@ void xtables_register_target(struct xtab
+@@ -1277,12 +1271,6 @@ void xtables_register_target(struct xtab
struct xtables_target **pos;
bool seen_myself = false;
diff --git a/package/network/utils/iptables/patches/102-iptables-disable-modprobe.patch b/package/network/utils/iptables/patches/102-iptables-disable-modprobe.patch
index b8e19c781a1..710f481cac8 100644
--- a/package/network/utils/iptables/patches/102-iptables-disable-modprobe.patch
+++ b/package/network/utils/iptables/patches/102-iptables-disable-modprobe.patch
@@ -1,6 +1,15 @@
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
-@@ -403,6 +403,7 @@ static char *get_modprobe(void)
+@@ -476,7 +476,7 @@ char *xtables_strdup(const char *s)
+ return dup;
+ }
+
+-static char *get_modprobe(void)
++__attribute__((unused)) static char *get_modprobe(void)
+ {
+ int procfile;
+ char *ret;
+@@ -511,6 +511,7 @@ static char *get_modprobe(void)
int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
{
@@ -8,7 +17,7 @@
char *buf = NULL;
char *argv[4];
int status;
-@@ -437,6 +438,7 @@ int xtables_insmod(const char *modname,
+@@ -545,6 +546,7 @@ int xtables_insmod(const char *modname,
free(buf);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
return 0;
diff --git a/package/network/utils/iptables/patches/200-configurable_builtin.patch b/package/network/utils/iptables/patches/200-configurable_builtin.patch
index 6d7b5b5822c..75c29e1e9ca 100644
--- a/package/network/utils/iptables/patches/200-configurable_builtin.patch
+++ b/package/network/utils/iptables/patches/200-configurable_builtin.patch
@@ -60,7 +60,7 @@
.SECONDARY:
-@@ -161,11 +181,11 @@ libext4.a: initext4.o ${libext4_objs}
+@@ -163,11 +183,11 @@ libext4.a: initext4.o ${libext4_objs}
libext6.a: initext6.o ${libext6_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
diff --git a/package/network/utils/iptables/patches/600-shared-libext.patch b/package/network/utils/iptables/patches/600-shared-libext.patch
index 819f628f9ef..838b1ffa660 100644
--- a/package/network/utils/iptables/patches/600-shared-libext.patch
+++ b/package/network/utils/iptables/patches/600-shared-libext.patch
@@ -18,7 +18,7 @@
-include .*.d
-@@ -164,22 +164,22 @@ xt_connlabel_LIBADD = @libnetfilter_conn
+@@ -166,22 +166,22 @@ xt_connlabel_LIBADD = @libnetfilter_conn
# handling code in the Makefiles.
#
lib%.o: ${srcdir}/lib%.c
diff --git a/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch b/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch
index cc451ef9593..09db3900066 100644
--- a/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch
+++ b/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch
@@ -1,6 +1,6 @@
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
-@@ -1395,6 +1395,7 @@ static int conntrack3_mt6_xlate(struct x
+@@ -1399,6 +1399,7 @@ static int conntrack3_mt6_xlate(struct x
}
static struct xtables_match conntrack_mt_reg[] = {
@@ -8,7 +8,7 @@
{
.version = XTABLES_VERSION,
.name = "conntrack",
-@@ -1470,6 +1471,7 @@ static struct xtables_match conntrack_mt
+@@ -1474,6 +1475,7 @@ static struct xtables_match conntrack_mt
.alias = conntrack_print_name_alias,
.x6_options = conntrack2_mt_opts,
},
@@ -16,7 +16,7 @@
{
.version = XTABLES_VERSION,
.name = "conntrack",
-@@ -1502,6 +1504,7 @@ static struct xtables_match conntrack_mt
+@@ -1506,6 +1508,7 @@ static struct xtables_match conntrack_mt
.x6_options = conntrack3_mt_opts,
.xlate = conntrack3_mt6_xlate,
},
@@ -24,7 +24,7 @@
{
.family = NFPROTO_UNSPEC,
.name = "state",
-@@ -1532,6 +1535,8 @@ static struct xtables_match conntrack_mt
+@@ -1536,6 +1539,8 @@ static struct xtables_match conntrack_mt
.x6_parse = state_ct23_parse,
.x6_options = state_opts,
},
@@ -33,7 +33,7 @@
{
.family = NFPROTO_UNSPEC,
.name = "state",
-@@ -1561,6 +1566,7 @@ static struct xtables_match conntrack_mt
+@@ -1565,6 +1570,7 @@ static struct xtables_match conntrack_mt
.x6_parse = state_parse,
.x6_options = state_opts,
},
@@ -77,7 +77,7 @@
void _init(void)
--- a/extensions/libxt_multiport.c
+++ b/extensions/libxt_multiport.c
-@@ -571,6 +571,7 @@ static int multiport_xlate6_v1(struct xt
+@@ -591,6 +591,7 @@ static int multiport_xlate6_v1(struct xt
}
static struct xtables_match multiport_mt_reg[] = {
@@ -85,7 +85,7 @@
{
.family = NFPROTO_IPV4,
.name = "multiport",
-@@ -601,6 +602,7 @@ static struct xtables_match multiport_mt
+@@ -621,6 +622,7 @@ static struct xtables_match multiport_mt
.x6_options = multiport_opts,
.xlate = multiport_xlate6,
},
diff --git a/package/network/utils/iw/Makefile b/package/network/utils/iw/Makefile
index 8e11046189c..528f6868b23 100644
--- a/package/network/utils/iw/Makefile
+++ b/package/network/utils/iw/Makefile
@@ -8,16 +8,18 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=iw
-PKG_VERSION:=5.9-8fab0c9e
-PKG_RELEASE:=$(AUTORELEASE)
-
-PKG_SOURCE_PROTO:=git
-PKG_SOURCE_URL:=https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git
-PKG_SOURCE_VERSION:=8fab0c9ee9db217587a58efcc37421c86edcb638
-PKG_MIRROR_HASH:=797b322bc03952f3127ae0a7da476c14ada1bbe9a9ae234a56dd6f864c568e16
+PKG_VERSION:=5.19
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/software/network/iw
+PKG_HASH:=f167bbe947dd53bb9ebc0c1dcef5db6ad73ac1d6084f2c6f9376c5c360cc4d4e
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
+PKG_CPE_ID:=cpe:/a:kernel:iw
+
+PKG_BUILD_FLAGS:=gc-sections lto
include $(INCLUDE_DIR)/package.mk
@@ -47,8 +49,7 @@ TARGET_CPPFLAGS:= \
-I$(STAGING_DIR)/usr/include/libnl-tiny \
$(TARGET_CPPFLAGS) \
-DCONFIG_LIBNL20 \
- -D_GNU_SOURCE \
- -flto
+ -D_GNU_SOURCE
ifeq ($(BUILD_VARIANT),full)
TARGET_CPPFLAGS += -DIW_FULL
@@ -56,8 +57,8 @@ ifeq ($(BUILD_VARIANT),full)
endif
MAKE_FLAGS += \
- CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -ffunction-sections -fdata-sections" \
- LDFLAGS="$(TARGET_LDFLAGS) -Wl,--gc-sections -flto" \
+ CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
+ LDFLAGS="$(TARGET_LDFLAGS)" \
NL1FOUND="" NL2FOUND=Y \
NLLIBNAME="libnl-tiny" \
LIBS="-lm -lnl-tiny" \
diff --git a/package/network/utils/iw/patches/001-nl80211_h_sync.patch b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
deleted file mode 100644
index 1d6ea0fae0f..00000000000
--- a/package/network/utils/iw/patches/001-nl80211_h_sync.patch
+++ /dev/null
@@ -1,302 +0,0 @@
---- a/nl80211.h
-+++ b/nl80211.h
-@@ -655,6 +655,9 @@
- * When a security association was established on an 802.1X network using
- * fast transition, this event should be followed by an
- * %NL80211_CMD_PORT_AUTHORIZED event.
-+ * Following a %NL80211_CMD_ROAM event userspace can issue
-+ * %NL80211_CMD_GET_SCAN in order to obtain the scan information for the
-+ * new BSS the card/driver roamed to.
- * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
- * userspace that a connection was dropped by the AP or due to other
- * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
-@@ -757,7 +760,8 @@
- * of any other interfaces, and other interfaces will again take
- * precedence when they are used.
- *
-- * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
-+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface
-+ * (no longer supported).
- *
- * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
- * multicast to unicast conversion. When enabled, all multicast packets
-@@ -1177,6 +1181,10 @@
- * includes the contents of the frame. %NL80211_ATTR_ACK flag is included
- * if the recipient acknowledged the frame.
- *
-+ * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is
-+ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
-+ * specify the wiphy index to be applied to.
-+ *
- * @NL80211_CMD_MAX: highest used command number
- * @__NL80211_CMD_AFTER_LAST: internal use
- */
-@@ -1407,6 +1415,8 @@ enum nl80211_commands {
-
- NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
-
-+ NL80211_CMD_SET_SAR_SPECS,
-+
- /* add new commands above here */
-
- /* used to define NL80211_CMD_MAX below */
-@@ -1750,8 +1760,9 @@ enum nl80211_commands {
- * specify just a single bitrate, which is to be used for the beacon.
- * The driver must also specify support for this with the extended
- * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
-- * NL80211_EXT_FEATURE_BEACON_RATE_HT and
-- * NL80211_EXT_FEATURE_BEACON_RATE_VHT.
-+ * NL80211_EXT_FEATURE_BEACON_RATE_HT,
-+ * NL80211_EXT_FEATURE_BEACON_RATE_VHT and
-+ * NL80211_EXT_FEATURE_BEACON_RATE_HE.
- *
- * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
- * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
-@@ -1955,8 +1966,15 @@ enum nl80211_commands {
- * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
- * probe-response frame. The DA field in the 802.11 header is zero-ed out,
- * to be filled by the FW.
-- * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
-- * this feature. Currently, only supported in mac80211 drivers.
-+ * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
-+ * this feature during association. This is a flag attribute.
-+ * Currently only supported in mac80211 drivers.
-+ * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable
-+ * this feature during association. This is a flag attribute.
-+ * Currently only supported in mac80211 drivers.
-+ * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable
-+ * this feature during association. This is a flag attribute.
-+ * Currently only supported in mac80211 drivers.
- * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
- * ATTR_HT_CAPABILITY to which attention should be paid.
- * Currently, only mac80211 NICs support this feature.
-@@ -2077,7 +2095,8 @@ enum nl80211_commands {
- * until the channel switch event.
- * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
- * must be blocked on the current channel (before the channel switch
-- * operation).
-+ * operation). Also included in the channel switch started event if quiet
-+ * was requested by the AP.
- * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
- * for the time while performing a channel switch.
- * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel
-@@ -2527,6 +2546,23 @@ enum nl80211_commands {
- * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
- * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
- *
-+ * @NL80211_ATTR_SAE_PWE: Indicates the mechanism(s) allowed for SAE PWE
-+ * derivation in WPA3-Personal networks which are using SAE authentication.
-+ * This is a u8 attribute that encapsulates one of the values from
-+ * &enum nl80211_sae_pwe_mechanism.
-+ *
-+ * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when
-+ * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields
-+ * of %nl80211_sar_attrs which specifies the sar type and related
-+ * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs.
-+ *
-+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
-+ * disassoc events to indicate that an immediate reconnect to the AP
-+ * is desired.
-+ *
-+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
-+ * transmit power to stay within regulatory limits. u32, dBi.
-+ *
- * @NUM_NL80211_ATTR: total number of nl80211_attrs available
- * @NL80211_ATTR_MAX: highest attribute number currently defined
- * @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -3016,6 +3052,16 @@ enum nl80211_attrs {
- NL80211_ATTR_S1G_CAPABILITY,
- NL80211_ATTR_S1G_CAPABILITY_MASK,
-
-+ NL80211_ATTR_SAE_PWE,
-+
-+ NL80211_ATTR_RECONNECT_REQUESTED,
-+
-+ NL80211_ATTR_SAR_SPEC,
-+
-+ NL80211_ATTR_DISABLE_HE,
-+
-+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
-+
- /* add attributes here, update the policy in nl80211.c */
-
- __NL80211_ATTR_AFTER_LAST,
-@@ -5896,6 +5942,19 @@ enum nl80211_feature_flags {
- * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports
- * unsolicited broadcast probe response transmission
- *
-+ * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate
-+ * configuration (AP/mesh) with HE rates.
-+ *
-+ * @NL80211_EXT_FEATURE_SECURE_LTF: Device supports secure LTF measurement
-+ * exchange protocol.
-+ *
-+ * @NL80211_EXT_FEATURE_SECURE_RTT: Device supports secure RTT measurement
-+ * exchange protocol.
-+ *
-+ * @NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE: Device supports management
-+ * frame protection for all management frames exchanged during the
-+ * negotiation and range measurement procedure.
-+ *
- * @NUM_NL80211_EXT_FEATURES: number of extended features.
- * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
- */
-@@ -5956,6 +6015,10 @@ enum nl80211_ext_feature_index {
- NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
- NL80211_EXT_FEATURE_FILS_DISCOVERY,
- NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
-+ NL80211_EXT_FEATURE_BEACON_RATE_HE,
-+ NL80211_EXT_FEATURE_SECURE_LTF,
-+ NL80211_EXT_FEATURE_SECURE_RTT,
-+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
-
- /* add new features before the definition below */
- NUM_NL80211_EXT_FEATURES,
-@@ -6253,11 +6316,13 @@ struct nl80211_vendor_cmd_info {
- * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
- * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
- * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
-+ * @NL80211_TDLS_PEER_HE: TDLS peer is HE capable.
- */
- enum nl80211_tdls_peer_capability {
- NL80211_TDLS_PEER_HT = 1<<0,
- NL80211_TDLS_PEER_VHT = 1<<1,
- NL80211_TDLS_PEER_WMM = 1<<2,
-+ NL80211_TDLS_PEER_HE = 1<<3,
- };
-
- /**
-@@ -6849,6 +6914,9 @@ enum nl80211_peer_measurement_ftm_capa {
- * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
- * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
- * ranging will be used.
-+ * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only
-+ * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or
-+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set.
- *
- * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
- * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
-@@ -6867,6 +6935,7 @@ enum nl80211_peer_measurement_ftm_req {
- NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
- NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
- NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
-+ NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK,
-
- /* keep last */
- NUM_NL80211_PMSR_FTM_REQ_ATTR,
-@@ -7124,4 +7193,115 @@ enum nl80211_unsol_bcast_probe_resp_attr
- NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX =
- __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1
- };
-+
-+/**
-+ * enum nl80211_sae_pwe_mechanism - The mechanism(s) allowed for SAE PWE
-+ * derivation. Applicable only when WPA3-Personal SAE authentication is
-+ * used.
-+ *
-+ * @NL80211_SAE_PWE_UNSPECIFIED: not specified, used internally to indicate that
-+ * attribute is not present from userspace.
-+ * @NL80211_SAE_PWE_HUNT_AND_PECK: hunting-and-pecking loop only
-+ * @NL80211_SAE_PWE_HASH_TO_ELEMENT: hash-to-element only
-+ * @NL80211_SAE_PWE_BOTH: both hunting-and-pecking loop and hash-to-element
-+ * can be used.
-+ */
-+enum nl80211_sae_pwe_mechanism {
-+ NL80211_SAE_PWE_UNSPECIFIED,
-+ NL80211_SAE_PWE_HUNT_AND_PECK,
-+ NL80211_SAE_PWE_HASH_TO_ELEMENT,
-+ NL80211_SAE_PWE_BOTH,
-+};
-+
-+/**
-+ * enum nl80211_sar_type - type of SAR specs
-+ *
-+ * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit
-+ *
-+ */
-+enum nl80211_sar_type {
-+ NL80211_SAR_TYPE_POWER,
-+
-+ /* add new type here */
-+
-+ /* Keep last */
-+ NUM_NL80211_SAR_TYPE,
-+};
-+
-+/**
-+ * enum nl80211_sar_attrs - Attributes for SAR spec
-+ *
-+ * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type.
-+ *
-+ * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power
-+ * limit specifications. Each specification contains a set
-+ * of %nl80211_sar_specs_attrs.
-+ *
-+ * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER
-+ * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX.
-+ *
-+ * For sar_capa dump, it contains array of
-+ * %NL80211_SAR_ATTR_SPECS_START_FREQ
-+ * and %NL80211_SAR_ATTR_SPECS_END_FREQ.
-+ *
-+ * @__NL80211_SAR_ATTR_LAST: Internal
-+ * @NL80211_SAR_ATTR_MAX: highest sar attribute
-+ *
-+ * These attributes are used with %NL80211_CMD_SET_SAR_SPEC
-+ */
-+enum nl80211_sar_attrs {
-+ __NL80211_SAR_ATTR_INVALID,
-+
-+ NL80211_SAR_ATTR_TYPE,
-+ NL80211_SAR_ATTR_SPECS,
-+
-+ __NL80211_SAR_ATTR_LAST,
-+ NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1,
-+};
-+
-+/**
-+ * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs
-+ *
-+ * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual
-+ * power limit value in units of 0.25 dBm if type is
-+ * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm).
-+ * 0 means userspace doesn't have SAR limitation on this associated range.
-+ *
-+ * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the
-+ * index of exported freq range table and the associated power limitation
-+ * is applied to this range.
-+ *
-+ * Userspace isn't required to set all the ranges advertised by WLAN driver,
-+ * and userspace can skip some certain ranges. These skipped ranges don't
-+ * have SAR limitations, and they are same as setting the
-+ * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any
-+ * value higher than regulatory allowed value just means SAR power
-+ * limitation is removed, but it's required to set at least one range.
-+ * It's not allowed to set duplicated range in one SET operation.
-+ *
-+ * Every SET operation overwrites previous SET operation.
-+ *
-+ * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start
-+ * frequency of this range edge when registering SAR capability to wiphy.
-+ * It's not a channel center frequency. The unit is kHz.
-+ *
-+ * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end
-+ * frequency of this range edge when registering SAR capability to wiphy.
-+ * It's not a channel center frequency. The unit is kHz.
-+ *
-+ * @__NL80211_SAR_ATTR_SPECS_LAST: Internal
-+ * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute
-+ */
-+enum nl80211_sar_specs_attrs {
-+ __NL80211_SAR_ATTR_SPECS_INVALID,
-+
-+ NL80211_SAR_ATTR_SPECS_POWER,
-+ NL80211_SAR_ATTR_SPECS_RANGE_INDEX,
-+ NL80211_SAR_ATTR_SPECS_START_FREQ,
-+ NL80211_SAR_ATTR_SPECS_END_FREQ,
-+
-+ __NL80211_SAR_ATTR_SPECS_LAST,
-+ NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
-+};
-+
- #endif /* __LINUX_NL80211_H */
diff --git a/package/network/utils/iw/patches/010-Revert-iw-allow-specifying-CFLAGS-LIBS-externally.patch b/package/network/utils/iw/patches/010-Revert-iw-allow-specifying-CFLAGS-LIBS-externally.patch
new file mode 100644
index 00000000000..1254efa9c70
--- /dev/null
+++ b/package/network/utils/iw/patches/010-Revert-iw-allow-specifying-CFLAGS-LIBS-externally.patch
@@ -0,0 +1,68 @@
+From 1f3706d10812d70adefe32fe0d7d3a3ec25374f0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 21 Nov 2021 00:02:57 +0100
+Subject: Revert "iw: allow specifying CFLAGS/LIBS externally"
+
+This reverts commit 1325244b77d56fd7a16d1e35fdae0efc151920b1.
+
+The OpenWrt build system provides the CFLAGS and LIBS names from the
+package Makefile to overwrite them for libnl-tiny. This is not possible
+after this upstream change which we revert here any more
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ Makefile | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -45,30 +45,30 @@ NLLIBNAME = libnl-1
+ endif
+
+ ifeq ($(NL2FOUND),Y)
+-override CFLAGS += -DCONFIG_LIBNL20
+-override LIBS += -lnl-genl
++CFLAGS += -DCONFIG_LIBNL20
++LIBS += -lnl-genl
+ NLLIBNAME = libnl-2.0
+ endif
+
+ ifeq ($(NL3xFOUND),Y)
+ # libnl 3.2 might be found as 3.2 and 3.0
+ NL3FOUND = N
+-override CFLAGS += -DCONFIG_LIBNL30
+-override LIBS += -lnl-genl-3
++CFLAGS += -DCONFIG_LIBNL30
++LIBS += -lnl-genl-3
+ NLLIBNAME = libnl-3.0
+ endif
+
+ ifeq ($(NL3FOUND),Y)
+-override CFLAGS += -DCONFIG_LIBNL30
+-override LIBS += -lnl-genl
++CFLAGS += -DCONFIG_LIBNL30
++LIBS += -lnl-genl
+ NLLIBNAME = libnl-3.0
+ endif
+
+ # nl-3.1 has a broken libnl-gnl-3.1.pc file
+ # as show by pkg-config --debug --libs --cflags --exact-version=3.1 libnl-genl-3.1;echo $?
+ ifeq ($(NL31FOUND),Y)
+-override CFLAGS += -DCONFIG_LIBNL30
+-override LIBS += -lnl-genl
++CFLAGS += -DCONFIG_LIBNL30
++LIBS += -lnl-genl
+ NLLIBNAME = libnl-3.1
+ endif
+
+@@ -76,8 +76,8 @@ ifeq ($(NLLIBNAME),)
+ $(error Cannot find development files for any supported version of libnl)
+ endif
+
+-override LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME))
+-override CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME))
++LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME))
++CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME))
+ endif # NO_PKG_CONFIG
+
+ ifeq ($(V),1)
diff --git a/package/network/utils/iw/patches/120-antenna_gain.patch b/package/network/utils/iw/patches/120-antenna_gain.patch
deleted file mode 100644
index f8d537fe1ed..00000000000
--- a/package/network/utils/iw/patches/120-antenna_gain.patch
+++ /dev/null
@@ -1,33 +0,0 @@
---- a/phy.c
-+++ b/phy.c
-@@ -855,3 +855,30 @@ static int handle_get_txq(struct nl80211
- COMMAND(get, txq, "",
- NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
- "Get TXQ parameters.");
-+
-+static int handle_antenna_gain(struct nl80211_state *state,
-+ struct nl_msg *msg,
-+ int argc, char **argv,
-+ enum id_input id)
-+{
-+ char *endptr;
-+ int dbm;
-+
-+ /* get the required args */
-+ if (argc != 1)
-+ return 1;
-+
-+ dbm = strtol(argv[0], &endptr, 10);
-+ if (*endptr)
-+ return 2;
-+
-+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_GAIN, dbm);
-+
-+ return 0;
-+
-+ nla_put_failure:
-+ return -ENOBUFS;
-+}
-+COMMAND(set, antenna_gain, "<antenna gain in dBm>",
-+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna_gain,
-+ "Specify antenna gain.");
diff --git a/package/network/utils/iw/patches/200-reduce_size.patch b/package/network/utils/iw/patches/200-reduce_size.patch
index 83e11405cbd..86219945242 100644
--- a/package/network/utils/iw/patches/200-reduce_size.patch
+++ b/package/network/utils/iw/patches/200-reduce_size.patch
@@ -1,6 +1,6 @@
--- a/event.c
+++ b/event.c
-@@ -956,6 +956,7 @@ static int print_event(struct nl_msg *ms
+@@ -971,6 +971,7 @@ static int print_event(struct nl_msg *ms
}
switch (gnlh->cmd) {
@@ -8,7 +8,7 @@
case NL80211_CMD_NEW_WIPHY:
printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
break;
-@@ -991,6 +992,7 @@ static int print_event(struct nl_msg *ms
+@@ -1006,6 +1007,7 @@ static int print_event(struct nl_msg *ms
case NL80211_CMD_SCHED_SCAN_RESULTS:
printf("got scheduled scan results\n");
break;
@@ -16,7 +16,7 @@
case NL80211_CMD_WIPHY_REG_CHANGE:
case NL80211_CMD_REG_CHANGE:
if (gnlh->cmd == NL80211_CMD_WIPHY_REG_CHANGE)
-@@ -1073,6 +1075,7 @@ static int print_event(struct nl_msg *ms
+@@ -1088,6 +1090,7 @@ static int print_event(struct nl_msg *ms
mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
printf("del station %s\n", macbuf);
break;
@@ -24,9 +24,9 @@
case NL80211_CMD_JOIN_IBSS:
mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
printf("IBSS %s joined\n", macbuf);
-@@ -1271,9 +1274,9 @@ static int print_event(struct nl_msg *ms
- case NL80211_CMD_CH_SWITCH_NOTIFY:
- parse_ch_switch_notify(tb, gnlh->cmd);
+@@ -1295,9 +1298,9 @@ static int print_event(struct nl_msg *ms
+ case NL80211_CMD_ASSOC_COMEBACK: /* 147 */
+ parse_assoc_comeback(tb, gnlh->cmd);
break;
+#endif
default:
@@ -38,7 +38,7 @@
--- a/info.c
+++ b/info.c
-@@ -216,6 +216,7 @@ next:
+@@ -309,6 +309,7 @@ next:
}
}
@@ -46,7 +46,7 @@
if (tb_band[NL80211_BAND_ATTR_RATES]) {
printf("\t\tBitrates (non-HT):\n");
nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
-@@ -232,6 +233,7 @@ next:
+@@ -325,6 +326,7 @@ next:
printf("\n");
}
}
@@ -54,7 +54,7 @@
}
}
-@@ -297,6 +299,7 @@ next:
+@@ -390,6 +392,7 @@ next:
printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage);
}
@@ -62,7 +62,7 @@
if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) {
int num = nla_len(tb_msg[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
int i;
-@@ -308,6 +311,7 @@ next:
+@@ -401,6 +404,7 @@ next:
cipher_name(ciphers[i]));
}
}
@@ -70,21 +70,19 @@
if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX] &&
tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX])
-@@ -327,11 +331,13 @@ next:
- printf("\t\t * %s\n", iftype_name(nla_type(nl_mode)));
- }
+@@ -418,9 +422,11 @@ next:
+ print_iftype_list("\tSupported interface modes", "\t\t",
+ tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
+#ifdef IW_FULL
- if (tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES]) {
- printf("\tsoftware interface modes (can always be added):\n");
- nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES], rem_mode)
- printf("\t\t * %s\n", iftype_name(nla_type(nl_mode)));
- }
+ if (tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES])
+ print_iftype_list("\tsoftware interface modes (can always be added)",
+ "\t\t", tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES]);
+#endif
if (tb_msg[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
struct nlattr *nl_combi;
-@@ -428,6 +434,7 @@ broken_combination:
+@@ -510,6 +516,7 @@ broken_combination:
printf("\tinterface combinations are not supported\n");
}
@@ -92,7 +90,7 @@
if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
printf("\tSupported commands:\n");
nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], rem_cmd)
-@@ -525,6 +532,7 @@ broken_combination:
+@@ -607,6 +614,7 @@ broken_combination:
printf("\t\t * wake up on TCP connection\n");
}
}
@@ -100,7 +98,7 @@
if (tb_msg[NL80211_ATTR_ROAM_SUPPORT])
printf("\tDevice supports roaming.\n");
-@@ -563,6 +571,7 @@ broken_combination:
+@@ -645,6 +653,7 @@ broken_combination:
}
}
@@ -108,7 +106,7 @@
if (tb_msg[NL80211_ATTR_FEATURE_FLAGS]) {
unsigned int features = nla_get_u32(tb_msg[NL80211_ATTR_FEATURE_FLAGS]);
-@@ -627,6 +636,7 @@ broken_combination:
+@@ -709,6 +718,7 @@ broken_combination:
if (features & NL80211_FEATURE_ND_RANDOM_MAC_ADDR)
printf("\tDevice supports randomizing MAC-addr in net-detect scans.\n");
}
@@ -116,7 +114,7 @@
if (tb_msg[NL80211_ATTR_TDLS_SUPPORT])
printf("\tDevice supports T-DLS.\n");
-@@ -762,6 +772,7 @@ TOPLEVEL(list, NULL, NL80211_CMD_GET_WIP
+@@ -774,6 +784,7 @@ TOPLEVEL(list, NULL, NL80211_CMD_GET_WIP
"List all wireless devices and their capabilities.");
TOPLEVEL(phy, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info, NULL);
@@ -124,7 +122,7 @@
static int handle_commands(struct nl80211_state *state, struct nl_msg *msg,
int argc, char **argv, enum id_input id)
{
-@@ -773,6 +784,7 @@ static int handle_commands(struct nl8021
+@@ -785,6 +796,7 @@ static int handle_commands(struct nl8021
}
TOPLEVEL(commands, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_NONE, handle_commands,
"list all known commands and their decimal & hex value");
@@ -187,23 +185,29 @@
};
static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
-@@ -2326,6 +2331,7 @@ void print_ies(unsigned char *ie, int ie
- ieprinters[ie[0]].flags & BIT(ptype)) {
- print_ie(&ieprinters[ie[0]],
- ie[0], ie[1], ie + 2, &ie_buffer);
+@@ -2080,8 +2085,10 @@ static void print_wifi_wps(const uint8_t
+
+ static const struct ie_print wifiprinters[] = {
+ [1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
+#ifdef IW_FULL
- } else if (ie[0] == 221 /* vendor */) {
- print_vendor(ie[1], ie + 2, unknown, ptype);
- } else if (ie[0] == 255 /* extension */) {
-@@ -2337,6 +2343,7 @@ void print_ies(unsigned char *ie, int ie
- for (i=0; i<ie[1]; i++)
- printf(" %.2x", ie[2+i]);
- printf("\n");
+ [2] = { "WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN), },
+ [4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), },
+#endif
- }
- ielen -= ie[1] + 2;
- ie += ie[1] + 2;
-@@ -2377,6 +2384,7 @@ static void print_capa_non_dmg(__u16 cap
+ };
+
+ static inline void print_p2p(const uint8_t type, uint8_t len,
+@@ -2244,6 +2251,10 @@ static void print_vendor(unsigned char l
+ return;
+ }
+
++#ifdef IW_FULL
++ return;
++#endif
++
+ if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
+ if (data[3] < ARRAY_SIZE(wfa_printers) &&
+ wfa_printers[data[3]].name &&
+@@ -2377,6 +2388,7 @@ static void print_capa_non_dmg(__u16 cap
printf(" ESS");
if (capa & WLAN_CAPABILITY_IBSS)
printf(" IBSS");
@@ -211,7 +215,7 @@
if (capa & WLAN_CAPABILITY_CF_POLLABLE)
printf(" CfPollable");
if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
-@@ -2405,6 +2413,7 @@ static void print_capa_non_dmg(__u16 cap
+@@ -2405,6 +2417,7 @@ static void print_capa_non_dmg(__u16 cap
printf(" DelayedBACK");
if (capa & WLAN_CAPABILITY_IMM_BACK)
printf(" ImmediateBACK");
@@ -219,7 +223,7 @@
}
static int print_bss_handler(struct nl_msg *msg, void *arg)
-@@ -2489,8 +2498,10 @@ static int print_bss_handler(struct nl_m
+@@ -2489,8 +2502,10 @@ static int print_bss_handler(struct nl_m
if (bss[NL80211_BSS_FREQUENCY]) {
int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
printf("\tfreq: %d\n", freq);
@@ -230,7 +234,7 @@
}
if (bss[NL80211_BSS_BEACON_INTERVAL])
printf("\tbeacon interval: %d TUs\n",
-@@ -2684,6 +2695,7 @@ static int handle_stop_sched_scan(struct
+@@ -2684,6 +2699,7 @@ static int handle_stop_sched_scan(struct
return 0;
}
@@ -238,7 +242,7 @@
COMMAND(scan, sched_start,
SCHED_SCAN_OPTIONS,
NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
-@@ -2694,3 +2706,4 @@ COMMAND(scan, sched_start,
+@@ -2694,3 +2710,4 @@ COMMAND(scan, sched_start,
COMMAND(scan, sched_stop, "",
NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
"Stop an ongoing scheduled scan.");
@@ -288,7 +292,7 @@
ifeq ($(NO_PKG_CONFIG),)
--- a/station.c
+++ b/station.c
-@@ -777,10 +777,12 @@ static int handle_station_set_plink(stru
+@@ -791,10 +791,12 @@ static int handle_station_set_plink(stru
nla_put_failure:
return -ENOBUFS;
}
@@ -301,7 +305,7 @@
static int handle_station_set_vlan(struct nl80211_state *state,
struct nl_msg *msg,
-@@ -875,11 +877,13 @@ static int handle_station_set_mesh_power
+@@ -889,11 +891,13 @@ static int handle_station_set_mesh_power
nla_put_failure:
return -ENOBUFS;
}
@@ -317,7 +321,7 @@
struct nl_msg *msg,
--- a/interface.c
+++ b/interface.c
-@@ -627,9 +627,11 @@ static int handle_interface_wds_peer(str
+@@ -629,9 +629,11 @@ static int handle_interface_wds_peer(str
nla_put_failure:
return -ENOBUFS;
}
@@ -329,7 +333,7 @@
static int set_mcast_rate(struct nl80211_state *state,
struct nl_msg *msg,
-@@ -719,6 +721,7 @@ static int handle_chan(struct nl80211_st
+@@ -721,6 +723,7 @@ static int handle_chan(struct nl80211_st
return handle_chanfreq(state, msg, true, argc, argv, id);
}
@@ -337,7 +341,7 @@
SECTION(switch);
COMMAND(switch, freq,
"<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]\n"
-@@ -990,3 +993,4 @@ COMMAND(set, tidconf, "[peer <MAC addres
+@@ -992,3 +995,4 @@ COMMAND(set, tidconf, "[peer <MAC addres
" $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x2 bitrates auto\n"
" $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x2 bitrates limit vht-mcs-5 4:9\n"
);
diff --git a/package/network/utils/iwinfo/Makefile b/package/network/utils/iwinfo/Makefile
index 9dbf91efe9f..4fef2babbb2 100644
--- a/package/network/utils/iwinfo/Makefile
+++ b/package/network/utils/iwinfo/Makefile
@@ -11,13 +11,15 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/iwinfo.git
-PKG_SOURCE_DATE:=2021-07-11
-PKG_SOURCE_VERSION:=a0a0e02dd91d14a50155390d5fd3b95d6ec87bf4
-PKG_MIRROR_HASH:=7b4f745c2cace836e57bd116399973d9ac32cee7f98d4628a17395caa3d0cebc
+PKG_SOURCE_DATE:=2023-11-19
+PKG_SOURCE_VERSION:=a34977c0760c93480491c8eb94da656b57d7f4cc
+PKG_MIRROR_HASH:=cb01671a2a9155f8ba55751ab1fe28488c5821212dd97ba5b79653640abb787e
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=GPL-2.0
-IWINFO_ABI_VERSION:=20210430
+PKG_BUILD_FLAGS:=no-lto
+
+IWINFO_ABI_VERSION:=20230701
include $(INCLUDE_DIR)/package.mk
diff --git a/package/network/utils/layerscape/restool/Makefile b/package/network/utils/layerscape/restool/Makefile
index 73fa8e4d9ea..5919f42ff2a 100644
--- a/package/network/utils/layerscape/restool/Makefile
+++ b/package/network/utils/layerscape/restool/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=restool
-PKG_VERSION:=LSDK-20.04
-PKG_RELEASE:=2
+PKG_VERSION:=21.08
+PKG_RELEASE:=4
PKG_SOURCE_PROTO:=git
-PKG_SOURCE_URL:=https://source.codeaurora.org/external/qoriq/qoriq-components/restool
-PKG_SOURCE_VERSION:=f0cec094e4c6d1c975b377203a3bf994ba9325a9
-PKG_MIRROR_HASH:=1863acfaef319e6b277671fead51df0a31bdddb59022080d86b7d81da0bc8490
+PKG_SOURCE_URL:=https://github.com/nxp-qoriq/restool
+PKG_SOURCE_VERSION:=LSDK-21.08
+PKG_MIRROR_HASH:=0396644927b8f3da20183227562f695c8063d3d4c6bb606e8f31dda450e962e4
PKG_FLAGS:=nonshared
diff --git a/package/network/utils/layerscape/restool/patches/0001-restool-fix-get_device_file-function.patch b/package/network/utils/layerscape/restool/patches/0001-restool-fix-get_device_file-function.patch
deleted file mode 100644
index 2745fd02a0e..00000000000
--- a/package/network/utils/layerscape/restool/patches/0001-restool-fix-get_device_file-function.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From 37f0f1550e7822584b858edde416a694fb902236 Mon Sep 17 00:00:00 2001
-From: Ioana Ciornei <ioana.ciornei@nxp.com>
-Date: Tue, 31 Jul 2018 13:33:20 +0300
-Subject: [PATCH] restool: fix get_device_file() function
-
-This patch fixes multiple problems encountered in the
-get_device_file() function:
- - The deprecated atoi() function is replaced by strtoul
- - An invalid memory access was being performed by using
- memory from dir->d_name even after closedir(). This is
- fixed by a strdup() on the device filename.
- - Also, error prints now print any relevant error code.
-
-Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
----
- restool.c | 44 ++++++++++++++++++++++++++++----------------
- 1 file changed, 28 insertions(+), 16 deletions(-)
-
-diff --git a/restool.c b/restool.c
-index 7553659..78fd1bf 100644
---- a/restool.c
-+++ b/restool.c
-@@ -1185,8 +1185,13 @@ out:
-
- static int get_device_file(void)
- {
-+ int num_dev_files = 0;
-+ struct dirent *dir;
- int error = 0;
-+ char *device;
- int num_char;
-+ long val;
-+ DIR *d;
-
- memset(restool.device_file, '\0', DEV_FILE_SIZE);
-
-@@ -1214,10 +1219,6 @@ static int get_device_file(void)
- goto out;
- }
- } else {
-- DIR *d;
-- struct dirent *dir;
-- int num_dev_files = 0;
-- char *dprc_index;
-
- d = opendir("/dev");
- if (!d) {
-@@ -1227,26 +1228,34 @@ static int get_device_file(void)
- }
- while ((dir = readdir(d)) != NULL) {
- if (strncmp(dir->d_name, "dprc.", 5) == 0) {
-- dprc_index = &dir->d_name[5];
-- num_dev_files += 1;
-+ if (num_dev_files == 0)
-+ device = strdup(dir->d_name);
-+ num_dev_files++;
- }
- }
- closedir(d);
-
- if (num_dev_files == 1) {
-- int temp_len = strlen(dprc_index);
-+ errno = 0;
-+ val = strtoul(&device[5], NULL, 0);
-+ if ((errno == ERANGE && val == LONG_MAX) ||
-+ ( errno != 0 && val == 0 )) {
-+ ERROR_PRINTF("error: device file malformed\n");
-+ error = -1;
-+ goto out_free_device;;
-+ }
-+ restool.root_dprc_id = val;
-
-- temp_len += 10;
-- num_char = sprintf(restool.device_file, "/dev/dprc.%s",
-- dprc_index);
-- if (num_char != temp_len) {
-- ERROR_PRINTF("sprintf error\n");
-+ num_char = snprintf(restool.device_file, DEV_FILE_SIZE,
-+ "/dev/dprc.%d", restool.root_dprc_id);
-+ if (num_char < 0 || num_char >= DEV_FILE_SIZE) {
-+ ERROR_PRINTF("error: device file malformed\n");
- error = -1;
-- goto out;
-+ goto out_free_device;
- }
-- restool.root_dprc_id = atoi(dprc_index);
-- if (access(restool.device_file, F_OK) != 0)
-- printf("no such dev file\n");
-+ error = access(restool.device_file, F_OK);
-+ if (error != 0)
-+ ERROR_PRINTF("error: access(%s) = %d\n", restool.device_file, error);
- } else {
- error = -1;
- if (num_dev_files == 0)
-@@ -1255,6 +1264,9 @@ static int get_device_file(void)
- ERROR_PRINTF("error: multiple root containers\n");
- }
- }
-+
-+out_free_device:
-+ free(device);
- out:
- return error;
- }
---
-2.17.1
-
diff --git a/package/network/utils/layerscape/restool/patches/remove-manpage.patch b/package/network/utils/layerscape/restool/patches/remove-manpage.patch
new file mode 100644
index 00000000000..5cb9e0a55fc
--- /dev/null
+++ b/package/network/utils/layerscape/restool/patches/remove-manpage.patch
@@ -0,0 +1,18 @@
+--- a/Makefile
++++ b/Makefile
+@@ -53,14 +53,13 @@ restool: $(OBJ)
+ %.1: %.md
+ pandoc --standalone --to man $^ -o $@
+
+-install: restool scripts/ls-main scripts/ls-append-dpl scripts/ls-debug scripts/restool_completion.sh $(MANPAGE)
++install: restool scripts/ls-main scripts/ls-append-dpl scripts/ls-debug scripts/restool_completion.sh
+ install -D -m 755 restool $(DESTDIR)$(bindir)/restool
+ install -D -m 755 scripts/ls-main $(DESTDIR)$(bindir)/ls-main
+ install -D -m 755 scripts/ls-append-dpl $(DESTDIR)$(bindir)/ls-append-dpl
+ install -D -m 755 scripts/ls-debug $(DESTDIR)$(bindir)/ls-debug
+ $(foreach symlink, $(RESTOOL_SCRIPT_SYMLINKS), sh -c "cd $(DESTDIR)$(bindir) && ln -sf ls-main $(symlink)" ;)
+ install -D -m 755 scripts/restool_completion.sh $(DESTDIR)$(bindir_completion)/restool
+- install -m 0644 -D $(MANPAGE) $(call get_manpage_destination,$(MANPAGE))
+
+ clean:
+ rm -f $(OBJ) $(MANPAGE) \
diff --git a/package/network/utils/linux-atm/Makefile b/package/network/utils/linux-atm/Makefile
index c74febcbbc3..43f4b6556b5 100644
--- a/package/network/utils/linux-atm/Makefile
+++ b/package/network/utils/linux-atm/Makefile
@@ -21,6 +21,7 @@ PKG_BUILD_PARALLEL:=1
PKG_LICENSE:=GPL-2.0+
PKG_CPE_ID:=cpe:/a:linux-atm:linux-atm
PKG_FIXUP:=autoreconf
+PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
@@ -98,6 +99,8 @@ endef
$(foreach t,$(ATM_DEBUG_TOOLS),$(eval $(call GenAtmPlugin,atm-$(t),$(t))))
+TARGET_CFLAGS += -I$(LINUX_DIR)/user_headers/include
+
define Build/Configure
$(call Build/Configure/Default)
# prevent autoheader invocation
diff --git a/package/network/utils/ltq-dsl-base/Makefile b/package/network/utils/ltq-dsl-base/Makefile
index 2ff069ca4dc..b51851f076e 100644
--- a/package/network/utils/ltq-dsl-base/Makefile
+++ b/package/network/utils/ltq-dsl-base/Makefile
@@ -17,7 +17,7 @@ define Package/ltq-dsl-base
CATEGORY:=Network
TITLE:=DSL related files for Intel/Lantiq DSL Chipsets
URL:=http://openwrt.org/
- DEPENDS:=@TARGET_lantiq +jshn
+ DEPENDS:=@(TARGET_lantiq||TARGET_ipq40xx) +jshn
endef
define Package/ltq-dsl-base/description
diff --git a/package/network/utils/nftables/Makefile b/package/network/utils/nftables/Makefile
index 7830596e847..38a8199d11d 100644
--- a/package/network/utils/nftables/Makefile
+++ b/package/network/utils/nftables/Makefile
@@ -1,24 +1,27 @@
-# Copyright (C) 2015 OpenWrt.org
+# SPDX-License-Identifier: GPL-2.0-only
#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
+# Copyright (C) 2015 OpenWrt.org
#
include $(TOPDIR)/rules.mk
PKG_NAME:=nftables
-PKG_VERSION:=0.9.6
-PKG_RELEASE:=2
+PKG_VERSION:=1.0.9
+PKG_RELEASE:=1
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://netfilter.org/projects/$(PKG_NAME)/files
-PKG_HASH:=68d6fdfe8ab02303e6b1f13968a4022da5b0120110eaee3233d806857937b66e
+PKG_HASH:=a3c304cd9ba061239ee0474f9afb938a9bb99d89b960246f66f0c3a0a85e14cd
+
PKG_MAINTAINER:=
PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
+PKG_BUILD_FLAGS:=lto
+
include $(INCLUDE_DIR)/package.mk
DISABLE_NLS:=
@@ -45,6 +48,7 @@ define Package/nftables-nojson
TITLE+= no JSON support
VARIANT:=nojson
DEFAULT_VARIANT:=1
+ CONFLICTS:=nftables-json
endef
define Package/nftables-json
@@ -58,8 +62,14 @@ ifeq ($(BUILD_VARIANT),json)
CONFIGURE_ARGS += --with-json
endif
-TARGET_CFLAGS += -flto
-TARGET_LDFLAGS += -flto
+define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/lib $(1)/usr/include
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/
+ $(CP) $(PKG_INSTALL_DIR)/usr/include/nftables $(1)/usr/include/
+ $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnftables.pc \
+ $(1)/usr/lib/pkgconfig/
+endef
define Package/nftables/install/Default
$(INSTALL_DIR) $(1)/usr/sbin
diff --git a/package/network/utils/rssileds/Makefile b/package/network/utils/rssileds/Makefile
index 2282d8c5b1a..5adc25e8d80 100644
--- a/package/network/utils/rssileds/Makefile
+++ b/package/network/utils/rssileds/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=rssileds
-PKG_RELEASE:=3
+PKG_RELEASE:=4
PKG_LICNESE:=GPL-2.0+
include $(INCLUDE_DIR)/package.mk
diff --git a/package/network/utils/tcpdump/Makefile b/package/network/utils/tcpdump/Makefile
index f333cf98d2a..d2e933a1a1a 100644
--- a/package/network/utils/tcpdump/Makefile
+++ b/package/network/utils/tcpdump/Makefile
@@ -8,19 +8,19 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=tcpdump
-PKG_VERSION:=4.9.3
-PKG_RELEASE:=3
+PKG_VERSION:=4.99.4
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=http://www.us.tcpdump.org/release/ \
- http://www.tcpdump.org/release/
-PKG_HASH:=2cd47cb3d460b6ff75f4a9940f594317ad456cfbf2bd2c8e5151e16559db6410
+PKG_SOURCE_URL:=https://www.tcpdump.org/release/
+PKG_HASH:=0232231bb2f29d6bf2426e70a08a7e0c63a0d59a9b44863b7f5e2357a6e49fea
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=BSD-3-Clause
PKG_CPE_ID:=cpe:/a:tcpdump:tcpdump
PKG_INSTALL:=1
+PKG_BUILD_FLAGS:=gc-sections
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
@@ -49,9 +49,6 @@ CONFIGURE_ARGS += \
--without-crypto \
$(call autoconf_bool,CONFIG_IPV6,ipv6)
-TARGET_CFLAGS += -ffunction-sections -fdata-sections
-TARGET_LDFLAGS += -Wl,--gc-sections
-
ifeq ($(BUILD_VARIANT),mini)
TARGET_CFLAGS += -DTCPDUMP_MINI
CONFIGURE_ARGS += --disable-smb
@@ -59,8 +56,8 @@ ifeq ($(BUILD_VARIANT),mini)
endif
define Package/tcpdump/install
- $(INSTALL_DIR) $(1)/usr/sbin
- $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/tcpdump $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/tcpdump $(1)/usr/bin/
endef
Package/tcpdump-mini/install = $(Package/tcpdump/install)
diff --git a/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch b/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch
index 3da979dd35e..1988587029b 100644
--- a/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch
+++ b/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch
@@ -1,8 +1,8 @@
--- a/configure
+++ b/configure
-@@ -6183,97 +6183,6 @@ $as_echo "no" >&6; }
- fi
- fi
+@@ -6568,97 +6568,6 @@ fi
+
+
-#
-# Check for special debugging functions
diff --git a/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch b/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch
index 17477d27997..8a014cabf0b 100644
--- a/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch
+++ b/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch
@@ -1,13 +1,14 @@
--- a/Makefile.in
+++ b/Makefile.in
-@@ -72,6 +72,80 @@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@
+@@ -73,6 +73,86 @@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@
- CSRC = setsignal.c tcpdump.c
+ CSRC = fptype.c tcpdump.c
+ifdef TCPDUMP_MINI
+
+LIBNETDISSECT_SRC=\
+ netdissect.c \
++ netdissect-alloc.c \
+ addrtoname.c \
+ addrtostr.c \
+ af.c \
@@ -15,17 +16,18 @@
+ checksum.c \
+ cpack.c \
+ gmpls.c \
-+ gmt2local.c \
+ in_cksum.c \
+ ipproto.c \
+ l2vpn.c \
+ machdep.c \
++ ntp.c \
+ nlpid.c \
+ oui.c \
+ parsenfsfh.c \
+ print.c \
+ print-802_11.c \
+ print-aodv.c \
++ print-arista.c \
+ print-arp.c \
+ print-ascii.c \
+ print-bootp.c \
@@ -39,6 +41,7 @@
+ print-icmp.c \
+ print-icmp6.c \
+ print-igmp.c \
++ print-ip-demux.c \
+ print-ip.c \
+ print-ip6.c \
+ print-ip6opts.c \
@@ -47,6 +50,7 @@
+ print-llc.c \
+ print-lldp.c \
+ print-loopback.c \
++ print-macsec.c \
+ print-nfs.c \
+ print-ntp.c \
+ print-null.c \
@@ -72,6 +76,8 @@
+ print-telnet.c \
+ print-tftp.c \
+ print-udp.c \
++ print-unsupported.c \
++ print-whois.c \
+ signature.c \
+ strtoaddr.c \
+ util-print.c
@@ -81,19 +87,19 @@
LIBNETDISSECT_SRC=\
addrtoname.c \
addrtostr.c \
-@@ -237,6 +311,8 @@ LIBNETDISSECT_SRC=\
+@@ -254,6 +334,8 @@ LIBNETDISSECT_SRC=\
strtoaddr.c \
util-print.c
+endif
+
LOCALSRC = @LOCALSRC@
- GENSRC = version.c
LIBOBJS = @LIBOBJS@
+
--- a/addrtoname.c
+++ b/addrtoname.c
-@@ -578,8 +578,10 @@ linkaddr_string(netdissect_options *ndo,
- if (type == LINKADDR_ETHER && len == ETHER_ADDR_LEN)
+@@ -680,8 +680,10 @@ linkaddr_string(netdissect_options *ndo,
+ if (type == LINKADDR_ETHER && len == MAC_ADDR_LEN)
return (etheraddr_string(ndo, ep));
+#ifndef TCPDUMP_MINI
@@ -103,7 +109,7 @@
tp = lookup_bytestring(ndo, ep, len);
if (tp->bs_name)
-@@ -1214,6 +1216,7 @@ init_addrtoname(netdissect_options *ndo,
+@@ -1260,6 +1262,7 @@ init_addrtoname(netdissect_options *ndo,
init_ipxsaparray(ndo);
}
@@ -111,7 +117,7 @@
const char *
dnaddr_string(netdissect_options *ndo, u_short dnaddr)
{
-@@ -1230,6 +1233,7 @@ dnaddr_string(netdissect_options *ndo, u
+@@ -1276,6 +1279,7 @@ dnaddr_string(netdissect_options *ndo, u
return(tp->name);
}
@@ -119,138 +125,45 @@
/* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
struct hnamemem *
---- a/print.c
-+++ b/print.c
-@@ -48,6 +48,7 @@ static const struct printer printers[] =
- #ifdef DLT_IPNET
- { ipnet_if_print, DLT_IPNET },
- #endif
-+#ifndef TCPDUMP_MINI
- #ifdef DLT_IEEE802_15_4
- { ieee802_15_4_if_print, DLT_IEEE802_15_4 },
- #endif
-@@ -57,12 +58,14 @@ static const struct printer printers[] =
- #ifdef DLT_PPI
- { ppi_if_print, DLT_PPI },
- #endif
-+#endif
- #ifdef DLT_NETANALYZER
- { netanalyzer_if_print, DLT_NETANALYZER },
- #endif
- #ifdef DLT_NETANALYZER_TRANSPARENT
- { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT },
- #endif
-+#ifndef TCPDUMP_MINI
- #if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H)
- { nflog_if_print, DLT_NFLOG},
- #endif
-@@ -75,10 +78,12 @@ static const struct printer printers[] =
- #ifdef DLT_IP_OVER_FC
- { ipfc_if_print, DLT_IP_OVER_FC },
- #endif
-+#endif
- { null_if_print, DLT_NULL },
- #ifdef DLT_LOOP
- { null_if_print, DLT_LOOP },
- #endif
-+#ifndef TCPDUMP_MINI
- #ifdef DLT_APPLE_IP_OVER_IEEE1394
- { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 },
- #endif
-@@ -92,7 +97,9 @@ static const struct printer printers[] =
- #ifdef DLT_ARCNET_LINUX
- { arcnet_linux_if_print, DLT_ARCNET_LINUX },
- #endif
-+#endif
- { raw_if_print, DLT_RAW },
-+#ifndef TCPDUMP_MINI
- #ifdef DLT_IPV4
- { raw_if_print, DLT_IPV4 },
- #endif
-@@ -116,17 +123,21 @@ static const struct printer printers[] =
- #ifdef DLT_HDLC
- { chdlc_if_print, DLT_HDLC },
- #endif
-+#endif
- #ifdef DLT_PPP_ETHER
- { pppoe_if_print, DLT_PPP_ETHER },
- #endif
-+#ifndef TCPDUMP_MINI
- #if defined(DLT_PFLOG) && defined(HAVE_NET_IF_PFLOG_H)
- { pflog_if_print, DLT_PFLOG },
- #endif
- { token_if_print, DLT_IEEE802 },
- { fddi_if_print, DLT_FDDI },
-+#endif
- #ifdef DLT_LINUX_SLL
- { sll_if_print, DLT_LINUX_SLL },
- #endif
-+#ifndef TCPDUMP_MINI
- #ifdef DLT_FR
- { fr_if_print, DLT_FR },
- #endif
-@@ -198,6 +209,7 @@ static const struct printer printers[] =
- #ifdef DLT_PKTAP
- { pktap_if_print, DLT_PKTAP },
- #endif
-+#endif
- #ifdef DLT_IEEE802_11_RADIO
- { ieee802_11_radio_if_print, DLT_IEEE802_11_RADIO },
- #endif
-@@ -214,12 +226,14 @@ static const struct printer printers[] =
- #ifdef DLT_PPP_WITHDIRECTION
- { ppp_if_print, DLT_PPP_WITHDIRECTION },
- #endif
-+#ifndef TCPDUMP_MINI
- #ifdef DLT_PPP_BSDOS
- { ppp_bsdos_if_print, DLT_PPP_BSDOS },
- #endif
- #ifdef DLT_PPP_SERIAL
- { ppp_hdlc_if_print, DLT_PPP_SERIAL },
- #endif
-+#endif
- { NULL, 0 },
- };
-
--- a/print-ether.c
+++ b/print-ether.c
-@@ -342,6 +342,7 @@ ethertype_print(netdissect_options *ndo,
- arp_print(ndo, p, length, caplen);
+@@ -545,6 +545,7 @@ ethertype_print(netdissect_options *ndo,
+ arp_print(ndo, p, length, caplen);
return (1);
+#ifndef TCPDUMP_MINI
case ETHERTYPE_DN:
decnet_print(ndo, p, length, caplen);
return (1);
-@@ -368,6 +369,7 @@ ethertype_print(netdissect_options *ndo,
- }
+@@ -575,6 +576,7 @@ ethertype_print(netdissect_options *ndo,
+ ND_TCHECK_LEN(p, 1);
isoclns_print(ndo, p + 1, length - 1);
return(1);
+#endif
case ETHERTYPE_PPPOED:
case ETHERTYPE_PPPOES:
-@@ -380,9 +382,11 @@ ethertype_print(netdissect_options *ndo,
- eap_print(ndo, p, length);
+@@ -587,9 +589,11 @@ ethertype_print(netdissect_options *ndo,
+ eapol_print(ndo, p);
return (1);
+#ifndef TCPDUMP_MINI
- case ETHERTYPE_RRCP:
- rrcp_print(ndo, p, length, src, dst);
+ case ETHERTYPE_REALTEK:
+ rtl_print(ndo, p, length, src, dst);
return (1);
+#endif
case ETHERTYPE_PPP:
if (length) {
-@@ -391,6 +395,7 @@ ethertype_print(netdissect_options *ndo,
+@@ -598,6 +602,7 @@ ethertype_print(netdissect_options *ndo,
}
return (1);
+#ifndef TCPDUMP_MINI
case ETHERTYPE_MPCP:
- mpcp_print(ndo, p, length);
+ mpcp_print(ndo, p, length);
return (1);
-@@ -403,6 +408,7 @@ ethertype_print(netdissect_options *ndo,
+@@ -610,19 +615,23 @@ ethertype_print(netdissect_options *ndo,
case ETHERTYPE_CFM_OLD:
cfm_print(ndo, p, length);
return (1);
@@ -258,17 +171,25 @@
case ETHERTYPE_LLDP:
lldp_print(ndo, p, length);
-@@ -412,6 +418,7 @@ ethertype_print(netdissect_options *ndo,
+ return (1);
+
++#ifndef TCPDUMP_MINI
+ case ETHERTYPE_NSH:
+ nsh_print(ndo, p, length);
+ return (1);
++#endif
+
+ case ETHERTYPE_LOOPBACK:
loopback_print(ndo, p, length);
- return (1);
+ return (1);
+#ifndef TCPDUMP_MINI
case ETHERTYPE_MPLS:
case ETHERTYPE_MPLS_MULTI:
mpls_print(ndo, p, length);
-@@ -441,6 +448,7 @@ ethertype_print(netdissect_options *ndo,
- case ETHERTYPE_MEDSA:
- medsa_print(ndo, p, length, caplen, src, dst);
+@@ -652,6 +661,7 @@ ethertype_print(netdissect_options *ndo,
+ case ETHERTYPE_PTP:
+ ptp_print(ndo, p, length);
return (1);
+#endif
@@ -276,7 +197,7 @@
case ETHERTYPE_SCA:
--- a/print-gre.c
+++ b/print-gre.c
-@@ -216,6 +216,7 @@ gre_print_0(netdissect_options *ndo, con
+@@ -207,6 +207,7 @@ gre_print_0(netdissect_options *ndo, con
case ETHERTYPE_IPV6:
ip6_print(ndo, bp, len);
break;
@@ -284,104 +205,63 @@
case ETHERTYPE_MPLS:
mpls_print(ndo, bp, len);
break;
-@@ -231,6 +232,7 @@ gre_print_0(netdissect_options *ndo, con
+@@ -219,6 +220,7 @@ gre_print_0(netdissect_options *ndo, con
+ case ETHERTYPE_GRE_ISO:
+ isoclns_print(ndo, bp, len);
+ break;
++#endif
case ETHERTYPE_TEB:
- ether_print(ndo, bp, len, ndo->ndo_snapend - bp, NULL, NULL);
+ ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
break;
+--- a/print-icmp6.c
++++ b/print-icmp6.c
+@@ -1371,7 +1371,7 @@ get_upperlayer(netdissect_options *ndo,
+ nh = GET_U_1(fragh->ip6f_nxt);
+ hlen = sizeof(struct ip6_frag);
+ break;
+-
++#ifndef TCPDUMP_MINI
+ case IPPROTO_AH:
+ ah = (const struct ah *)bp;
+ if (!ND_TTEST_1(ah->ah_len))
+@@ -1379,7 +1379,7 @@ get_upperlayer(netdissect_options *ndo,
+ nh = GET_U_1(ah->ah_nxt);
+ hlen = (GET_U_1(ah->ah_len) + 2) << 2;
+ break;
+-
+#endif
- default:
- ND_PRINT((ndo, "gre-proto-0x%x", prot));
- }
+ default: /* unknown or undecodable header */
+ *prot = nh; /* meaningless, but set here anyway */
+ return(NULL);
--- a/print-igmp.c
+++ b/print-igmp.c
-@@ -306,6 +306,7 @@ igmp_print(netdissect_options *ndo,
- ND_TCHECK2(bp[4], 4);
- ND_PRINT((ndo, "igmp leave %s", ipaddr_string(ndo, &bp[4])));
+@@ -269,6 +269,7 @@ igmp_print(netdissect_options *ndo,
+ case 0x17:
+ ND_PRINT("igmp leave %s", GET_IPADDR_STRING(bp + 4));
break;
+#ifndef TCPDUMP_MINI
case 0x13:
- ND_PRINT((ndo, "igmp dvmrp"));
+ ND_PRINT("igmp dvmrp");
if (len < 8)
-@@ -317,6 +318,7 @@ igmp_print(netdissect_options *ndo,
- ND_PRINT((ndo, "igmp pimv1"));
+@@ -280,6 +281,7 @@ igmp_print(netdissect_options *ndo,
+ ND_PRINT("igmp pimv1");
pimv1_print(ndo, bp, len);
break;
+#endif
case 0x1e:
- print_mresp(ndo, bp, len);
+ print_mtrace(ndo, "mresp", bp, len);
break;
---- a/print-ip6.c
-+++ b/print-ip6.c
-@@ -305,6 +305,7 @@ ip6_print(netdissect_options *ndo, const
- return;
- nh = *cp;
- break;
-+#ifndef TCPDUMP_MINI
- case IPPROTO_FRAGMENT:
- advance = frag6_print(ndo, cp, (const u_char *)ip6);
- if (advance < 0 || ndo->ndo_snapend <= cp + advance)
-@@ -328,6 +329,7 @@ ip6_print(netdissect_options *ndo, const
- return;
- nh = *cp;
- return;
-+#endif
- case IPPROTO_ROUTING:
- ND_TCHECK(*cp);
- advance = rt6_print(ndo, cp, (const u_char *)ip6);
-@@ -335,12 +337,14 @@ ip6_print(netdissect_options *ndo, const
- return;
- nh = *cp;
- break;
-+#ifndef TCPDUMP_MINI
- case IPPROTO_SCTP:
- sctp_print(ndo, cp, (const u_char *)ip6, len);
- return;
- case IPPROTO_DCCP:
- dccp_print(ndo, cp, (const u_char *)ip6, len);
- return;
-+#endif
- case IPPROTO_TCP:
- tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
- return;
-@@ -350,6 +354,7 @@ ip6_print(netdissect_options *ndo, const
- case IPPROTO_ICMPV6:
- icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented);
- return;
-+#ifndef TCPDUMP_MINI
- case IPPROTO_AH:
- advance = ah_print(ndo, cp);
- if (advance < 0)
-@@ -382,6 +387,7 @@ ip6_print(netdissect_options *ndo, const
- case IPPROTO_PIM:
- pim_print(ndo, cp, len, (const u_char *)ip6);
- return;
-+#endif
-
- case IPPROTO_OSPF:
- ospf6_print(ndo, cp, len);
-@@ -395,9 +401,11 @@ ip6_print(netdissect_options *ndo, const
- ip_print(ndo, cp, len);
- return;
-
-+#ifndef TCPDUMP_MINI
- case IPPROTO_PGM:
- pgm_print(ndo, cp, len, (const u_char *)ip6);
- return;
-+#endif
-
- case IPPROTO_GRE:
- gre_print(ndo, cp, len);
---- a/print-ip.c
-+++ b/print-ip.c
-@@ -344,6 +344,7 @@ ip_print_demux(netdissect_options *ndo,
+--- a/print-ip-demux.c
++++ b/print-ip-demux.c
+@@ -48,6 +48,7 @@ ip_demux_print(netdissect_options *ndo,
again:
- switch (ipds->nh) {
+ switch (nh) {
+#ifndef TCPDUMP_MINI
case IPPROTO_AH:
- if (!ND_TTEST(*ipds->cp)) {
- ND_PRINT((ndo, "[|AH]"));
-@@ -382,7 +383,9 @@ again:
+ if (!ND_TTEST_1(bp)) {
+ ndo->ndo_protocol = "ah";
+@@ -85,7 +86,9 @@ again:
*/
break;
}
@@ -389,61 +269,94 @@
+#ifndef TCPDUMP_MINI
case IPPROTO_SCTP:
- sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
+ sctp_print(ndo, bp, iph, length);
break;
-@@ -390,6 +393,7 @@ again:
+@@ -93,7 +96,7 @@ again:
case IPPROTO_DCCP:
- dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
+ dccp_print(ndo, bp, iph, length);
break;
+-
+#endif
-
case IPPROTO_TCP:
- /* pass on the MF bit plus the offset to detect fragments */
-@@ -409,6 +413,7 @@ again:
- ipds->off & (IP_MF|IP_OFFMASK));
+ tcp_print(ndo, bp, length, iph, fragmented);
+ break;
+@@ -122,6 +125,7 @@ again:
+ }
break;
+#ifndef TCPDUMP_MINI
case IPPROTO_PIGP:
/*
* XXX - the current IANA protocol number assignments
-@@ -429,14 +434,17 @@ again:
+@@ -142,14 +146,17 @@ again:
case IPPROTO_EIGRP:
- eigrp_print(ndo, ipds->cp, ipds->len);
+ eigrp_print(ndo, bp, length);
break;
+#endif
case IPPROTO_ND:
- ND_PRINT((ndo, " nd %d", ipds->len));
+ ND_PRINT(" nd %u", length);
break;
+#ifndef TCPDUMP_MINI
case IPPROTO_EGP:
- egp_print(ndo, ipds->cp, ipds->len);
+ egp_print(ndo, bp, length);
break;
+#endif
case IPPROTO_OSPF:
- ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
-@@ -469,6 +477,7 @@ again:
- gre_print(ndo, ipds->cp, ipds->len);
+ if (ver == 6)
+@@ -186,6 +193,7 @@ again:
+ gre_print(ndo, bp, length);
break;
+#ifndef TCPDUMP_MINI
case IPPROTO_MOBILE:
- mobile_print(ndo, ipds->cp, ipds->len);
+ mobile_print(ndo, bp, length);
break;
-@@ -497,6 +506,7 @@ again:
+@@ -205,6 +213,7 @@ again:
case IPPROTO_PGM:
- pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
+ pgm_print(ndo, bp, length, iph);
break;
+#endif
- default:
- if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(ipds->nh)) != NULL)
+ case IPPROTO_ETHERNET:
+ if (ver == 6)
+--- a/print-ip6.c
++++ b/print-ip6.c
+@@ -135,10 +135,11 @@ ip6_finddst(netdissect_options *ndo, nd_
+ * Only one routing header to a customer.
+ */
+ goto done;
+-
++#ifndef TCPDUMP_MINI
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+ case IPPROTO_IPCOMP:
++#endif
+ default:
+ /*
+ * AH and ESP are, in the RFCs that describe them,
+@@ -375,6 +376,7 @@ ip6_print(netdissect_options *ndo, const
+ nh = GET_U_1(cp);
+ break;
+
++#ifndef TCPDUMP_MINI
+ case IPPROTO_FRAGMENT:
+ advance = frag6_print(ndo, cp, (const u_char *)ip6);
+ if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
+@@ -405,7 +407,7 @@ ip6_print(netdissect_options *ndo, const
+ nh = GET_U_1(cp);
+ nd_pop_packet_info(ndo);
+ return;
+-
++#endif
+ case IPPROTO_ROUTING:
+ ND_TCHECK_1(cp);
+ advance = rt6_print(ndo, cp, (const u_char *)ip6);
--- a/print-llc.c
+++ b/print-llc.c
-@@ -206,6 +206,7 @@ llc_print(netdissect_options *ndo, const
+@@ -207,6 +207,7 @@ llc_print(netdissect_options *ndo, const
hdrlen = 4; /* DSAP, SSAP, 2-byte control field */
}
@@ -451,7 +364,7 @@
if (ssap_field == LLCSAP_GLOBAL && dsap_field == LLCSAP_GLOBAL) {
/*
* This is an Ethernet_802.3 IPX frame; it has an
-@@ -228,6 +229,7 @@ llc_print(netdissect_options *ndo, const
+@@ -229,6 +230,7 @@ llc_print(netdissect_options *ndo, const
ipx_print(ndo, p, length);
return (0); /* no LLC header */
}
@@ -459,7 +372,7 @@
dsap = dsap_field & ~LLC_IG;
ssap = ssap_field & ~LLC_GSAP;
-@@ -291,6 +293,7 @@ llc_print(netdissect_options *ndo, const
+@@ -292,6 +294,7 @@ llc_print(netdissect_options *ndo, const
return (hdrlen);
}
@@ -467,7 +380,7 @@
if (ssap == LLCSAP_IPX && dsap == LLCSAP_IPX &&
control == LLC_UI) {
/*
-@@ -304,6 +307,7 @@ llc_print(netdissect_options *ndo, const
+@@ -305,6 +308,7 @@ llc_print(netdissect_options *ndo, const
ipx_print(ndo, p, length);
return (hdrlen);
}
@@ -475,7 +388,7 @@
#ifdef ENABLE_SMB
if (ssap == LLCSAP_NETBEUI && dsap == LLCSAP_NETBEUI
-@@ -322,12 +326,13 @@ llc_print(netdissect_options *ndo, const
+@@ -323,12 +327,13 @@ llc_print(netdissect_options *ndo, const
return (hdrlen);
}
#endif
@@ -490,15 +403,15 @@
if (!ndo->ndo_eflag) {
if (ssap == dsap) {
if (src == NULL || dst == NULL)
-@@ -480,6 +485,7 @@ snap_print(netdissect_options *ndo, cons
+@@ -484,6 +489,7 @@ snap_print(netdissect_options *ndo, cons
case OUI_CISCO:
switch (et) {
+#ifndef TCPDUMP_MINI
case PID_CISCO_CDP:
- cdp_print(ndo, p, length, caplen);
+ cdp_print(ndo, p, length);
return (1);
-@@ -492,6 +498,7 @@ snap_print(netdissect_options *ndo, cons
+@@ -496,6 +502,7 @@ snap_print(netdissect_options *ndo, cons
case PID_CISCO_VTP:
vtp_print(ndo, p, length);
return (1);
@@ -506,7 +419,7 @@
case PID_CISCO_PVST:
case PID_CISCO_VLANBRIDGE:
stp_print(ndo, p, length);
-@@ -504,6 +511,7 @@ snap_print(netdissect_options *ndo, cons
+@@ -508,6 +515,7 @@ snap_print(netdissect_options *ndo, cons
case OUI_RFC2684:
switch (et) {
@@ -514,7 +427,7 @@
case PID_RFC2684_ETH_FCS:
case PID_RFC2684_ETH_NOFCS:
/*
-@@ -565,6 +573,7 @@ snap_print(netdissect_options *ndo, cons
+@@ -569,6 +577,7 @@ snap_print(netdissect_options *ndo, cons
*/
fddi_print(ndo, p, length, caplen);
return (1);
@@ -542,25 +455,25 @@
/* unknown AF_ value */
--- a/print-ppp.c
+++ b/print-ppp.c
-@@ -1367,6 +1367,7 @@ trunc:
- return 0;
- }
-
+@@ -1355,6 +1355,7 @@ trunc:
+ * The length argument is the on-the-wire length, not the captured
+ * length; we can only un-escape the captured part.
+ */
+#ifndef TCPDUMP_MINI
static void
ppp_hdlc(netdissect_options *ndo,
- const u_char *p, int length)
-@@ -1445,6 +1446,7 @@ trunc:
- free(b);
- ND_PRINT((ndo, "[|ppp]"));
+ const u_char *p, u_int length)
+@@ -1451,17 +1452,19 @@ trunc:
+ ndo->ndo_snapend = se;
+ nd_print_trunc(ndo);
}
+-
+#endif
-
/* PPP */
-@@ -1452,10 +1454,12 @@ static void
+ static void
handle_ppp(netdissect_options *ndo,
- u_int proto, const u_char *p, int length)
+ u_int proto, const u_char *p, u_int length)
{
+#ifndef TCPDUMP_MINI
if ((proto & 0xff00) == 0x7e00) { /* is this an escape code ? */
@@ -571,7 +484,7 @@
switch (proto) {
case PPP_LCP: /* fall through */
-@@ -1488,6 +1492,7 @@ handle_ppp(netdissect_options *ndo,
+@@ -1494,6 +1497,7 @@ handle_ppp(netdissect_options *ndo,
case PPP_IPV6:
ip6_print(ndo, p, length);
break;
@@ -579,33 +492,30 @@
case ETHERTYPE_IPX: /*XXX*/
case PPP_IPX:
ipx_print(ndo, p, length);
-@@ -1499,6 +1504,7 @@ handle_ppp(netdissect_options *ndo,
+@@ -1505,6 +1509,7 @@ handle_ppp(netdissect_options *ndo,
case PPP_MPLS_MCAST:
mpls_print(ndo, p, length);
break;
+#endif
case PPP_COMP:
- ND_PRINT((ndo, "compressed PPP data"));
+ ND_PRINT("compressed PPP data");
break;
-@@ -1639,6 +1645,7 @@ ppp_if_print(netdissect_options *ndo,
- return (0);
+@@ -1652,6 +1657,7 @@ ppp_if_print(netdissect_options *ndo,
+ ppp_print(ndo, p, length);
}
+#ifndef TCPDUMP_MINI
/*
* PPP I/F printer to use if we know that RFC 1662-style PPP in HDLC-like
* framing, or Cisco PPP with HDLC framing as per section 4.3.1 of RFC 1547,
-@@ -1866,6 +1873,7 @@ printx:
+@@ -1895,3 +1901,4 @@ printx:
#endif /* __bsdi__ */
- return (hdrlength);
+ ndo->ndo_ll_hdr_len += hdrlength;
}
+#endif
-
-
- /*
--- a/print-sll.c
+++ b/print-sll.c
-@@ -249,12 +249,14 @@ recurse:
+@@ -465,12 +465,14 @@ recurse:
*/
switch (ether_type) {
@@ -622,22 +532,24 @@
/*
--- a/print-tcp.c
+++ b/print-tcp.c
-@@ -589,12 +589,14 @@ tcp_print(netdissect_options *ndo,
- ND_PRINT((ndo, " %u", utoval));
+@@ -614,6 +614,7 @@ tcp_print(netdissect_options *ndo,
+ ND_PRINT(" %u", utoval);
break;
+#ifndef TCPDUMP_MINI
case TCPOPT_MPTCP:
- datalen = len - 2;
- LENCHECK(datalen);
- if (!mptcp_print(ndo, cp-2, len, flags))
+ {
+ const u_char *snapend_save;
+@@ -637,7 +638,7 @@ tcp_print(netdissect_options *ndo,
goto bad;
break;
+ }
+-
+#endif
-
case TCPOPT_FASTOPEN:
datalen = len - 2;
-@@ -670,6 +672,7 @@ tcp_print(netdissect_options *ndo,
+ LENCHECK(datalen);
+@@ -722,6 +723,7 @@ tcp_print(netdissect_options *ndo,
return;
}
@@ -645,7 +557,7 @@
if (ndo->ndo_packettype) {
switch (ndo->ndo_packettype) {
case PT_ZMTP1:
-@@ -681,28 +684,36 @@ tcp_print(netdissect_options *ndo,
+@@ -737,6 +739,7 @@ tcp_print(netdissect_options *ndo,
}
return;
}
@@ -653,9 +565,10 @@
if (IS_SRC_OR_DST_PORT(TELNET_PORT)) {
telnet_print(ndo, bp, length);
- } else if (IS_SRC_OR_DST_PORT(SMTP_PORT)) {
- ND_PRINT((ndo, ": "));
- smtp_print(ndo, bp, length);
+@@ -746,24 +749,31 @@ tcp_print(netdissect_options *ndo,
+ } else if (IS_SRC_OR_DST_PORT(WHOIS_PORT)) {
+ ND_PRINT(": ");
+ whois_print(ndo, bp, length);
- } else if (IS_SRC_OR_DST_PORT(BGP_PORT))
+ }
+#ifndef TCPDUMP_MINI
@@ -667,12 +580,14 @@
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(REDIS_PORT))
resp_print(ndo, bp, length);
+ else if (IS_SRC_OR_DST_PORT(SSH_PORT))
+ ssh_print(ndo, bp, length);
+#endif
#ifdef ENABLE_SMB
else if (IS_SRC_OR_DST_PORT(NETBIOS_SSN_PORT))
nbt_tcp_print(ndo, bp, length);
- else if (IS_SRC_OR_DST_PORT(SMB_PORT))
- smb_tcp_print(ndo, bp, length);
+ else if (IS_SRC_OR_DST_PORT(SMB_PORT))
+ smb_tcp_print(ndo, bp, length);
#endif
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(BEEP_PORT))
@@ -681,41 +596,40 @@
openflow_print(ndo, bp, length);
+#endif
else if (IS_SRC_OR_DST_PORT(FTP_PORT)) {
- ND_PRINT((ndo, ": "));
+ ND_PRINT(": ");
ftp_print(ndo, bp, length);
-@@ -725,6 +736,7 @@ tcp_print(netdissect_options *ndo,
- * XXX packet could be unaligned, it can go strange
- */
- ns_print(ndo, bp + 2, length - 2, 0);
+@@ -776,12 +786,14 @@ tcp_print(netdissect_options *ndo,
+ } else if (IS_SRC_OR_DST_PORT(NAMESERVER_PORT)) {
+ /* over_tcp: TRUE, is_mdns: FALSE */
+ domain_print(ndo, bp, length, TRUE, FALSE);
+#ifndef TCPDUMP_MINI
} else if (IS_SRC_OR_DST_PORT(MSDP_PORT)) {
msdp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(RPKI_RTR_PORT)) {
-@@ -732,6 +744,7 @@ tcp_print(netdissect_options *ndo,
- }
- else if (length > 0 && (IS_SRC_OR_DST_PORT(LDP_PORT))) {
+ rpki_rtr_print(ndo, bp, length);
+ } else if (IS_SRC_OR_DST_PORT(LDP_PORT)) {
ldp_print(ndo, bp, length);
+#endif
- }
- else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
- length >= 4 && ND_TTEST2(*bp, 4)) {
+ } else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
+ length >= 4 && ND_TTEST_4(bp)) {
+ /*
--- a/print-udp.c
+++ b/print-udp.c
-@@ -430,10 +430,12 @@ udp_print(netdissect_options *ndo, regis
- vat_print(ndo, (const void *)(up + 1), up);
+@@ -435,10 +435,12 @@ udp_print(netdissect_options *ndo, const
+ vat_print(ndo, cp, length);
break;
+#ifndef TCPDUMP_MINI
case PT_WB:
udpipaddr_print(ndo, ip, sport, dport);
- wb_print(ndo, (const void *)(up + 1), length);
+ wb_print(ndo, cp, length);
break;
+#endif
case PT_RPC:
- rp = (const struct sunrpc_msg *)(up + 1);
-@@ -462,10 +464,12 @@ udp_print(netdissect_options *ndo, regis
- snmp_print(ndo, (const u_char *)(up + 1), length);
+ rp = (const struct sunrpc_msg *)cp;
+@@ -467,10 +469,12 @@ udp_print(netdissect_options *ndo, const
+ snmp_print(ndo, cp, length);
break;
+#ifndef TCPDUMP_MINI
@@ -727,131 +641,221 @@
case PT_TFTP:
udpipaddr_print(ndo, ip, sport, dport);
-@@ -483,6 +487,7 @@ udp_print(netdissect_options *ndo, regis
+@@ -488,6 +492,7 @@ udp_print(netdissect_options *ndo, const
radius_print(ndo, cp, length);
break;
+#ifndef TCPDUMP_MINI
case PT_VXLAN:
udpipaddr_print(ndo, ip, sport, dport);
- vxlan_print(ndo, (const u_char *)(up + 1), length);
-@@ -497,6 +502,7 @@ udp_print(netdissect_options *ndo, regis
+ vxlan_print(ndo, cp, length);
+@@ -510,6 +515,7 @@ udp_print(netdissect_options *ndo, const
udpipaddr_print(ndo, ip, sport, dport);
- lmp_print(ndo, cp, length);
+ someip_print(ndo, cp, length);
break;
+#endif
- }
- return;
- }
-@@ -574,31 +580,40 @@ udp_print(netdissect_options *ndo, regis
- ns_print(ndo, (const u_char *)(up + 1), length, 0);
+ case PT_DOMAIN:
+ udpipaddr_print(ndo, ip, sport, dport);
+ /* over_tcp: FALSE, is_mdns: FALSE */
+@@ -596,29 +602,37 @@ udp_print(netdissect_options *ndo, const
else if (IS_SRC_OR_DST_PORT(MULTICASTDNS_PORT))
- ns_print(ndo, (const u_char *)(up + 1), length, 1);
+ /* over_tcp: FALSE, is_mdns: TRUE */
+ domain_print(ndo, cp, length, FALSE, TRUE);
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(TIMED_PORT))
- timed_print(ndo, (const u_char *)(up + 1));
+ timed_print(ndo, (const u_char *)cp);
+#endif
else if (IS_SRC_OR_DST_PORT(TFTP_PORT))
- tftp_print(ndo, (const u_char *)(up + 1), length);
+ tftp_print(ndo, cp, length);
else if (IS_SRC_OR_DST_PORT(BOOTPC_PORT) || IS_SRC_OR_DST_PORT(BOOTPS_PORT))
- bootp_print(ndo, (const u_char *)(up + 1), length);
+ bootp_print(ndo, cp, length);
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(RIP_PORT))
- rip_print(ndo, (const u_char *)(up + 1), length);
+ rip_print(ndo, cp, length);
+#endif
else if (IS_SRC_OR_DST_PORT(AODV_PORT))
- aodv_print(ndo, (const u_char *)(up + 1), length,
+ aodv_print(ndo, cp, length,
ip6 != NULL);
+#ifndef TCPDUMP_MINI
- else if (IS_SRC_OR_DST_PORT(ISAKMP_PORT))
- isakmp_print(ndo, (const u_char *)(up + 1), length, bp2);
-+
- else if (IS_SRC_OR_DST_PORT(ISAKMP_PORT_NATT))
- isakmp_rfc3948_print(ndo, (const u_char *)(up + 1), length, bp2);
- #if 1 /*???*/
- else if (IS_SRC_OR_DST_PORT(ISAKMP_PORT_USER1) || IS_SRC_OR_DST_PORT(ISAKMP_PORT_USER2))
- isakmp_print(ndo, (const u_char *)(up + 1), length, bp2);
- #endif
+ else if (IS_SRC_OR_DST_PORT(ISAKMP_PORT))
+ isakmp_print(ndo, cp, length, bp2);
+ else if (IS_SRC_OR_DST_PORT(ISAKMP_PORT_NATT))
+ isakmp_rfc3948_print(ndo, cp, length, bp2, IP_V(ip), fragmented, ttl_hl);
+ else if (IS_SRC_OR_DST_PORT(ISAKMP_PORT_USER1) || IS_SRC_OR_DST_PORT(ISAKMP_PORT_USER2))
+ isakmp_print(ndo, cp, length, bp2);
+#endif
else if (IS_SRC_OR_DST_PORT(SNMP_PORT) || IS_SRC_OR_DST_PORT(SNMPTRAP_PORT))
- snmp_print(ndo, (const u_char *)(up + 1), length);
+ snmp_print(ndo, cp, length);
else if (IS_SRC_OR_DST_PORT(NTP_PORT))
- ntp_print(ndo, (const u_char *)(up + 1), length);
+ ntp_print(ndo, cp, length);
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(KERBEROS_PORT) || IS_SRC_OR_DST_PORT(KERBEROS_SEC_PORT))
- krb_print(ndo, (const void *)(up + 1));
+ krb_print(ndo, (const u_char *)cp);
+#endif
else if (IS_SRC_OR_DST_PORT(L2TP_PORT))
- l2tp_print(ndo, (const u_char *)(up + 1), length);
+ l2tp_print(ndo, cp, length);
#ifdef ENABLE_SMB
-@@ -609,6 +624,7 @@ udp_print(netdissect_options *ndo, regis
+@@ -629,6 +643,7 @@ udp_print(netdissect_options *ndo, const
#endif
else if (dport == VAT_PORT)
- vat_print(ndo, (const void *)(up + 1), up);
+ vat_print(ndo, cp, length);
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(ZEPHYR_SRV_PORT) || IS_SRC_OR_DST_PORT(ZEPHYR_CLT_PORT))
- zephyr_print(ndo, (const void *)(up + 1), length);
+ zephyr_print(ndo, cp, length);
/*
-@@ -621,8 +637,11 @@ udp_print(netdissect_options *ndo, regis
+@@ -641,8 +656,11 @@ udp_print(netdissect_options *ndo, const
(const u_char *) ip);
else if (IS_SRC_OR_DST_PORT(RIPNG_PORT))
- ripng_print(ndo, (const u_char *)(up + 1), length);
+ ripng_print(ndo, cp, length);
+#endif
+
else if (IS_SRC_OR_DST_PORT(DHCP6_SERV_PORT) || IS_SRC_OR_DST_PORT(DHCP6_CLI_PORT))
- dhcp6_print(ndo, (const u_char *)(up + 1), length);
+ dhcp6_print(ndo, cp, length);
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(AHCP_PORT))
- ahcp_print(ndo, (const u_char *)(up + 1), length);
+ ahcp_print(ndo, cp, length);
else if (IS_SRC_OR_DST_PORT(BABEL_PORT) || IS_SRC_OR_DST_PORT(BABEL_PORT_OLD))
-@@ -636,6 +655,7 @@ udp_print(netdissect_options *ndo, regis
- wb_print(ndo, (const void *)(up + 1), length);
+@@ -656,6 +674,7 @@ udp_print(netdissect_options *ndo, const
+ wb_print(ndo, cp, length);
else if (IS_SRC_OR_DST_PORT(CISCO_AUTORP_PORT))
- cisco_autorp_print(ndo, (const void *)(up + 1), length);
+ cisco_autorp_print(ndo, cp, length);
+#endif
else if (IS_SRC_OR_DST_PORT(RADIUS_PORT) ||
IS_SRC_OR_DST_PORT(RADIUS_NEW_PORT) ||
IS_SRC_OR_DST_PORT(RADIUS_ACCOUNTING_PORT) ||
-@@ -643,15 +663,18 @@ udp_print(netdissect_options *ndo, regis
+@@ -663,15 +682,18 @@ udp_print(netdissect_options *ndo, const
IS_SRC_OR_DST_PORT(RADIUS_CISCO_COA_PORT) ||
IS_SRC_OR_DST_PORT(RADIUS_COA_PORT) )
- radius_print(ndo, (const u_char *)(up+1), length);
+ radius_print(ndo, cp, length);
+#ifndef TCPDUMP_MINI
else if (dport == HSRP_PORT)
- hsrp_print(ndo, (const u_char *)(up + 1), length);
+ hsrp_print(ndo, cp, length);
else if (IS_SRC_OR_DST_PORT(LWRES_PORT))
- lwres_print(ndo, (const u_char *)(up + 1), length);
+ lwres_print(ndo, cp, length);
else if (IS_SRC_OR_DST_PORT(LDP_PORT))
- ldp_print(ndo, (const u_char *)(up + 1), length);
+ ldp_print(ndo, cp, length);
+#endif
else if (IS_SRC_OR_DST_PORT(OLSR_PORT))
- olsr_print(ndo, (const u_char *)(up + 1), length,
+ olsr_print(ndo, cp, length,
(IP_V(ip) == 6) ? 1 : 0);
+#ifndef TCPDUMP_MINI
else if (IS_SRC_OR_DST_PORT(MPLS_LSP_PING_PORT))
- lspping_print(ndo, (const u_char *)(up + 1), length);
- else if (dport == BFD_CONTROL_PORT ||
-@@ -669,10 +692,12 @@ udp_print(netdissect_options *ndo, regis
- lwapp_control_print(ndo, (const u_char *)(up + 1), length, 0);
- else if (IS_SRC_OR_DST_PORT(LWAPP_DATA_PORT))
- lwapp_data_print(ndo, (const u_char *)(up + 1), length);
-+#endif
- else if (IS_SRC_OR_DST_PORT(SIP_PORT))
- sip_print(ndo, (const u_char *)(up + 1), length);
- else if (IS_SRC_OR_DST_PORT(SYSLOG_PORT))
- syslog_print(ndo, (const u_char *)(up + 1), length);
-+#ifndef TCPDUMP_MINI
- else if (IS_SRC_OR_DST_PORT(OTV_PORT))
- otv_print(ndo, (const u_char *)(up + 1), length);
- else if (IS_SRC_OR_DST_PORT(VXLAN_PORT))
-@@ -689,7 +714,9 @@ udp_print(netdissect_options *ndo, regis
- if (ndo->ndo_vflag)
- ND_PRINT((ndo, "kip "));
- llap_print(ndo, cp, length);
-- } else {
-+ }
-+#endif
-+ else {
- if (ulen > length)
- ND_PRINT((ndo, "UDP, bad length %u > %u",
- ulen, length));
+ lspping_print(ndo, cp, length);
+ else if (sport == BCM_LI_PORT)
+@@ -693,10 +715,12 @@ udp_print(netdissect_options *ndo, const
+ lwapp_control_print(ndo, cp, length, 0);
+ else if (IS_SRC_OR_DST_PORT(LWAPP_DATA_PORT))
+ lwapp_data_print(ndo, cp, length);
++#endif
+ else if (IS_SRC_OR_DST_PORT(SIP_PORT))
+ sip_print(ndo, cp, length);
+ else if (IS_SRC_OR_DST_PORT(SYSLOG_PORT))
+ syslog_print(ndo, cp, length);
++#ifndef TCPDUMP_MINI
+ else if (IS_SRC_OR_DST_PORT(OTV_PORT))
+ otv_print(ndo, cp, length);
+ else if (IS_SRC_OR_DST_PORT(VXLAN_PORT))
+@@ -722,6 +746,7 @@ udp_print(netdissect_options *ndo, const
+ ptp_print(ndo, cp, length);
+ } else if (IS_SRC_OR_DST_PORT(SOMEIP_PORT))
+ someip_print(ndo, cp, length);
++#endif
+ else {
+ if (ulen > length && !fragmented)
+ ND_PRINT("UDP, bad length %u > %u",
+--- a/print.c
++++ b/print.c
+@@ -48,6 +48,7 @@ struct printer {
+ };
+
+ static const struct printer printers[] = {
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_APPLE_IP_OVER_IEEE1394
+ { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 },
+ #endif
+@@ -86,7 +87,9 @@ static const struct printer printers[] =
+ #ifdef DLT_ENC
+ { enc_if_print, DLT_ENC },
+ #endif
++#endif
+ { ether_if_print, DLT_EN10MB },
++#ifndef TCPDUMP_MINI
+ { fddi_if_print, DLT_FDDI },
+ #ifdef DLT_FR
+ { fr_if_print, DLT_FR },
+@@ -94,6 +97,7 @@ static const struct printer printers[] =
+ #ifdef DLT_FRELAY
+ { fr_if_print, DLT_FRELAY },
+ #endif
++#endif
+ #ifdef DLT_IEEE802_11
+ { ieee802_11_if_print, DLT_IEEE802_11},
+ #endif
+@@ -103,6 +107,7 @@ static const struct printer printers[] =
+ #ifdef DLT_IEEE802_11_RADIO
+ { ieee802_11_radio_if_print, DLT_IEEE802_11_RADIO },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_IEEE802_15_4
+ { ieee802_15_4_if_print, DLT_IEEE802_15_4 },
+ #endif
+@@ -115,9 +120,11 @@ static const struct printer printers[] =
+ #ifdef DLT_IP_OVER_FC
+ { ipfc_if_print, DLT_IP_OVER_FC },
+ #endif
++#endif
+ #ifdef DLT_IPNET
+ { ipnet_if_print, DLT_IPNET },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_IPOIB
+ { ipoib_if_print, DLT_IPOIB },
+ #endif
+@@ -172,19 +179,23 @@ static const struct printer printers[] =
+ #ifdef DLT_MFR
+ { mfr_if_print, DLT_MFR },
+ #endif
++#endif
+ #ifdef DLT_NETANALYZER
+ { netanalyzer_if_print, DLT_NETANALYZER },
+ #endif
+ #ifdef DLT_NETANALYZER_TRANSPARENT
+ { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_NFLOG
+ { nflog_if_print, DLT_NFLOG},
+ #endif
++#endif
+ { null_if_print, DLT_NULL },
+ #ifdef DLT_LOOP
+ { null_if_print, DLT_LOOP },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_PFLOG
+ { pflog_if_print, DLT_PFLOG },
+ #endif
+@@ -200,6 +211,7 @@ static const struct printer printers[] =
+ #ifdef DLT_PPP_SERIAL
+ { ppp_hdlc_if_print, DLT_PPP_SERIAL },
+ #endif
++#endif
+ { ppp_if_print, DLT_PPP },
+ #ifdef DLT_PPP_PPPD
+ { ppp_if_print, DLT_PPP_PPPD },
+@@ -211,6 +223,7 @@ static const struct printer printers[] =
+ { prism_if_print, DLT_PRISM_HEADER },
+ #endif
+ { raw_if_print, DLT_RAW },
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_IPV4
+ { raw_if_print, DLT_IPV4 },
+ #endif
+@@ -243,6 +256,7 @@ static const struct printer printers[] =
+ #ifdef DLT_VSOCK
+ { vsock_if_print, DLT_VSOCK },
+ #endif
++#endif
+ { NULL, 0 },
+ };
+
diff --git a/package/network/utils/tcpdump/patches/101-CVE-2020-8037.patch b/package/network/utils/tcpdump/patches/101-CVE-2020-8037.patch
deleted file mode 100644
index 281854777df..00000000000
--- a/package/network/utils/tcpdump/patches/101-CVE-2020-8037.patch
+++ /dev/null
@@ -1,47 +0,0 @@
---- a/print-ppp.c
-+++ b/print-ppp.c
-@@ -1368,19 +1368,29 @@ trunc:
- }
-
- #ifndef TCPDUMP_MINI
-+/*
-+ * Un-escape RFC 1662 PPP in HDLC-like framing, with octet escapes.
-+ * The length argument is the on-the-wire length, not the captured
-+ * length; we can only un-escape the captured part.
-+ */
- static void
- ppp_hdlc(netdissect_options *ndo,
- const u_char *p, int length)
- {
-+ u_int caplen = ndo->ndo_snapend - p;
- u_char *b, *t, c;
- const u_char *s;
-- int i, proto;
-+ u_int i;
-+ int proto;
- const void *se;
-
-+ if (caplen == 0)
-+ return;
-+
- if (length <= 0)
- return;
-
-- b = (u_char *)malloc(length);
-+ b = (u_char *)malloc(caplen);
- if (b == NULL)
- return;
-
-@@ -1389,10 +1399,10 @@ ppp_hdlc(netdissect_options *ndo,
- * Do this so that we dont overwrite the original packet
- * contents.
- */
-- for (s = p, t = b, i = length; i > 0 && ND_TTEST(*s); i--) {
-+ for (s = p, t = b, i = caplen; i != 0; i--) {
- c = *s++;
- if (c == 0x7d) {
-- if (i <= 1 || !ND_TTEST(*s))
-+ if (i <= 1)
- break;
- i--;
- c = *s++ ^ 0x20;
diff --git a/package/network/utils/umbim/Makefile b/package/network/utils/umbim/Makefile
index a0f5e4756b8..56e1a6f3785 100644
--- a/package/network/utils/umbim/Makefile
+++ b/package/network/utils/umbim/Makefile
@@ -1,19 +1,20 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=umbim
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=24
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/umbim.git
-PKG_SOURCE_DATE:=2019-09-11
-PKG_SOURCE_VERSION:=184b707ddaa0acee84d02e0ffe599cb8b67782bd
-PKG_MIRROR_HASH:=482ff69144f81fafed99035840f5a24e772472f2df2f3ac0219d6de791ac5835
+PKG_SOURCE_DATE:=2022-08-13
+PKG_SOURCE_VERSION:=146bc77c98ace3d1cc672986669650d2e1da71f3
+PKG_MIRROR_HASH:=3cf04858ff5c3f529904f9789b094aa9645ad41c91f553e6fc3fcd3cb341d359
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=
PKG_FLAGS:=nonshared
+PKG_BUILD_FLAGS:=gc-sections
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
@@ -32,9 +33,7 @@ define Package/umbim/description
endef
TARGET_CFLAGS += \
- -I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
-
-TARGET_LDFLAGS += -Wl,--gc-sections
+ -I$(STAGING_DIR)/usr/include
define Package/umbim/install
$(INSTALL_DIR) $(1)/sbin
diff --git a/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh b/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh
index abbabd6625c..50913e7fa04 100755
--- a/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh
+++ b/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh
@@ -14,19 +14,42 @@ proto_mbim_init_config() {
proto_config_add_string apn
proto_config_add_string pincode
proto_config_add_string delay
+ proto_config_add_boolean allow_roaming
+ proto_config_add_boolean allow_partner
proto_config_add_string auth
proto_config_add_string username
proto_config_add_string password
+ [ -e /proc/sys/net/ipv6 ] && proto_config_add_string ipv6
+ proto_config_add_string dhcp
+ proto_config_add_string dhcpv6
+ proto_config_add_string pdptype
+ proto_config_add_int mtu
proto_config_add_defaults
}
+_proto_mbim_get_field() {
+ local field="$1"
+ shift
+ local mbimconfig="$@"
+ echo "$mbimconfig" | while read -r line; do
+ variable=${line%%:*}
+ [ "$variable" = "$field" ] || continue;
+ value=${line##* }
+ echo -n "$value "
+ done
+}
+
_proto_mbim_setup() {
local interface="$1"
local tid=2
local ret
- local device apn pincode delay $PROTO_DEFAULT_OPTIONS
- json_get_vars device apn pincode delay auth username password $PROTO_DEFAULT_OPTIONS
+ local device apn pincode delay auth username password allow_roaming allow_partner
+ local dhcp dhcpv6 pdptype ip4table ip6table mtu $PROTO_DEFAULT_OPTIONS
+ json_get_vars device apn pincode delay auth username password allow_roaming allow_partner
+ json_get_vars dhcp dhcpv6 pdptype ip4table ip6table mtu $PROTO_DEFAULT_OPTIONS
+
+ [ ! -e /proc/sys/net/ipv6 ] && ipv6=0 || json_get_var ipv6 ipv6
[ -n "$ctl_device" ] && device=$ctl_device
@@ -65,6 +88,8 @@ _proto_mbim_setup() {
echo "mbim[$$]" "Reading capabilities"
umbim $DBG -n -d $device caps || {
echo "mbim[$$]" "Failed to read modem caps"
+ tid=$((tid + 1))
+ umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" PIN_FAILED
return 1
}
@@ -74,6 +99,8 @@ _proto_mbim_setup() {
echo "mbim[$$]" "Sending pin"
umbim $DBG -n -t $tid -d $device unlock "$pincode" || {
echo "mbim[$$]" "Unable to verify PIN"
+ tid=$((tid + 1))
+ umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" PIN_FAILED
proto_block_restart "$interface"
return 1
@@ -82,8 +109,11 @@ _proto_mbim_setup() {
tid=$((tid + 1))
echo "mbim[$$]" "Checking pin"
- umbim $DBG -n -t $tid -d $device pinstate || {
+ umbim $DBG -n -t $tid -d $device pinstate
+ [ $? -eq 2 ] && {
echo "mbim[$$]" "PIN required"
+ tid=$((tid + 1))
+ umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" PIN_FAILED
proto_block_restart "$interface"
return 1
@@ -93,55 +123,177 @@ _proto_mbim_setup() {
echo "mbim[$$]" "Checking subscriber"
umbim $DBG -n -t $tid -d $device subscriber || {
echo "mbim[$$]" "Subscriber init failed"
+ tid=$((tid + 1))
+ umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" NO_SUBSCRIBER
return 1
}
tid=$((tid + 1))
echo "mbim[$$]" "Register with network"
- umbim $DBG -n -t $tid -d $device registration || {
- echo "mbim[$$]" "Subscriber registration failed"
+ connected=0
+ umbim $DBG -n -t $tid -d $device registration
+ reg_status=$?
+ case $reg_status in
+ 0) echo "mbim[$$]" "Registered in home mode"
+ tid=$((tid + 1))
+ connected=1;;
+ 4) if [ "$allow_roaming" = "1" ]; then
+ echo "mbim[$$]" "Registered in roaming mode"
+ tid=$((tid + 1))
+ connected=1
+ fi;;
+ 5) if [ "$allow_partner" = "1" ]; then
+ echo "mbim[$$]" "Registered in partner mode"
+ tid=$((tid + 1))
+ connected=1
+ fi;;
+ esac
+ if [ $connected -ne 1 ]; then
+ echo "mbim[$$]" "Subscriber registration failed (code $reg_status)"
+ tid=$((tid + 1))
+ umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" NO_REGISTRATION
return 1
- }
- tid=$((tid + 1))
+ fi
echo "mbim[$$]" "Attach to network"
umbim $DBG -n -t $tid -d $device attach || {
echo "mbim[$$]" "Failed to attach to network"
+ tid=$((tid + 1))
+ umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" ATTACH_FAILED
return 1
}
tid=$((tid + 1))
+ pdptype=$(echo "$pdptype" | awk '{print tolower($0)}')
+ [ "$ipv6" = 0 ] && pdptype="ipv4"
+
+ local req_pdptype="" # Pass "default" PDP type to umbim if unconfigured
+ [ "$pdptype" = "ipv4" -o "$pdptype" = "ipv6" -o "$pdptype" = "ipv4v6" ] && req_pdptype="$pdptype:"
+
+ local connect_state
echo "mbim[$$]" "Connect to network"
- while ! umbim $DBG -n -t $tid -d $device connect "$apn" "$auth" "$username" "$password"; do
+ connect_state=$(umbim $DBG -n -t $tid -d $device connect "$req_pdptype$apn" "$auth" "$username" "$password") || {
+ echo "mbim[$$]" "Failed to connect bearer"
tid=$((tid + 1))
- sleep 1;
- done
+ umbim $DBG -t $tid -d "$device" disconnect
+ proto_notify_error "$interface" CONNECT_FAILED
+ return 1
+ }
tid=$((tid + 1))
- uci_set_state network $interface tid "$tid"
+ echo "$connect_state"
+ local iptype="$(echo "$connect_state" | grep iptype: | awk '{print $4}')"
+
+ echo "mbim[$$]" "Connected"
+
+ local zone="$(fw3 -q network "$interface" 2>/dev/null)"
+
+ echo "mbim[$$]" "Setting up $ifname"
+ local mbimconfig="$(umbim $DBG -n -t $tid -d $device config)"
+ echo "$mbimconfig"
+ tid=$((tid + 1))
- echo "mbim[$$]" "Connected, starting DHCP"
proto_init_update "$ifname" 1
proto_send_update "$interface"
- json_init
- json_add_string name "${interface}_4"
- json_add_string ifname "@$interface"
- json_add_string proto "dhcp"
- proto_add_dynamic_defaults
- json_close_object
- ubus call network add_dynamic "$(json_dump)"
-
- json_init
- json_add_string name "${interface}_6"
- json_add_string ifname "@$interface"
- json_add_string proto "dhcpv6"
- json_add_string extendprefix 1
- proto_add_dynamic_defaults
- ubus call network add_dynamic "$(json_dump)"
+ [ -z "$dhcp" ] && dhcp="auto"
+ [ -z "$dhcpv6" ] && dhcpv6="auto"
+
+ [ "$iptype" != "ipv6" ] && {
+ json_init
+ json_add_string name "${interface}_4"
+ json_add_string ifname "@$interface"
+ ipv4address=$(_proto_mbim_get_field ipv4address "$mbimconfig")
+ if [ -n "$ipv4address" -a "$dhcp" != 1 ]; then
+ json_add_string proto "static"
+
+ json_add_array ipaddr
+ for address in $ipv4address; do
+ json_add_string "" "$address"
+ done
+ json_close_array
+
+ json_add_string gateway $(_proto_mbim_get_field ipv4gateway "$mbimconfig")
+ elif [ "$dhcp" != 0 ]; then
+ echo "mbim[$$]" "Starting DHCP on $ifname"
+ json_add_string proto "dhcp"
+ fi
+
+ [ "$peerdns" = 0 -a "$dhcp" != 1 ] || {
+ json_add_array dns
+ for server in $(_proto_mbim_get_field ipv4dnsserver "$mbimconfig"); do
+ json_add_string "" "$server"
+ done
+ json_close_array
+ }
+
+ proto_add_dynamic_defaults
+ [ -n "$zone" ] && json_add_string zone "$zone"
+ [ -n "$ip4table" ] && json_add_string ip4table "$ip4table"
+ json_close_object
+ ubus call network add_dynamic "$(json_dump)"
+ }
+
+ [ "$iptype" != "ipv4" ] && {
+ json_init
+ json_add_string name "${interface}_6"
+ json_add_string ifname "@$interface"
+ ipv6address=$(_proto_mbim_get_field ipv6address "$mbimconfig")
+ if [ -n "$ipv6address" -a "$dhcpv6" != 1 ]; then
+ json_add_string proto "static"
+
+ json_add_array ip6addr
+ for address in $ipv6address; do
+ json_add_string "" "$address"
+ done
+ json_close_array
+
+ json_add_array ip6prefix
+ for address in $ipv6address; do
+ json_add_string "" "$address"
+ done
+ json_close_array
+
+ json_add_string ip6gw $(_proto_mbim_get_field ipv6gateway "$mbimconfig")
+
+ elif [ "$dhcpv6" != 0 ]; then
+ echo "mbim[$$]" "Starting DHCPv6 on $ifname"
+ json_add_string proto "dhcpv6"
+ json_add_string extendprefix 1
+ fi
+
+ [ "$peerdns" = 0 -a "$dhcpv6" != 1 ] || {
+ json_add_array dns
+ for server in $(_proto_mbim_get_field ipv6dnsserver "$mbimconfig"); do
+ json_add_string "" "$server"
+ done
+ json_close_array
+ }
+
+ proto_add_dynamic_defaults
+ [ -n "$zone" ] && json_add_string zone "$zone"
+ [ -n "$ip6table" ] && json_add_string ip6table "$ip6table"
+ json_close_object
+ ubus call network add_dynamic "$(json_dump)"
+ }
+
+ [ -z "$mtu" ] && {
+ local ipv4mtu=$(_proto_mbim_get_field ipv4mtu "$mbimconfig")
+ ipv4mtu="${ipv4mtu:-0}"
+ local ipv6mtu=$(_proto_mbim_get_field ipv6mtu "$mbimconfig")
+ ipv6mtu="${ipv6mtu:-0}"
+
+ mtu=$((ipv6mtu > ipv4mtu ? ipv6mtu : ipv4mtu))
+ }
+ [ -n "$mtu" -a "$mtu" != 0 ] && {
+ echo Setting MTU of $ifname to $mtu
+ /sbin/ip link set dev $ifname mtu $mtu
+ }
+
+ uci_set_state network $interface tid "$tid"
}
proto_mbim_setup() {
@@ -169,7 +321,7 @@ proto_mbim_teardown() {
echo "mbim[$$]" "Stopping network"
[ -n "$tid" ] && {
- umbim $DBG -t$tid -d "$device" disconnect
+ umbim $DBG -t $tid -d "$device" disconnect
uci_revert_state network $interface tid
}
diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile
index 53ca67230b6..6753e47cdb7 100644
--- a/package/network/utils/uqmi/Makefile
+++ b/package/network/utils/uqmi/Makefile
@@ -1,19 +1,20 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=uqmi
-PKG_RELEASE:=3
+PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/uqmi.git
-PKG_SOURCE_DATE:=2020-11-22
-PKG_SOURCE_VERSION:=0a19b5b77140465c29e2afa7d611fe93abc9672f
-PKG_MIRROR_HASH:=0a6641f8e167efd21d464b0b2aeb1fec5f974dddcdb8822fbd5d7190d0b741b4
+PKG_SOURCE_DATE:=2024-01-16
+PKG_SOURCE_VERSION:=c3488b831ce6285c8107704156b9b8ed7d59deb3
+PKG_MIRROR_HASH:=3ca47f2ae22bc1adcb05560e6dbea824063fa914670c13f107e7e78f33399779
PKG_MAINTAINER:=Matti Laakso <malaakso@elisanet.fi>
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=
PKG_FLAGS:=nonshared
+PKG_BUILD_FLAGS:=gc-sections
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
@@ -32,9 +33,9 @@ define Package/uqmi/description
endef
TARGET_CFLAGS += \
- -I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
-
-TARGET_LDFLAGS += -Wl,--gc-sections
+ -I$(STAGING_DIR)/usr/include \
+ -Wno-error=dangling-pointer \
+ -Wno-error=maybe-uninitialized
CMAKE_OPTIONS += \
-DDEBUG=1
diff --git a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
index c0134f44dde..49fd87ff9d1 100755
--- a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
+++ b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
@@ -11,6 +11,7 @@ proto_qmi_init_config() {
no_device=1
proto_config_add_string "device:device"
proto_config_add_string apn
+ proto_config_add_string v6apn
proto_config_add_string auth
proto_config_add_string username
proto_config_add_string password
@@ -19,6 +20,7 @@ proto_qmi_init_config() {
proto_config_add_string modes
proto_config_add_string pdptype
proto_config_add_int profile
+ proto_config_add_int v6profile
proto_config_add_boolean dhcp
proto_config_add_boolean dhcpv6
proto_config_add_boolean autoconnect
@@ -31,14 +33,15 @@ proto_qmi_init_config() {
proto_qmi_setup() {
local interface="$1"
local dataformat connstat plmn_mode mcc mnc
- local device apn auth username password pincode delay modes pdptype
- local profile dhcp dhcpv6 autoconnect plmn timeout mtu $PROTO_DEFAULT_OPTIONS
+ local device apn v6apn auth username password pincode delay modes pdptype
+ local profile v6profile dhcp dhcpv6 autoconnect plmn timeout mtu $PROTO_DEFAULT_OPTIONS
local ip4table ip6table
local cid_4 pdh_4 cid_6 pdh_6
local ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
+ local profile_pdptype
- json_get_vars device apn auth username password pincode delay modes
- json_get_vars pdptype profile dhcp dhcpv6 autoconnect plmn ip4table
+ json_get_vars device apn v6apn auth username password pincode delay modes
+ json_get_vars pdptype profile v6profile dhcp dhcpv6 autoconnect plmn ip4table
json_get_vars ip6table timeout mtu $PROTO_DEFAULT_OPTIONS
[ "$timeout" = "" ] && timeout="10"
@@ -81,7 +84,9 @@ proto_qmi_setup() {
echo "Waiting for SIM initialization"
local uninitialized_timeout=0
- while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
+ # timeout 3s for first call to avoid hanging uqmi
+ uqmi -d "$device" -t 3000 --get-pin-status > /dev/null 2>&1
+ while uqmi -s -d "$device" -t 1000 --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
[ -e "$device" ] || return 1
if [ "$uninitialized_timeout" -lt "$timeout" -o "$timeout" = "0" ]; then
let uninitialized_timeout++
@@ -94,9 +99,41 @@ proto_qmi_setup() {
fi
done
- if uqmi -s -d "$device" --get-pin-status | grep '"Not supported"\|"Invalid QMI command"' > /dev/null; then
+ # Check if UIM application is stuck in illegal state
+ local uim_state_timeout=0
+ while true; do
+ json_load "$(uqmi -s -d "$device" -t 1000 --uim-get-sim-state)"
+ json_get_var card_application_state card_application_state
+
+ # SIM card is either completely absent or state is labeled as illegal
+ # Try to power-cycle the SIM card to recover from this state
+ if [ -z "$card_application_state" -o "$card_application_state" = "illegal" ]; then
+ echo "SIM in illegal state - Power-cycling SIM"
+
+ # Try to reset SIM application
+ uqmi -d "$device" -t 1000 --uim-power-off --uim-slot 1
+ sleep 3
+ uqmi -d "$device" -t 1000 --uim-power-on --uim-slot 1
+
+ if [ "$uim_state_timeout" -lt "$timeout" ] || [ "$timeout" = "0" ]; then
+ let uim_state_timeout++
+ sleep 1
+ continue
+ fi
+
+ # Recovery failed
+ proto_notify_error "$interface" SIM_ILLEGAL_STATE
+ proto_block_restart "$interface"
+ return 1
+ else
+ break
+ fi
+ done
+
+ if uqmi -s -d "$device" -t 1000 --uim-get-sim-state | grep -q '"Not supported"\|"Invalid QMI command"' &&
+ uqmi -s -d "$device" -t 1000 --get-pin-status | grep -q '"Not supported"\|"Invalid QMI command"' ; then
[ -n "$pincode" ] && {
- uqmi -s -d "$device" --verify-pin1 "$pincode" > /dev/null || uqmi -s -d "$device" --uim-verify-pin1 "$pincode" > /dev/null || {
+ uqmi -s -d "$device" -t 1000 --verify-pin1 "$pincode" > /dev/null || uqmi -s -d "$device" -t 1000 --uim-verify-pin1 "$pincode" > /dev/null || {
echo "Unable to verify PIN"
proto_notify_error "$interface" PIN_FAILED
proto_block_restart "$interface"
@@ -104,9 +141,12 @@ proto_qmi_setup() {
}
}
else
- . /usr/share/libubox/jshn.sh
- json_load "$(uqmi -s -d "$device" --get-pin-status)"
+ json_load "$(uqmi -s -d "$device" -t 1000 --get-pin-status)"
json_get_var pin1_status pin1_status
+ if [ -z "$pin1_status" ]; then
+ json_load "$(uqmi -s -d "$device" -t 1000 --uim-get-sim-state)"
+ json_get_var pin1_status pin1_status
+ fi
json_get_var pin1_verify_tries pin1_verify_tries
case "$pin1_status" in
@@ -127,7 +167,7 @@ proto_qmi_setup() {
return 1
}
if [ -n "$pincode" ]; then
- uqmi -s -d "$device" --verify-pin1 "$pincode" > /dev/null 2>&1 || uqmi -s -d "$device" --uim-verify-pin1 "$pincode" > /dev/null 2>&1 || {
+ uqmi -s -d "$device" -t 1000 --verify-pin1 "$pincode" > /dev/null 2>&1 || uqmi -s -d "$device" -t 1000 --uim-verify-pin1 "$pincode" > /dev/null 2>&1 || {
echo "Unable to verify PIN"
proto_notify_error "$interface" PIN_FAILED
proto_block_restart "$interface"
@@ -144,16 +184,17 @@ proto_qmi_setup() {
echo "PIN already verified"
;;
*)
- echo "PIN status failed ($pin1_status)"
+ echo "PIN status failed (${pin1_status:-sim_not_present})"
proto_notify_error "$interface" PIN_STATUS_FAILED
proto_block_restart "$interface"
return 1
;;
esac
+ json_cleanup
fi
if [ -n "$plmn" ]; then
- json_load "$(uqmi -s -d "$device" --get-plmn)"
+ json_load "$(uqmi -s -d "$device" -t 1000 --get-plmn)"
json_get_var plmn_mode mode
json_get_vars mcc mnc || {
mcc=0
@@ -176,25 +217,17 @@ proto_qmi_setup() {
fi
fi
- if [ -n "$mcc" -a -n "$mnc" ]; then
- uqmi -s -d "$device" --set-plmn --mcc "$mcc" --mnc "$mnc" > /dev/null 2>&1 || {
- echo "Unable to set PLMN"
- proto_notify_error "$interface" PLMN_FAILED
- proto_block_restart "$interface"
- return 1
- }
- fi
-
# Cleanup current state if any
- uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --stop-network 0xffffffff --autoconnect > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-ip-family ipv6 --stop-network 0xffffffff --autoconnect > /dev/null 2>&1
# Go online
- uqmi -s -d "$device" --set-device-operating-mode online > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-device-operating-mode online > /dev/null 2>&1
# Set IP format
- uqmi -s -d "$device" --set-data-format 802.3 > /dev/null 2>&1
- uqmi -s -d "$device" --wda-set-data-format 802.3 > /dev/null 2>&1
- dataformat="$(uqmi -s -d "$device" --wda-get-data-format)"
+ uqmi -s -d "$device" -t 1000 --set-data-format 802.3 > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --wda-set-data-format 802.3 > /dev/null 2>&1
+ dataformat="$(uqmi -s -d "$device" -t 1000 --wda-get-data-format)"
if [ "$dataformat" = '"raw-ip"' ]; then
@@ -207,16 +240,33 @@ proto_qmi_setup() {
echo "Y" > /sys/class/net/$ifname/qmi/raw_ip
fi
- uqmi -s -d "$device" --sync > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --sync > /dev/null 2>&1
- uqmi -s -d "$device" --network-register > /dev/null 2>&1
+ uqmi -s -d "$device" -t 20000 --network-register > /dev/null 2>&1
+
+ # PLMN selection must happen after the call to network-register
+ if [ -n "$mcc" -a -n "$mnc" ]; then
+ uqmi -s -d "$device" -t 1000 --set-plmn --mcc "$mcc" --mnc "$mnc" > /dev/null 2>&1 || {
+ echo "Unable to set PLMN"
+ proto_notify_error "$interface" PLMN_FAILED
+ proto_block_restart "$interface"
+ return 1
+ }
+ fi
+
+ [ -n "$modes" ] && {
+ uqmi -s -d "$device" -t 1000 --set-network-modes "$modes" > /dev/null 2>&1
+ sleep 3
+ # Scan network to not rely on registration-timeout after RAT change
+ uqmi -s -d "$device" -t 30000 --network-scan > /dev/null 2>&1
+ }
echo "Waiting for network registration"
- sleep 1
+ sleep 5
local registration_timeout=0
local registration_state=""
while true; do
- registration_state=$(uqmi -s -d "$device" --get-serving-system 2>/dev/null | jsonfilter -e "@.registration" 2>/dev/null)
+ registration_state=$(uqmi -s -d "$device" -t 1000 --get-serving-system 2>/dev/null | jsonfilter -e "@.registration" 2>/dev/null)
[ "$registration_state" = "registered" ] && break
@@ -224,7 +274,7 @@ proto_qmi_setup() {
if [ "$registration_timeout" -lt "$timeout" ] || [ "$timeout" = "0" ]; then
[ "$registration_state" = "searching" ] || {
echo "Device stopped network registration. Restart network registration"
- uqmi -s -d "$device" --network-register > /dev/null 2>&1
+ uqmi -s -d "$device" -t 20000 --network-register > /dev/null 2>&1
}
let registration_timeout++
sleep 1
@@ -237,17 +287,23 @@ proto_qmi_setup() {
fi
proto_notify_error "$interface" NETWORK_REGISTRATION_FAILED
- proto_block_restart "$interface"
return 1
done
- [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes" > /dev/null 2>&1
echo "Starting network $interface"
- pdptype=$(echo "$pdptype" | awk '{print tolower($0)}')
+ pdptype="$(echo "$pdptype" | awk '{print tolower($0)}')"
+
[ "$pdptype" = "ip" -o "$pdptype" = "ipv6" -o "$pdptype" = "ipv4v6" ] || pdptype="ip"
+ # Configure PDP type and APN for profile 1.
+ # In case GGSN rejects IPv4v6 PDP, modem might not be able to
+ # establish a non-LTE data session.
+ profile_pdptype="$pdptype"
+ [ "$profile_pdptype" = "ip" ] && profile_pdptype="ipv4"
+ uqmi -s -d "$device" -t 1000 --modify-profile "3gpp,1" --apn "$apn" --pdp-type "$profile_pdptype" > /dev/null 2>&1
+
if [ "$pdptype" = "ip" ]; then
[ -z "$autoconnect" ] && autoconnect=1
[ "$autoconnect" = 0 ] && autoconnect=""
@@ -256,16 +312,16 @@ proto_qmi_setup() {
fi
[ "$pdptype" = "ip" -o "$pdptype" = "ipv4v6" ] && {
- cid_4=$(uqmi -s -d "$device" --get-client-id wds)
+ cid_4=$(uqmi -s -d "$device" -t 1000 --get-client-id wds)
if ! [ "$cid_4" -eq "$cid_4" ] 2> /dev/null; then
echo "Unable to obtain client ID"
proto_notify_error "$interface" NO_CID
return 1
fi
- uqmi -s -d "$device" --set-client-id wds,"$cid_4" --set-ip-family ipv4 > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_4" --set-ip-family ipv4 > /dev/null 2>&1
- pdh_4=$(uqmi -s -d "$device" --set-client-id wds,"$cid_4" \
+ pdh_4=$(uqmi -s -d "$device" -t 5000 --set-client-id wds,"$cid_4" \
--start-network \
${apn:+--apn $apn} \
${profile:+--profile $profile} \
@@ -277,35 +333,38 @@ proto_qmi_setup() {
# pdh_4 is a numeric value on success
if ! [ "$pdh_4" -eq "$pdh_4" ] 2> /dev/null; then
echo "Unable to connect IPv4"
- uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
proto_notify_error "$interface" CALL_FAILED
return 1
fi
# Check data connection state
- connstat=$(uqmi -s -d "$device" --get-data-status)
+ connstat=$(uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_4" --get-data-status)
[ "$connstat" == '"connected"' ] || {
echo "No data link!"
- uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
proto_notify_error "$interface" CALL_FAILED
return 1
}
}
[ "$pdptype" = "ipv6" -o "$pdptype" = "ipv4v6" ] && {
- cid_6=$(uqmi -s -d "$device" --get-client-id wds)
+ cid_6=$(uqmi -s -d "$device" -t 1000 --get-client-id wds)
if ! [ "$cid_6" -eq "$cid_6" ] 2> /dev/null; then
echo "Unable to obtain client ID"
proto_notify_error "$interface" NO_CID
return 1
fi
- uqmi -s -d "$device" --set-client-id wds,"$cid_6" --set-ip-family ipv6 > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_6" --set-ip-family ipv6 > /dev/null 2>&1
+
+ : "${v6apn:=${apn}}"
+ : "${v6profile:=${profile}}"
- pdh_6=$(uqmi -s -d "$device" --set-client-id wds,"$cid_6" \
+ pdh_6=$(uqmi -s -d "$device" -t 5000 --set-client-id wds,"$cid_6" \
--start-network \
- ${apn:+--apn $apn} \
- ${profile:+--profile $profile} \
+ ${v6apn:+--apn $v6apn} \
+ ${v6profile:+--profile $v6profile} \
${auth:+--auth-type $auth} \
${username:+--username $username} \
${password:+--password $password} \
@@ -314,16 +373,16 @@ proto_qmi_setup() {
# pdh_6 is a numeric value on success
if ! [ "$pdh_6" -eq "$pdh_6" ] 2> /dev/null; then
echo "Unable to connect IPv6"
- uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
proto_notify_error "$interface" CALL_FAILED
return 1
fi
# Check data connection state
- connstat=$(uqmi -s -d "$device" --get-data-status)
+ connstat=$(uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_6" --set-ip-family ipv6 --get-data-status)
[ "$connstat" == '"connected"' ] || {
echo "No data link!"
- uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
proto_notify_error "$interface" CALL_FAILED
return 1
}
@@ -348,7 +407,7 @@ proto_qmi_setup() {
[ -n "$pdh_6" ] && {
if [ -z "$dhcpv6" -o "$dhcpv6" = 0 ]; then
- json_load "$(uqmi -s -d $device --set-client-id wds,$cid_6 --get-current-settings)"
+ json_load "$(uqmi -s -d $device -t 1000 --set-client-id wds,$cid_6 --get-current-settings)"
json_select ipv6
json_get_var ip_6 ip
json_get_var gateway_6 gateway
@@ -376,6 +435,7 @@ proto_qmi_setup() {
json_init
json_add_string name "${interface}_6"
json_add_string ifname "@$interface"
+ [ "$pdptype" = "ipv4v6" ] && json_add_string iface_464xlat "0"
json_add_string proto "dhcpv6"
[ -n "$ip6table" ] && json_add_string ip6table "$ip6table"
proto_add_dynamic_defaults
@@ -389,7 +449,7 @@ proto_qmi_setup() {
[ -n "$pdh_4" ] && {
if [ "$dhcp" = 0 ]; then
- json_load "$(uqmi -s -d $device --set-client-id wds,$cid_4 --get-current-settings)"
+ json_load "$(uqmi -s -d $device -t 1000 --set-client-id wds,$cid_4 --get-current-settings)"
json_select ipv4
json_get_var ip_4 ip
json_get_var gateway_4 gateway
@@ -432,16 +492,16 @@ qmi_wds_stop() {
[ -n "$cid" ] || return
- uqmi -s -d "$device" --set-client-id wds,"$cid" \
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid" \
--stop-network 0xffffffff \
--autoconnect > /dev/null 2>&1
[ -n "$pdh" ] && {
- uqmi -s -d "$device" --set-client-id wds,"$cid" \
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid" \
--stop-network "$pdh" > /dev/null 2>&1
}
- uqmi -s -d "$device" --set-client-id wds,"$cid" \
+ uqmi -s -d "$device" -t 1000 --set-client-id wds,"$cid" \
--release-client-id wds > /dev/null 2>&1
}
diff --git a/package/network/utils/wireguard-tools/Makefile b/package/network/utils/wireguard-tools/Makefile
index 5f8da147c16..e2a86c97d8d 100644
--- a/package/network/utils/wireguard-tools/Makefile
+++ b/package/network/utils/wireguard-tools/Makefile
@@ -7,16 +7,15 @@
# See /LICENSE for more information.
include $(TOPDIR)/rules.mk
-include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=wireguard-tools
-PKG_VERSION:=1.0.20210223
-PKG_RELEASE:=2
+PKG_VERSION:=1.0.20210914
+PKG_RELEASE:=3
PKG_SOURCE:=wireguard-tools-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://git.zx2c4.com/wireguard-tools/snapshot/
-PKG_HASH:=1f72da217044622d79e0bab57779e136a3df795e3761a3fc1dc0941a9055877c
+PKG_HASH:=97ff31489217bb265b7ae850d3d0f335ab07d2652ba1feec88b734bc96bd05ac
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
@@ -24,7 +23,6 @@ PKG_LICENSE_FILES:=COPYING
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
-include $(INCLUDE_DIR)/package-defaults.mk
MAKE_PATH:=src
MAKE_VARS += PLATFORM=linux
diff --git a/package/network/utils/wireguard-tools/files/wireguard.sh b/package/network/utils/wireguard-tools/files/wireguard.sh
index 63261aea71d..f6ad967b404 100644
--- a/package/network/utils/wireguard-tools/files/wireguard.sh
+++ b/package/network/utils/wireguard-tools/files/wireguard.sh
@@ -26,6 +26,7 @@ proto_wireguard_init_config() {
proto_wireguard_setup_peer() {
local peer_config="$1"
+ local disabled
local public_key
local preshared_key
local allowed_ips
@@ -34,6 +35,7 @@ proto_wireguard_setup_peer() {
local endpoint_port
local persistent_keepalive
+ config_get_bool disabled "${peer_config}" "disabled" 0
config_get public_key "${peer_config}" "public_key"
config_get preshared_key "${peer_config}" "preshared_key"
config_get allowed_ips "${peer_config}" "allowed_ips"
@@ -42,6 +44,11 @@ proto_wireguard_setup_peer() {
config_get endpoint_port "${peer_config}" "endpoint_port"
config_get persistent_keepalive "${peer_config}" "persistent_keepalive"
+ if [ "${disabled}" -eq 1 ]; then
+ # skip disabled peers
+ return 0
+ fi
+
if [ -z "$public_key" ]; then
echo "Skipping peer config $peer_config because public key is not defined."
return 0
@@ -95,6 +102,23 @@ proto_wireguard_setup_peer() {
fi
}
+ensure_key_is_generated() {
+ local private_key
+ private_key="$(uci get network."$1".private_key)"
+
+ if [ "$private_key" == "generate" ]; then
+ local ucitmp
+ oldmask="$(umask)"
+ umask 077
+ ucitmp="$(mktemp -d)"
+ private_key="$("${WG}" genkey)"
+ uci -q -t "$ucitmp" set network."$1".private_key="$private_key" && \
+ uci -q -t "$ucitmp" commit network
+ rm -rf "$ucitmp"
+ umask "$oldmask"
+ fi
+}
+
proto_wireguard_setup() {
local config="$1"
local wg_dir="/tmp/wireguard"
@@ -104,6 +128,8 @@ proto_wireguard_setup() {
local listen_port
local mtu
+ ensure_key_is_generated "${config}"
+
config_load network
config_get private_key "${config}" "private_key"
config_get listen_port "${config}" "listen_port"
diff --git a/package/network/utils/wireguard-tools/files/wireguard_watchdog b/package/network/utils/wireguard-tools/files/wireguard_watchdog
index c0a5a0aa33c..fc90f4a25b3 100644
--- a/package/network/utils/wireguard-tools/files/wireguard_watchdog
+++ b/package/network/utils/wireguard-tools/files/wireguard_watchdog
@@ -17,6 +17,7 @@
check_peer_activity() {
local cfg=$1
local iface=$2
+ local disabled
local public_key
local endpoint_host
local endpoint_port
@@ -24,9 +25,16 @@ check_peer_activity() {
local last_handshake
local idle_seconds
+ config_get_bool disabled "${cfg}" "disabled" 0
config_get public_key "${cfg}" "public_key"
config_get endpoint_host "${cfg}" "endpoint_host"
config_get endpoint_port "${cfg}" "endpoint_port"
+
+ if [ "${disabled}" -eq 1 ]; then
+ # skip disabled peers
+ return 0
+ fi
+
persistent_keepalive=$(wg show ${iface} persistent-keepalive | grep ${public_key} | awk '{print $2}')
# only process peers with endpoints and keepalive set
@@ -51,7 +59,7 @@ check_peer_activity() {
}
# query ubus for all active wireguard interfaces
-wg_ifaces=$(ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=true]' | jsonfilter -a -e '@[@.proto="wireguard"].interface' | tr "\n" " ")
+eval $(ubus -S call network.interface dump | jsonfilter -e 'wg_ifaces=@.interface[@.up=true && @.proto="wireguard"].interface')
# check every peer in every active wireguard interface
config_load network
diff --git a/package/network/utils/wireless-tools/Makefile b/package/network/utils/wireless-tools/Makefile
index 52e246a59c8..6ac66a056a0 100644
--- a/package/network/utils/wireless-tools/Makefile
+++ b/package/network/utils/wireless-tools/Makefile
@@ -8,6 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=wireless-tools
+PKG_CPE_ID:=cpe:/a:wireless_tools_project:wireless_tools
PKG_VERSION:=29
PKG_MINOR:=
PKG_RELEASE:=6
diff --git a/package/network/utils/wpan-tools/Makefile b/package/network/utils/wpan-tools/Makefile
index 060aaf50468..7b2cfe7a602 100644
--- a/package/network/utils/wpan-tools/Makefile
+++ b/package/network/utils/wpan-tools/Makefile
@@ -1,18 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2015 OpenWrt.org
#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
include $(TOPDIR)/rules.mk
PKG_NAME:=wpan-tools
-PKG_VERSION:=0.7
+PKG_VERSION:=0.9
+PKG_RELEASE=1
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
-PKG_SOURCE_URL:=http://wpan.cakelab.org/releases/
-PKG_HASH:=c16de9d7861c2d9b6a4436a0fac730f9f545ee290b92bc770c538ec6a3f22309
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/linux-wpan/wpan-tools/releases/download/$(PKG_NAME)-$(PKG_VERSION)/$(PKG_NAME)-$(PKG_VERSION).tar.gz?
+PKG_HASH:=fa76d9c1874220e4b1f91c226f42baf1e372ea8ccf4b892effaf0d164448f608
include $(INCLUDE_DIR)/package.mk
@@ -20,7 +19,7 @@ define Package/wpan-tools
SECTION:=net
CATEGORY:=Network
TITLE:=cfg802154 interface configuration utility
- URL:=http://wpan.cakelab.org/
+ URL:=https://linux-wpan.org/wpan-tools.html
DEPENDS:= +libnl
endef
diff --git a/package/network/utils/wpan-tools/patches/001-src-nl_extras.h-fix-compatibility-with-libnl-3.3.0.patch b/package/network/utils/wpan-tools/patches/001-src-nl_extras.h-fix-compatibility-with-libnl-3.3.0.patch
deleted file mode 100644
index 1370854b6b5..00000000000
--- a/package/network/utils/wpan-tools/patches/001-src-nl_extras.h-fix-compatibility-with-libnl-3.3.0.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From bb522bd584f05e6658d5dba97f48ca018f46394c Mon Sep 17 00:00:00 2001
-From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
-Date: Sat, 6 May 2017 14:36:08 +0200
-Subject: [PATCH] src/nl_extras.h: fix compatibility with libnl 3.3.0
-
-nl_extras.h defines a set of nla_set_s*() functions if not provided by
-libnl. They are provided by libnl since version 3.2.26. The test
-(LIBNL_VER_MIC <= 26) was working fine while libnl was in the 3.2.x
-series, but now that they have incremented the minor version, the
-micro version was reset to 0, with the latest libnl version being
-3.3.0.
-
-Due to this, the condition (LIBNL_VER_MIC <= 26) is true, and we get
-redefinition errors because nl_extras.h redefines functions already
-provided by libnl.
-
-This commit improves the condition so that nl_extras.h provides the
-missing functions only if the minor version is < 2, or if minor is 2
-and micro is < 26.
-
-Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
----
- src/nl_extras.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/src/nl_extras.h
-+++ b/src/nl_extras.h
-@@ -1,7 +1,7 @@
- #ifndef __NL_EXTRAS_H
- #define __NL_EXTRAS_H
-
--#if LIBNL_VER_MIC <= 26
-+#if (LIBNL_VER_MIN < 2) || (LIBNL_VER_MIN == 2) && (LIBNL_VER_MIC <= 26)
-
- #ifndef NLA_S8
-
-@@ -45,6 +45,6 @@ static inline int32_t nla_get_s32(struct
-
- #endif /* NLA_S64 */
-
--#endif /* LIBNL_VER_MIC */
-+#endif /* LIBNL_VER_* */
-
- #endif /* __NL_EXTRAS_H */
diff --git a/package/network/utils/wwan/Makefile b/package/network/utils/wwan/Makefile
index 1c5a5e6669f..19404383cb7 100644
--- a/package/network/utils/wwan/Makefile
+++ b/package/network/utils/wwan/Makefile
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=wwan
PKG_VERSION:=2019-04-29
-PKG_RELEASE=5
+PKG_RELEASE=6
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=
diff --git a/package/network/utils/wwan/files/data/0e8d-00a5 b/package/network/utils/wwan/files/data/0e8d-00a5
new file mode 100644
index 00000000000..23a7ce36161
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0e8d-00a5
@@ -0,0 +1,5 @@
+{
+ "desc": "Medion S4222",
+ "control": 2,
+ "data": 0
+}
diff --git a/package/network/utils/xdp-tools/Makefile b/package/network/utils/xdp-tools/Makefile
new file mode 100644
index 00000000000..dba775e4ea1
--- /dev/null
+++ b/package/network/utils/xdp-tools/Makefile
@@ -0,0 +1,139 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=xdp-tools
+PKG_RELEASE:=1
+PKG_VERSION:=1.2.9
+PKG_HASH:=159ed8d3c8195d812ec3cde83bd736245a72743af372998320d39c2ba69ab142
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://codeload.github.com/xdp-project/xdp-tools/tar.gz/v$(PKG_VERSION)?
+PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_VERSION))
+
+PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
+
+PKG_BUILD_DEPENDS:=bpf-headers
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/bpf.mk
+include $(INCLUDE_DIR)/nls.mk
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+define Package/libxdp
+ SECTION:=libs
+ CATEGORY:=Libraries
+ TITLE:=libxdp - Library for use with XDP
+ LICENSE:=LGPL-2.1 OR BSD-2-Clause
+ ABI_VERSION:=$(PKG_ABI_VERSION)
+ URL:=https://github.com/xdp-project/xdp-tools/
+ DEPENDS:=+libbpf $(BPF_DEPENDS)
+endef
+
+define Package/libxdp/description
+libxdp - library for attaching XDP programs and using AF_XDP sockets
+endef
+
+define Package/xdp-tools/Default
+ SECTION:=net
+ CATEGORY:=Network
+ LICENSE:=GPL-2.0-only
+ URL:=https://github.com/xdp-project/xdp-tools/
+ DEPENDS:=+libxdp
+endef
+
+define Package/xdp-filter
+$(call Package/xdp-tools/Default)
+ TITLE:=xdp-filter - a simple XDP-powered packet filter
+endef
+
+define Package/xdp-filter/description
+xdp-filter is a packet filtering utility powered by XDP. It is deliberately
+simple and so does not have the same matching capabilities as, e.g.,
+netfilter. Instead, thanks to XDP, it can achieve very high drop rates:
+tens of millions of packets per second on a single CPU core.
+endef
+
+
+define Package/xdp-loader
+$(call Package/xdp-tools/Default)
+ TITLE:=xdp-loader - an XDP program loader
+endef
+
+define Package/xdp-loader/description
+xdp-loader is a simple loader for XDP programs with support for attaching
+multiple programs to the same interface. To achieve this it exposes the same
+load and unload semantics exposed by the libxdp library.
+endef
+
+define Package/xdpdump
+$(call Package/xdp-tools/Default)
+ TITLE:=xdpdump - tool for capturing packets at the XDP layer
+ DEPENDS+=+libpcap
+endef
+
+define Package/xdpdump/description
+xdpdump - a simple tcpdump like tool for capturing packets at the XDP layer
+endef
+
+TARGET_LDFLAGS += $(INTL_LDFLAGS)
+
+CONFIGURE_VARS += \
+ FORCE_SYSTEM_LIBBPF=1 \
+ CC="$(TARGET_CC)" \
+ CFLAGS="$(TARGET_CFLAGS)" \
+ LDFLAGS="$(TARGET_LDFLAGS)" \
+ CLANG="$(CLANG)" \
+ BPF_TARGET="$(BPF_TARGET)" \
+ LLC="$(LLVM_LLC)"
+
+MAKE_VARS += \
+ PREFIX=/usr \
+ RUNDIR=/tmp/run
+
+define Build/Configure
+ $(call Build/Configure/Default)
+ echo "BPF_CFLAGS += -I$(BPF_HEADERS_DIR)/tools/lib -fno-stack-protector" >> $(PKG_BUILD_DIR)/config.mk
+endef
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/include/xdp
+ $(CP) $(PKG_INSTALL_DIR)/usr/include/xdp/*.h $(1)/usr/include/xdp/
+ $(INSTALL_DIR) $(1)/usr/lib/bpf
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libxdp.{a,so*} $(1)/usr/lib/
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/bpf/*.o $(1)/usr/lib/bpf
+ $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libxdp.pc \
+ $(1)/usr/lib/pkgconfig/
+ $(SED) 's,/usr/include,$$$${prefix}/include,g' \
+ $(1)/usr/lib/pkgconfig/libxdp.pc
+ $(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \
+ $(1)/usr/lib/pkgconfig/libxdp.pc
+endef
+
+define Package/xdp-filter/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/xdp-filter $(1)/usr/sbin
+endef
+
+define Package/xdp-loader/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/xdp-loader $(1)/usr/sbin
+endef
+
+define Package/xdpdump/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/xdpdump $(1)/usr/sbin
+endef
+
+define Package/libxdp/install
+ $(INSTALL_DIR) $(1)/usr/lib/bpf
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libxdp.so.* $(1)/usr/lib/
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/bpf/*.o $(1)/usr/lib/bpf
+endef
+
+$(eval $(call BuildPackage,libxdp))
+$(eval $(call BuildPackage,xdp-filter))
+$(eval $(call BuildPackage,xdp-loader))
+$(eval $(call BuildPackage,xdpdump))
diff --git a/package/network/utils/xdp-tools/patches/010-configure-respect-LDFLAGS.patch b/package/network/utils/xdp-tools/patches/010-configure-respect-LDFLAGS.patch
new file mode 100644
index 00000000000..e2fbfa57dca
--- /dev/null
+++ b/package/network/utils/xdp-tools/patches/010-configure-respect-LDFLAGS.patch
@@ -0,0 +1,29 @@
+--- a/configure
++++ b/configure
+@@ -174,7 +174,7 @@ int main(int argc, char **argv) {
+ return 0;
+ }
+ EOF
+- libpcap_err=$($CC -o $TMPDIR/libpcaptest $TMPDIR/libpcaptest.c $LIBPCAP_CFLAGS $LIBPCAP_LDLIBS 2>&1)
++ libpcap_err=$($CC -o $TMPDIR/libpcaptest $TMPDIR/libpcaptest.c $LIBPCAP_CFLAGS $LIBPCAP_LDLIBS $LDFLAGS 2>&1)
+ if [ "$?" -eq "0" ]; then
+ echo "HAVE_PCAP:=y" >>$CONFIG
+ [ -n "$LIBPCAP_CFLAGS" ] && echo 'CFLAGS += ' $LIBPCAP_CFLAGS >> $CONFIG
+@@ -222,7 +222,7 @@ int main(int argc, char **argv) {
+ return 0;
+ }
+ EOF
+- libbpf_err=$($CC -o $TMPDIR/libbpftest $TMPDIR/libbpftest.c -Werror $LIBBPF_CFLAGS $LIBBPF_LDLIBS 2>&1)
++ libbpf_err=$($CC -o $TMPDIR/libbpftest $TMPDIR/libbpftest.c -Werror $LIBBPF_CFLAGS $LIBBPF_LDLIBS $LDFLAGS 2>&1)
+ if [ "$?" -eq "0" ]; then
+ echo "HAVE_FEATURES+=${config_var}" >>"$CONFIG"
+ echo "yes"
+@@ -289,7 +289,7 @@ int main(int argc, char **argv) {
+ }
+ EOF
+
+- libbpf_err=$($CC -o $TMPDIR/libbpftest $TMPDIR/libbpftest.c -Werror $LIBBPF_CFLAGS $LIBBPF_LDLIBS 2>&1)
++ libbpf_err=$($CC -o $TMPDIR/libbpftest $TMPDIR/libbpftest.c -Werror $LIBBPF_CFLAGS $LIBBPF_LDLIBS $LDFLAGS 2>&1)
+ if [ "$?" -eq "0" ]; then
+ echo "SYSTEM_LIBBPF:=y" >>$CONFIG
+ echo "LIBBPF_VERSION=$LIBBPF_VERSION" >>$CONFIG