From 86c287f010c66796344506cfafd3af1c39bbbda3 Mon Sep 17 00:00:00 2001 From: orangepi-xunlong <258384131@qq.com> Date: Fri, 6 Jan 2023 16:05:10 +0800 Subject: [PATCH] Update for Orange Pi 5 v1.1.0 --- external/config/boards/orangepi5.conf | 2 +- .../config/bootscripts/boot-rockchip64.cmd | 6 +- .../config_cli_standard/packages.additional | 2 + .../linux-rockchip-rk3588-legacy.config | 414 ++-- .../environments/xfce/config_base/packages | 1 + external/config/sources/arm64.conf | 14 +- .../sources/families/rockchip-rk3588.conf | 2 +- .../conf-hooks.d/orangepi-plymouth | 3 + .../bsp/rk3588/usr/local/bin/create_ap | 1919 +++++++++++++++++ .../rk3588/usr/local/bin/set_lcd_rotate.sh | 56 +- .../plymouth-theme-orangepi/bullet.png | Bin 0 -> 616 bytes .../plymouth-theme-orangepi/capslock.png | Bin 0 -> 960 bytes .../plymouth-theme-orangepi/debian/postinst | 17 + .../plymouth-theme-orangepi/debian/postrm | 7 + .../plymouth-theme-orangepi/debian/prerm | 13 + .../plymouth-theme-orangepi/entry.png | Bin 0 -> 8999 bytes .../plymouth-theme-orangepi/keyboard.png | Bin 0 -> 946 bytes .../plymouth-theme-orangepi/keymap-render.png | Bin 0 -> 26362 bytes .../packages/plymouth-theme-orangepi/lock.png | Bin 0 -> 1997 bytes .../plymouth-theme-orangepi/orangepi-logo.png | Bin 0 -> 14421 bytes .../plymouth-theme-orangepi/orangepi.plymouth | 64 + .../plymouth-theme-orangepi/spinner.gif | Bin 0 -> 18707 bytes .../plymouth-theme-orangepi/watermark.png | Bin 0 -> 14421 bytes scripts/compilation.sh | 112 +- scripts/configuration.sh | 1 + scripts/debootstrap.sh | 2 +- scripts/distributions.sh | 9 + scripts/general.sh | 10 +- scripts/main.sh | 17 +- 29 files changed, 2406 insertions(+), 265 deletions(-) create mode 100644 external/packages/bsp/common/usr/share/initramfs-tools/conf-hooks.d/orangepi-plymouth create mode 100755 external/packages/bsp/rk3588/usr/local/bin/create_ap create mode 100755 external/packages/plymouth-theme-orangepi/bullet.png create mode 100755 external/packages/plymouth-theme-orangepi/capslock.png create mode 100644 external/packages/plymouth-theme-orangepi/debian/postinst create mode 100644 external/packages/plymouth-theme-orangepi/debian/postrm create mode 100644 external/packages/plymouth-theme-orangepi/debian/prerm create mode 100755 external/packages/plymouth-theme-orangepi/entry.png create mode 100755 external/packages/plymouth-theme-orangepi/keyboard.png create mode 100755 external/packages/plymouth-theme-orangepi/keymap-render.png create mode 100755 external/packages/plymouth-theme-orangepi/lock.png create mode 100755 external/packages/plymouth-theme-orangepi/orangepi-logo.png create mode 100644 external/packages/plymouth-theme-orangepi/orangepi.plymouth create mode 100755 external/packages/plymouth-theme-orangepi/spinner.gif create mode 100755 external/packages/plymouth-theme-orangepi/watermark.png diff --git a/external/config/boards/orangepi5.conf b/external/config/boards/orangepi5.conf index 233f48729312..7407b8aec044 100644 --- a/external/config/boards/orangepi5.conf +++ b/external/config/boards/orangepi5.conf @@ -12,4 +12,4 @@ BOOT_SUPPORT_SPI="yes" SKIP_BOOTSPLASH="yes" # Skip boot splash patch, conflicts with CONFIG_VT=yes DISTRIB_TYPE_LEGACY="bullseye focal jammy" BOOTFS_TYPE="fat" -REVISION="1.0.8" +REVISION="1.1.0" diff --git a/external/config/bootscripts/boot-rockchip64.cmd b/external/config/bootscripts/boot-rockchip64.cmd index 8f31242a3c8a..b09625ae0337 100644 --- a/external/config/bootscripts/boot-rockchip64.cmd +++ b/external/config/bootscripts/boot-rockchip64.cmd @@ -26,7 +26,11 @@ if test "${logo}" = "disabled"; then setenv logo "logo.nologo"; fi if test "${console}" = "display" || test "${console}" = "both"; then setenv consoleargs "console=tty1"; fi if test "${console}" = "serial" || test "${console}" = "both"; then setenv consoleargs "console=ttyS2,1500000 ${consoleargs}"; fi if test "${earlycon}" = "on"; then setenv consoleargs "earlycon ${consoleargs}"; fi -if test "${bootlogo}" = "true"; then setenv consoleargs "bootsplash.bootfile=bootsplash.orangepi ${consoleargs}"; fi +if test "${bootlogo}" = "true"; then + setenv consoleargs "splash plymouth.ignore-serial-consoles ${consoleargs}" +else + setenv consoleargs "splash=verbose ${consoleargs}" +fi # get PARTUUID of first partition on SD/eMMC the boot script was loaded from if test "${devtype}" = "mmc"; then part uuid mmc ${devnum}:1 partuuid; fi diff --git a/external/config/cli/focal/main/config_cli_standard/packages.additional b/external/config/cli/focal/main/config_cli_standard/packages.additional index 5f958847ac15..d2b9dabd1439 100644 --- a/external/config/cli/focal/main/config_cli_standard/packages.additional +++ b/external/config/cli/focal/main/config_cli_standard/packages.additional @@ -25,6 +25,8 @@ libproc-processtable-perl nfs-common ntfs-3g pciutils +plymouth +plymouth-themes pv qrencode rfkill diff --git a/external/config/kernel/linux-rockchip-rk3588-legacy.config b/external/config/kernel/linux-rockchip-rk3588-legacy.config index 057d2e778217..c96b063c5eb2 100644 --- a/external/config/kernel/linux-rockchip-rk3588-legacy.config +++ b/external/config/kernel/linux-rockchip-rk3588-legacy.config @@ -778,7 +778,8 @@ CONFIG_BLK_SCSI_REQUEST=y CONFIG_BLK_CGROUP_RWSTAT=y CONFIG_BLK_DEV_BSG=y CONFIG_BLK_DEV_BSGLIB=y -# CONFIG_BLK_DEV_INTEGRITY is not set +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y # CONFIG_BLK_DEV_ZONED is not set CONFIG_BLK_DEV_THROTTLING=y # CONFIG_BLK_DEV_THROTTLING_LOW is not set @@ -2128,27 +2129,30 @@ CONFIG_OF_RESERVED_MEM=y # CONFIG_OF_OVERLAY is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_NULL_BLK is not set -CONFIG_CDROM=y -# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_CDROM=m +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m CONFIG_ZRAM=y # CONFIG_ZRAM_WRITEBACK is not set # CONFIG_ZRAM_MEMORY_TRACKING is not set -# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_UMEM=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_DRBD is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_SKD is not set -# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_DRBD=m +# CONFIG_DRBD_FAULT_INJECTION is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SKD=m +CONFIG_BLK_DEV_SX8=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 CONFIG_BLK_DEV_RAM_SIZE=4096 -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set -# CONFIG_BLK_DEV_RBD is not set -# CONFIG_BLK_DEV_RSXX is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_RSXX=m # # NVME Support @@ -2227,85 +2231,133 @@ CONFIG_EEPROM_93CX6=m # SCSI device support # CONFIG_SCSI_MOD=y -# CONFIG_RAID_ATTRS is not set +CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # # SCSI support type (disk, tape, CD-ROM) # -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -CONFIG_BLK_DEV_SR=y -# CONFIG_CHR_DEV_SG is not set -# CONFIG_CHR_DEV_SCH is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y # # SCSI Transports # CONFIG_SCSI_SPI_ATTRS=y -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set -# CONFIG_SCSI_SAS_LIBSAS is not set -# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_SCSI_SRP_ATTRS=m # end of SCSI Transports CONFIG_SCSI_LOWLEVEL=y -# CONFIG_ISCSI_TCP is not set -# CONFIG_ISCSI_BOOT_SYSFS is not set -# CONFIG_SCSI_CXGB3_ISCSI is not set -# CONFIG_SCSI_CXGB4_ISCSI is not set -# CONFIG_SCSI_BNX2_ISCSI is not set -# CONFIG_BE2ISCSI is not set -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_HPSA is not set -# CONFIG_SCSI_3W_9XXX is not set -# CONFIG_SCSI_3W_SAS is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AACRAID is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_AIC94XX is not set -# CONFIG_SCSI_HISI_SAS is not set -# CONFIG_SCSI_MVSAS is not set -# CONFIG_SCSI_MVUMI is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_ARCMSR is not set -# CONFIG_SCSI_ESAS2R is not set -# CONFIG_MEGARAID_NEWGEN is not set -# CONFIG_MEGARAID_LEGACY is not set -# CONFIG_MEGARAID_SAS is not set -# CONFIG_SCSI_MPT3SAS is not set -# CONFIG_SCSI_MPT2SAS is not set -# CONFIG_SCSI_SMARTPQI is not set -# CONFIG_SCSI_UFSHCD is not set -# CONFIG_SCSI_HPTIOP is not set -# CONFIG_SCSI_MYRB is not set -# CONFIG_SCSI_MYRS is not set -# CONFIG_SCSI_SNIC is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_FDOMAIN_PCI is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_STEX is not set -# CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLA_ISCSI is not set -# CONFIG_SCSI_DC395x is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_WD719X is not set -# CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_PMCRAID is not set -# CONFIG_SCSI_PM8001 is not set -# CONFIG_SCSI_DH is not set +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2X_FCOE=m +CONFIG_BE2ISCSI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_3W_SAS=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=5000 +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_AIC94XX_DEBUG=y +CONFIG_SCSI_HISI_SAS=m +CONFIG_SCSI_MVSAS=m +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVSAS_TASKLET is not set +CONFIG_SCSI_MVUMI=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ESAS2R=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_MPT2SAS_MAX_SGE=128 +CONFIG_SCSI_MPT3SAS_MAX_SGE=128 +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_SMARTPQI=m +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m +CONFIG_SCSI_UFS_DWC_TC_PCI=m +CONFIG_SCSI_UFSHCD_PLATFORM=m +CONFIG_SCSI_UFS_CDNS_PLATFORM=m +CONFIG_SCSI_UFS_DWC_TC_PLATFORM=m +# CONFIG_SCSI_UFS_BSG is not set +# CONFIG_SCSI_UFS_HPB is not set +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_MYRB=m +CONFIG_SCSI_MYRS=m +CONFIG_LIBFC=m +CONFIG_LIBFCOE=m +CONFIG_FCOE=m +CONFIG_SCSI_SNIC=m +# CONFIG_SCSI_SNIC_DEBUG_FS is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_FDOMAIN=m +CONFIG_SCSI_FDOMAIN_PCI=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_MMIO is not set +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +# CONFIG_SCSI_LPFC_DEBUG_FS is not set +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_AM53C974=m +CONFIG_SCSI_WD719X=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_PMCRAID=m +CONFIG_SCSI_PM8001=m +CONFIG_SCSI_BFA_FC=m +CONFIG_SCSI_CHELSIO_FCOE=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m # end of SCSI device support CONFIG_HAVE_PATA_PLATFORM=y @@ -2407,19 +2459,19 @@ CONFIG_MACVLAN=m CONFIG_MACVTAP=m CONFIG_IPVLAN_L3S=y CONFIG_IPVLAN=m -# CONFIG_IPVTAP is not set +CONFIG_IPVTAP=m CONFIG_VXLAN=m CONFIG_GENEVE=m -# CONFIG_BAREUDP is not set -# CONFIG_GTP is not set -# CONFIG_MACSEC is not set +CONFIG_BAREUDP=m +CONFIG_GTP=m +CONFIG_MACSEC=m CONFIG_NETCONSOLE=m -# CONFIG_NETCONSOLE_DYNAMIC is not set +CONFIG_NETCONSOLE_DYNAMIC=y CONFIG_NETPOLL=y CONFIG_NET_POLL_CONTROLLER=y CONFIG_TUN=m CONFIG_TAP=m -# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_TUN_VNET_CROSS_LE=y CONFIG_VETH=m CONFIG_NLMON=m CONFIG_NET_VRF=m @@ -2450,6 +2502,7 @@ CONFIG_ATM_DRIVERS=y # end of Distributed Switch Architecture drivers CONFIG_ETHERNET=y +CONFIG_MDIO=m # CONFIG_NET_VENDOR_3COM is not set # CONFIG_NET_VENDOR_ADAPTEC is not set # CONFIG_NET_VENDOR_AGERE is not set @@ -2466,12 +2519,29 @@ CONFIG_NET_VENDOR_AQUANTIA=y # CONFIG_NET_VENDOR_ATHEROS is not set CONFIG_NET_VENDOR_AURORA=y # CONFIG_AURORA_NB8800 is not set -# CONFIG_NET_VENDOR_BROADCOM is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BCMGENET is not set +CONFIG_BNX2=m +CONFIG_CNIC=m +# CONFIG_TIGON3 is not set +# CONFIG_BNX2X is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_BNXT is not set # CONFIG_NET_VENDOR_BROCADE is not set CONFIG_NET_VENDOR_CADENCE=y # CONFIG_MACB is not set # CONFIG_NET_VENDOR_CAVIUM is not set -# CONFIG_NET_VENDOR_CHELSIO is not set +CONFIG_NET_VENDOR_CHELSIO=y +# CONFIG_CHELSIO_T1 is not set +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +# CONFIG_CHELSIO_T4_DCB is not set +# CONFIG_CHELSIO_T4VF is not set +CONFIG_CHELSIO_LIB=m +CONFIG_CHELSIO_INLINE_CRYPTO=y +# CONFIG_CRYPTO_DEV_CHELSIO_TLS is not set +# CONFIG_CHELSIO_TLS_DEVICE is not set # CONFIG_NET_VENDOR_CISCO is not set CONFIG_NET_VENDOR_CORTINA=y # CONFIG_GEMINI_ETHERNET is not set @@ -6031,95 +6101,105 @@ CONFIG_RTC_INTF_DEV=y # # I2C RTC drivers # -# CONFIG_RTC_DRV_ABB5ZES3 is not set -# CONFIG_RTC_DRV_ABEOZ9 is not set -# CONFIG_RTC_DRV_ABX80X is not set -# CONFIG_RTC_DRV_DS1307 is not set -# CONFIG_RTC_DRV_DS1374 is not set -# CONFIG_RTC_DRV_DS1672 is not set +CONFIG_RTC_DRV_ABB5ZES3=m +CONFIG_RTC_DRV_ABEOZ9=m +CONFIG_RTC_DRV_ABX80X=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1307_CENTURY=y +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1374_WDT=y +CONFIG_RTC_DRV_DS1672=m CONFIG_RTC_DRV_HYM8563=y -# CONFIG_RTC_DRV_MAX6900 is not set -CONFIG_RTC_DRV_RK808=y +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RK808=m # CONFIG_RTC_DRV_ROCKCHIP is not set -# CONFIG_RTC_DRV_RS5C372 is not set -# CONFIG_RTC_DRV_ISL1208 is not set -# CONFIG_RTC_DRV_ISL12022 is not set -# CONFIG_RTC_DRV_ISL12026 is not set -# CONFIG_RTC_DRV_X1205 is not set -# CONFIG_RTC_DRV_PCF8523 is not set -# CONFIG_RTC_DRV_PCF85063 is not set -# CONFIG_RTC_DRV_PCF85363 is not set -# CONFIG_RTC_DRV_PCF8563 is not set -# CONFIG_RTC_DRV_PCF8583 is not set -# CONFIG_RTC_DRV_M41T80 is not set -# CONFIG_RTC_DRV_BQ32K is not set -# CONFIG_RTC_DRV_TPS6586X is not set -# CONFIG_RTC_DRV_S35390A is not set -# CONFIG_RTC_DRV_FM3130 is not set -# CONFIG_RTC_DRV_RX8010 is not set -# CONFIG_RTC_DRV_RX8581 is not set -# CONFIG_RTC_DRV_RX8025 is not set -# CONFIG_RTC_DRV_EM3027 is not set -# CONFIG_RTC_DRV_RV3028 is not set -# CONFIG_RTC_DRV_RV3032 is not set -# CONFIG_RTC_DRV_RV8803 is not set -# CONFIG_RTC_DRV_SD3078 is not set +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_ISL12022=m +CONFIG_RTC_DRV_ISL12026=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8523=m +CONFIG_RTC_DRV_PCF85063=m +CONFIG_RTC_DRV_PCF85363=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_BQ32K=m +CONFIG_RTC_DRV_TPS6586X=m +CONFIG_RTC_DRV_S35390A=m +CONFIG_RTC_DRV_FM3130=m +CONFIG_RTC_DRV_RX8010=m +CONFIG_RTC_DRV_RX8581=m +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m +CONFIG_RTC_DRV_RV3032=m +CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD3078=m # # SPI RTC drivers # -# CONFIG_RTC_DRV_M41T93 is not set -# CONFIG_RTC_DRV_M41T94 is not set -# CONFIG_RTC_DRV_DS1302 is not set -# CONFIG_RTC_DRV_DS1305 is not set -# CONFIG_RTC_DRV_DS1343 is not set -# CONFIG_RTC_DRV_DS1347 is not set -# CONFIG_RTC_DRV_DS1390 is not set -# CONFIG_RTC_DRV_MAX6916 is not set -# CONFIG_RTC_DRV_R9701 is not set -# CONFIG_RTC_DRV_RX4581 is not set -# CONFIG_RTC_DRV_RX6110 is not set -# CONFIG_RTC_DRV_RS5C348 is not set -# CONFIG_RTC_DRV_MAX6902 is not set -# CONFIG_RTC_DRV_PCF2123 is not set -# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m +CONFIG_RTC_DRV_DS1302=m +CONFIG_RTC_DRV_DS1305=m +CONFIG_RTC_DRV_DS1343=m +CONFIG_RTC_DRV_DS1347=m +CONFIG_RTC_DRV_DS1390=m +CONFIG_RTC_DRV_MAX6916=m +CONFIG_RTC_DRV_R9701=m +CONFIG_RTC_DRV_RX4581=m +CONFIG_RTC_DRV_RX6110=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF2123=m +CONFIG_RTC_DRV_MCP795=m CONFIG_RTC_I2C_AND_SPI=y # # SPI and I2C RTC drivers # -# CONFIG_RTC_DRV_DS3232 is not set -# CONFIG_RTC_DRV_PCF2127 is not set -# CONFIG_RTC_DRV_RV3029C2 is not set +CONFIG_RTC_DRV_DS3232=m +CONFIG_RTC_DRV_DS3232_HWMON=y +CONFIG_RTC_DRV_PCF2127=m +CONFIG_RTC_DRV_RV3029C2=m +CONFIG_RTC_DRV_RV3029_HWMON=y # # Platform RTC drivers # -# CONFIG_RTC_DRV_DS1286 is not set -# CONFIG_RTC_DRV_DS1511 is not set -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_DS1685_FAMILY is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_DS2404 is not set -# CONFIG_RTC_DRV_EFI is not set -# CONFIG_RTC_DRV_STK17TA8 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_M48T35 is not set -# CONFIG_RTC_DRV_M48T59 is not set -# CONFIG_RTC_DRV_MSM6242 is not set -# CONFIG_RTC_DRV_BQ4802 is not set -# CONFIG_RTC_DRV_RP5C01 is not set -# CONFIG_RTC_DRV_V3020 is not set -# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_DRV_DS1286=m +CONFIG_RTC_DRV_DS1511=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1685_FAMILY=m +CONFIG_RTC_DRV_DS1685=y +# CONFIG_RTC_DRV_DS1689 is not set +# CONFIG_RTC_DRV_DS17285 is not set +# CONFIG_RTC_DRV_DS17485 is not set +# CONFIG_RTC_DRV_DS17885 is not set +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_DS2404=m +CONFIG_RTC_DRV_EFI=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T35=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_MSM6242=m +CONFIG_RTC_DRV_BQ4802=m +CONFIG_RTC_DRV_RP5C01=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_ZYNQMP=m # # on-CPU RTC drivers # -# CONFIG_RTC_DRV_PL030 is not set -# CONFIG_RTC_DRV_PL031 is not set -# CONFIG_RTC_DRV_CADENCE is not set -# CONFIG_RTC_DRV_FTRTC010 is not set -# CONFIG_RTC_DRV_R7301 is not set +CONFIG_RTC_DRV_PL030=m +CONFIG_RTC_DRV_PL031=m +CONFIG_RTC_DRV_CADENCE=m +CONFIG_RTC_DRV_FTRTC010=m +CONFIG_RTC_DRV_R7301=m # # HID Sensor RTC drivers @@ -6182,7 +6262,16 @@ CONFIG_DMABUF_HEAPS_CMA=y # end of DMABUF options # CONFIG_AUXDISPLAY is not set -# CONFIG_UIO is not set +CONFIG_UIO=m +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set # CONFIG_VFIO is not set # CONFIG_VIRT_DRIVERS is not set CONFIG_VIRTIO_MENU=y @@ -6338,6 +6427,7 @@ CONFIG_FB_TFT_WATTEROTT=m # CONFIG_XIL_AXIS_FIFO is not set # CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set # CONFIG_QLGE is not set # CONFIG_WFX is not set # CONFIG_SPMI_HISI3670 is not set @@ -7131,10 +7221,10 @@ CONFIG_ARM_PMU=y # CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y -# CONFIG_ANDROID_BINDERFS is not set +CONFIG_ANDROID_BINDERFS=y CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" # CONFIG_ANDROID_BINDER_IPC_SELFTEST is not set -CONFIG_ANDROID_DEBUG_SYMBOLS=y +# CONFIG_ANDROID_DEBUG_SYMBOLS is not set # CONFIG_ANDROID_VENDOR_HOOKS is not set # CONFIG_ANDROID_KABI_RESERVE is not set # CONFIG_ANDROID_VENDOR_OEM_DATA is not set @@ -7786,6 +7876,7 @@ CONFIG_CRYPTO_DEV_ROCKCHIP_V1=y CONFIG_CRYPTO_DEV_ROCKCHIP_V2=y # CONFIG_CRYPTO_DEV_ROCKCHIP_V3 is not set CONFIG_CRYPTO_DEV_ROCKCHIP_DEV=y +# CONFIG_CRYPTO_DEV_CHELSIO is not set # CONFIG_CRYPTO_DEV_SAFEXCEL is not set # CONFIG_CRYPTO_DEV_CCREE is not set # CONFIG_CRYPTO_DEV_HISI_SEC is not set @@ -7882,6 +7973,7 @@ CONFIG_TEXTSEARCH=y CONFIG_TEXTSEARCH_KMP=m CONFIG_TEXTSEARCH_BM=m CONFIG_TEXTSEARCH_FSM=m +CONFIG_BTREE=y CONFIG_INTERVAL_TREE=y CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_HAS_IOMEM=y @@ -7908,7 +8000,7 @@ CONFIG_DMA_CMA=y # # Default contiguous memory area size: # -CONFIG_CMA_SIZE_MBYTES=16 +CONFIG_CMA_SIZE_MBYTES=128 CONFIG_CMA_SIZE_SEL_MBYTES=y # CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set # CONFIG_CMA_SIZE_SEL_MIN is not set @@ -7916,13 +8008,15 @@ CONFIG_CMA_SIZE_SEL_MBYTES=y CONFIG_CMA_ALIGNMENT=8 # CONFIG_DMA_API_DEBUG is not set CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y CONFIG_CPU_RMAP=y CONFIG_DQL=y CONFIG_GLOB=y # CONFIG_GLOB_SELFTEST is not set CONFIG_NLATTR=y +CONFIG_LRU_CACHE=m CONFIG_CLZ_TAB=y -# CONFIG_IRQ_POLL is not set +CONFIG_IRQ_POLL=y CONFIG_MPILIB=y CONFIG_LIBFDT=y CONFIG_OID_REGISTRY=y diff --git a/external/config/optional/families/rockchip-rk3588/_config/desktop/jammy/environments/xfce/config_base/packages b/external/config/optional/families/rockchip-rk3588/_config/desktop/jammy/environments/xfce/config_base/packages index dc03e0873bad..6a11e6b4b043 100644 --- a/external/config/optional/families/rockchip-rk3588/_config/desktop/jammy/environments/xfce/config_base/packages +++ b/external/config/optional/families/rockchip-rk3588/_config/desktop/jammy/environments/xfce/config_base/packages @@ -271,3 +271,4 @@ language-pack-zh-hans fcitx5-data fcitx5-config-qt xinput +gparted diff --git a/external/config/sources/arm64.conf b/external/config/sources/arm64.conf index aea90935b865..dd72d0feb1ba 100644 --- a/external/config/sources/arm64.conf +++ b/external/config/sources/arm64.conf @@ -22,20 +22,26 @@ if [[ $BOARD =~ orangepipch5|orangepioneh5 ]]; then QEMU_BINARY="qemu-arm-static" fi -[[ $ATF_COMPILE != "no" && -z $ATF_COMPILER ]] && ATF_COMPILER="aarch64-none-linux-gnu-" +if [ "$(uname -m)" = "aarch64" ]; then + [[ $ATF_COMPILE != "no" && -z $ATF_COMPILER ]] && ATF_COMPILER="aarch64-linux-gnu-" + [[ -z $UBOOT_COMPILER ]] && UBOOT_COMPILER="aarch64-linux-gnu-" + [[ -z $KERNEL_COMPILER ]] && KERNEL_COMPILER="aarch64-linux-gnu-" +else + [[ $ATF_COMPILE != "no" && -z $ATF_COMPILER ]] && ATF_COMPILER="aarch64-none-linux-gnu-" + [[ -z $UBOOT_COMPILER ]] && UBOOT_COMPILER="aarch64-none-linux-gnu-" + [[ -z $KERNEL_COMPILER ]] && KERNEL_COMPILER="aarch64-none-linux-gnu-" +fi + [[ $ATF_COMPILE != "no" && -z $ATFSOURCE ]] && ATFSOURCE='https://github.com/ARM-software/arm-trusted-firmware' -#[[ $ATF_COMPILE != "no" && ${DOWNLOAD_MIRROR} == china ]] && ATFSOURCE="${GIT_SERVER}/arm-trusted-firmware" [[ $ATF_COMPILE != "no" && -z $ATFDIR ]] && ATFDIR='arm-trusted-firmware-sunxi-mainline' [[ $ATF_COMPILE != "no" && -z $ATFBRANCH ]] && ATFBRANCH='branch:master' [[ $ATF_COMPILE != "no" && -z $ATF_USE_GCC ]] && ATF_USE_GCC='> 8.0' -[[ -z $UBOOT_COMPILER ]] && UBOOT_COMPILER="aarch64-none-linux-gnu-" [[ -z $UBOOT_USE_GCC ]] && UBOOT_USE_GCC='> 8.0' [[ -z $BOOTSOURCE ]] && BOOTSOURCE="${GIT_SERVER}/u-boot-orangepi.git" [[ -z $BOOTDIR ]] && BOOTDIR="${SRC}/u-boot" [[ -z $BOOTBRANCH ]] && BOOTBRANCH='branch:v2020.04' -[[ -z $KERNEL_COMPILER ]] && KERNEL_COMPILER="aarch64-none-linux-gnu-" [[ -z $KERNEL_USE_GCC ]] && KERNEL_USE_GCC='> 8.0' [[ -z $KERNELDIR ]] && KERNELDIR="${SRC}/kernel" [[ -z $KERNELSOURCE ]] && KERNELSOURCE="${GIT_SERVER}/linux-orangepi.git" diff --git a/external/config/sources/families/rockchip-rk3588.conf b/external/config/sources/families/rockchip-rk3588.conf index 83c003d6d3d3..d467ab336807 100644 --- a/external/config/sources/families/rockchip-rk3588.conf +++ b/external/config/sources/families/rockchip-rk3588.conf @@ -61,7 +61,7 @@ family_tweaks_s() { chroot "${SDCARD}" /bin/bash -c "ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime" chroot "${SDCARD}" /bin/bash -c "dpkg-reconfigure -f noninteractive tzdata" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1 - chroot $SDCARD /bin/bash -c "apt-get -y -qq install lm-sensors usb-modeswitch tree" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1 + chroot $SDCARD /bin/bash -c "apt-get -y -qq install lm-sensors usb-modeswitch tree dnsmasq swig python3-dev python3-setuptools" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1 install_wiringop install_docker diff --git a/external/packages/bsp/common/usr/share/initramfs-tools/conf-hooks.d/orangepi-plymouth b/external/packages/bsp/common/usr/share/initramfs-tools/conf-hooks.d/orangepi-plymouth new file mode 100644 index 000000000000..fae849593c38 --- /dev/null +++ b/external/packages/bsp/common/usr/share/initramfs-tools/conf-hooks.d/orangepi-plymouth @@ -0,0 +1,3 @@ +if which plymouth >/dev/null 2>&1; then + FRAMEBUFFER=y +fi diff --git a/external/packages/bsp/rk3588/usr/local/bin/create_ap b/external/packages/bsp/rk3588/usr/local/bin/create_ap new file mode 100755 index 000000000000..e5b7a88e9d27 --- /dev/null +++ b/external/packages/bsp/rk3588/usr/local/bin/create_ap @@ -0,0 +1,1919 @@ +#!/bin/bash + +# general dependencies: +# bash (to run this script) +# util-linux (for getopt) +# procps or procps-ng +# hostapd +# iproute2 +# iw +# iwconfig (you only need this if 'iw' can not recognize your adapter) +# haveged (optional) + +# dependencies for 'nat' or 'none' Internet sharing method +# dnsmasq +# iptables + +VERSION=0.4.6 +PROGNAME="$(basename $0)" + +# make sure that all command outputs are in english +# so we can parse them correctly +export LC_ALL=C + +# all new files and directories must be readable only by root. +# in special cases we must use chmod to give any other permissions. +SCRIPT_UMASK=0077 +umask $SCRIPT_UMASK + +usage() { + echo "Usage: "$PROGNAME" [options] [] [ []]" + echo + echo "Options:" + echo " -h, --help Show this help" + echo " --version Print version number" + echo " -c Channel number (default: 1)" + echo " -w Use 1 for WPA, use 2 for WPA2, use 1+2 for both (default: 1+2)" + echo " -n Disable Internet sharing (if you use this, don't pass" + echo " the argument)" + echo " -m Method for Internet sharing." + echo " Use: 'nat' for NAT (default)" + echo " 'bridge' for bridging" + echo " 'none' for no Internet sharing (equivalent to -n)" + echo " --psk Use 64 hex digits pre-shared-key instead of passphrase" + echo " --hidden Make the Access Point hidden (do not broadcast the SSID)" + echo " --mac-filter Enable MAC address filtering" + echo " --mac-filter-accept Location of MAC address filter list (defaults to /etc/hostapd/hostapd.accept)" + echo " --redirect-to-localhost If -n is set, redirect every web request to localhost (useful for public information networks)" + echo " --hostapd-debug With level between 1 and 2, passes arguments -d or -dd to hostapd for debugging." + echo " --isolate-clients Disable communication between clients" + echo " --ieee80211n Enable IEEE 802.11n (HT)" + echo " --ieee80211ac Enable IEEE 802.11ac (VHT)" + echo " --ht_capab HT capabilities (default: [HT40+])" + echo " --vht_capab VHT capabilities" + echo " --country Set two-letter country code for regularity (example: US)" + echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" + echo " --driver Choose your WiFi adapter driver (default: nl80211)" + echo " --no-virt Do not create virtual interface" + echo " --no-haveged Do not run 'haveged' automatically when needed" + echo " --fix-unmanaged If NetworkManager shows your interface as unmanaged after you" + echo " close create_ap, then use this option to switch your interface" + echo " back to managed" + echo " --mac Set MAC address" + echo " --dhcp-dns Set DNS returned by DHCP" + echo " --daemon Run create_ap in the background" + echo " --pidfile Save daemon PID to file" + echo " --logfile Save daemon messages to file" + echo " --stop Send stop command to an already running create_ap. For an " + echo " you can put the PID of create_ap or the WiFi interface. You can" + echo " get them with --list-running" + echo " --list-running Show the create_ap processes that are already running" + echo " --list-clients List the clients connected to create_ap instance associated with ." + echo " For an you can put the PID of create_ap or the WiFi interface." + echo " If virtual WiFi interface was created, then use that one." + echo " You can get them with --list-running" + echo " --mkconfig Store configs in conf_file" + echo " --config Load configs from conf_file" + echo + echo "Non-Bridging Options:" + echo " --no-dns Disable dnsmasq DNS server" + echo " --no-dnsmasq Disable dnsmasq server completely" + echo " -g IPv4 Gateway for the Access Point (default: 192.168.12.1)" + echo " -d DNS server will take into account /etc/hosts" + echo " -e DNS server will take into account additional hosts file" + echo + echo "Useful informations:" + echo " * If you're not using the --no-virt option, then you can create an AP with the same" + echo " interface you are getting your Internet connection." + echo " * You can pass your SSID and password through pipe or through arguments (see examples)." + echo " * On bridge method if the is not a bridge interface, then" + echo " a bridge interface is created automatically." + echo + echo "Examples:" + echo " "$PROGNAME" wlan0 eth0 MyAccessPoint MyPassPhrase" + echo " echo -e 'MyAccessPoint\nMyPassPhrase' | "$PROGNAME" wlan0 eth0" + echo " "$PROGNAME" wlan0 eth0 MyAccessPoint" + echo " echo 'MyAccessPoint' | "$PROGNAME" wlan0 eth0" + echo " "$PROGNAME" wlan0 wlan0 MyAccessPoint MyPassPhrase" + echo " "$PROGNAME" -n wlan0 MyAccessPoint MyPassPhrase" + echo " "$PROGNAME" -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase" + echo " "$PROGNAME" -m bridge wlan0 br0 MyAccessPoint MyPassPhrase" + echo " "$PROGNAME" --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase" + echo " "$PROGNAME" --daemon wlan0 eth0 MyAccessPoint MyPassPhrase" + echo " "$PROGNAME" --stop wlan0" +} + +# Busybox polyfills +if cp --help 2>&1 | grep -q -- --no-clobber; then + cp_n() { + cp -n "$@" + } +else + cp_n() { + yes n | cp -i "$@" + } +fi + +# on success it echos a non-zero unused FD +# on error it echos 0 +get_avail_fd() { + local x + for x in $(seq 1 $(ulimit -n)); do + if [[ ! -a "/proc/$BASHPID/fd/$x" ]]; then + echo $x + return + fi + done + echo 0 +} + +# lock file for the mutex counter +COUNTER_LOCK_FILE=/tmp/create_ap.$$.lock + +cleanup_lock() { + rm -f $COUNTER_LOCK_FILE +} + +init_lock() { + local LOCK_FILE=/tmp/create_ap.all.lock + + # we initialize only once + [[ $LOCK_FD -ne 0 ]] && return 0 + + LOCK_FD=$(get_avail_fd) + [[ $LOCK_FD -eq 0 ]] && return 1 + + # open/create lock file with write access for all users + # otherwise normal users will not be able to use it. + # to avoid race conditions on creation, we need to + # use umask to set the permissions. + umask 0555 + eval "exec $LOCK_FD>$LOCK_FILE" > /dev/null 2>&1 || return 1 + umask $SCRIPT_UMASK + + # there is a case where lock file was created from a normal + # user. change the owner to root as soon as we can. + [[ $(id -u) -eq 0 ]] && chown 0:0 $LOCK_FILE + + # create mutex counter lock file + echo 0 > $COUNTER_LOCK_FILE + + return $? +} + +# recursive mutex lock for all create_ap processes +mutex_lock() { + local counter_mutex_fd + local counter + + # lock local mutex and read counter + counter_mutex_fd=$(get_avail_fd) + if [[ $counter_mutex_fd -ne 0 ]]; then + eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE" + flock $counter_mutex_fd + read -u $counter_mutex_fd counter + else + echo "Failed to lock mutex counter" >&2 + return 1 + fi + + # lock global mutex and increase counter + [[ $counter -eq 0 ]] && flock $LOCK_FD + counter=$(( $counter + 1 )) + + # write counter and unlock local mutex + echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd + eval "exec ${counter_mutex_fd}<&-" + return 0 +} + +# recursive mutex unlock for all create_ap processes +mutex_unlock() { + local counter_mutex_fd + local counter + + # lock local mutex and read counter + counter_mutex_fd=$(get_avail_fd) + if [[ $counter_mutex_fd -ne 0 ]]; then + eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE" + flock $counter_mutex_fd + read -u $counter_mutex_fd counter + else + echo "Failed to lock mutex counter" >&2 + return 1 + fi + + # decrease counter and unlock global mutex + if [[ $counter -gt 0 ]]; then + counter=$(( $counter - 1 )) + [[ $counter -eq 0 ]] && flock -u $LOCK_FD + fi + + # write counter and unlock local mutex + echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd + eval "exec ${counter_mutex_fd}<&-" + return 0 +} + +# it takes 2 arguments +# returns: +# 0 if v1 (1st argument) and v2 (2nd argument) are the same +# 1 if v1 is less than v2 +# 2 if v1 is greater than v2 +version_cmp() { + local V1 V2 VN x + [[ ! $1 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!" + [[ ! $2 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!" + + V1=( $(echo $1 | tr '.' ' ') ) + V2=( $(echo $2 | tr '.' ' ') ) + VN=${#V1[@]} + [[ $VN -lt ${#V2[@]} ]] && VN=${#V2[@]} + + for ((x = 0; x < $VN; x++)); do + [[ ${V1[x]} -lt ${V2[x]} ]] && return 1 + [[ ${V1[x]} -gt ${V2[x]} ]] && return 2 + done + + return 0 +} + +USE_IWCONFIG=0 + +is_interface() { + [[ -z "$1" ]] && return 1 + [[ -d "/sys/class/net/${1}" ]] +} + +is_wifi_interface() { + which iw > /dev/null 2>&1 && iw dev $1 info > /dev/null 2>&1 && return 0 + if which iwconfig > /dev/null 2>&1 && iwconfig $1 > /dev/null 2>&1; then + USE_IWCONFIG=1 + return 0 + fi + return 1 +} + +is_bridge_interface() { + [[ -z "$1" ]] && return 1 + [[ -d "/sys/class/net/${1}/bridge" ]] +} + +get_phy_device() { + local x + for x in /sys/class/ieee80211/*; do + [[ ! -e "$x" ]] && continue + if [[ "${x##*/}" = "$1" ]]; then + echo $1 + return 0 + elif [[ -e "$x/device/net/$1" ]]; then + echo ${x##*/} + return 0 + elif [[ -e "$x/device/net:$1" ]]; then + echo ${x##*/} + return 0 + else + if [[ -e "/sys/class/net/$1" ]]; then + phy=$(readlink -f /sys/class/net/$1/phy80211) + phy1=$(readlink -f $x) + if [[ $phy == $phy1 ]]; then + echo ${x##*/} + return 0 + fi + fi + fi + done + echo "Failed to get phy interface" >&2 + return 1 +} + +get_adapter_info() { + local PHY + PHY=$(get_phy_device "$1") + [[ $? -ne 0 ]] && return 1 + iw phy $PHY info +} + +get_adapter_kernel_module() { + local MODULE + MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module") + echo ${MODULE##*/} +} + +can_be_sta_and_ap() { + # iwconfig does not provide this information, assume false + [[ $USE_IWCONFIG -eq 1 ]] && return 1 + if [[ "$(get_adapter_kernel_module "$1")" == "brcmfmac" ]]; then + echo "WARN: brmfmac driver doesn't work properly with virtual interfaces and" >&2 + echo " it can cause kernel panic. For this reason we disallow virtual" >&2 + echo " interfaces for your adapter." >&2 + echo " For more info: https://github.com/oblique/create_ap/issues/203" >&2 + return 1 + fi + get_adapter_info "$1" | grep -E '{.* managed.* AP.*}' > /dev/null 2>&1 && return 0 + get_adapter_info "$1" | grep -E '{.* AP.* managed.*}' > /dev/null 2>&1 && return 0 + return 1 +} + +can_be_ap() { + # iwconfig does not provide this information, assume true + [[ $USE_IWCONFIG -eq 1 ]] && return 0 + get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 && return 0 + return 1 +} + +can_transmit_to_channel() { + local IFACE CHANNEL_NUM CHANNEL_INFO + IFACE=$1 + CHANNEL_NUM=$2 + + if [[ $USE_IWCONFIG -eq 0 ]]; then + if [[ $FREQ_BAND == 2.4 ]]; then + CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9] MHz \[${CHANNEL_NUM}\]") + else + CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\) MHz \[${CHANNEL_NUM}\]") + fi + [[ -z "${CHANNEL_INFO}" ]] && return 1 + [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1 + [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1 + return 0 + else + CHANNEL_NUM=$(printf '%02d' ${CHANNEL_NUM}) + CHANNEL_INFO=$(iwlist ${IFACE} channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:") + [[ -z "${CHANNEL_INFO}" ]] && return 1 + return 0 + fi +} + +# taken from iw/util.c +ieee80211_frequency_to_channel() { + local FREQ=$1 + if [[ $FREQ -eq 2484 ]]; then + echo 14 + elif [[ $FREQ -lt 2484 ]]; then + echo $(( ($FREQ - 2407) / 5 )) + elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then + echo $(( ($FREQ - 4000) / 5 )) + elif [[ $FREQ -le 45000 ]]; then + echo $(( ($FREQ - 5000) / 5 )) + elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then + echo $(( ($FREQ - 56160) / 2160 )) + else + echo 0 + fi +} + +is_5ghz_frequency() { + [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]] +} + +is_wifi_connected() { + if [[ $USE_IWCONFIG -eq 0 ]]; then + iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 && return 0 + else + iwconfig "$1" 2>&1 | grep -E 'Access Point: [0-9a-fA-F]{2}:' > /dev/null 2>&1 && return 0 + fi + return 1 +} + +is_macaddr() { + echo "$1" | grep -E "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$" > /dev/null 2>&1 +} + +is_unicast_macaddr() { + local x + is_macaddr "$1" || return 1 + x=$(echo "$1" | cut -d: -f1) + x=$(printf '%d' "0x${x}") + [[ $(expr $x % 2) -eq 0 ]] +} + +get_macaddr() { + is_interface "$1" || return + cat "/sys/class/net/${1}/address" +} + +get_mtu() { + is_interface "$1" || return + cat "/sys/class/net/${1}/mtu" +} + +alloc_new_iface() { + local prefix=$1 + local i=0 + + mutex_lock + while :; do + if ! is_interface $prefix$i && [[ ! -f $COMMON_CONFDIR/ifaces/$prefix$i ]]; then + mkdir -p $COMMON_CONFDIR/ifaces + touch $COMMON_CONFDIR/ifaces/$prefix$i + echo $prefix$i + mutex_unlock + return + fi + i=$((i + 1)) + done + mutex_unlock +} + +dealloc_iface() { + rm -f $COMMON_CONFDIR/ifaces/$1 +} + +get_all_macaddrs() { + cat /sys/class/net/*/address +} + +get_new_macaddr() { + local OLDMAC NEWMAC LAST_BYTE i + OLDMAC=$(get_macaddr "$1") + LAST_BYTE=$(printf %d 0x${OLDMAC##*:}) + mutex_lock + for i in {1..255}; do + NEWMAC="${OLDMAC%:*}:$(printf %02x $(( ($LAST_BYTE + $i) % 256 )))" + (get_all_macaddrs | grep "$NEWMAC" > /dev/null 2>&1) || break + done + mutex_unlock + echo $NEWMAC +} + +# start haveged when needed +haveged_watchdog() { + local show_warn=1 + while :; do + mutex_lock + if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then + if ! which haveged > /dev/null 2>&1; then + if [[ $show_warn -eq 1 ]]; then + echo "WARN: Low entropy detected. We recommend you to install \`haveged'" + show_warn=0 + fi + elif ! pidof haveged > /dev/null 2>&1; then + echo "Low entropy detected, starting haveged" + # boost low-entropy + haveged -w 1024 -p $COMMON_CONFDIR/haveged.pid + fi + fi + mutex_unlock + sleep 2 + done +} + +NETWORKMANAGER_CONF=/etc/NetworkManager/NetworkManager.conf +NM_OLDER_VERSION=1 + +networkmanager_exists() { + local NM_VER + which nmcli > /dev/null 2>&1 || return 1 + NM_VER=$(nmcli -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+') + version_cmp $NM_VER 0.9.9 + if [[ $? -eq 1 ]]; then + NM_OLDER_VERSION=1 + else + NM_OLDER_VERSION=0 + fi + return 0 +} + +networkmanager_is_running() { + local NMCLI_OUT + networkmanager_exists || return 1 + if [[ $NM_OLDER_VERSION -eq 1 ]]; then + NMCLI_OUT=$(nmcli -t -f RUNNING nm 2>&1 | grep -E '^running$') + else + NMCLI_OUT=$(nmcli -t -f RUNNING g 2>&1 | grep -E '^running$') + fi + [[ -n "$NMCLI_OUT" ]] +} + +networkmanager_knows_iface() { + # check if the interface $1 is known to NetworkManager + # an interface may exist but may not be known to NetworkManager if it is in a different network namespace than NetworkManager + nmcli -t -f DEVICE d 2>&1 | grep -Fxq "$1" +} + +networkmanager_iface_is_unmanaged() { + is_interface "$1" || return 2 + networkmanager_knows_iface "$1" || return 0 + (nmcli -t -f DEVICE,STATE d 2>&1 | grep -E "^$1:unmanaged$" > /dev/null 2>&1) || return 1 +} + +ADDED_UNMANAGED= + +networkmanager_add_unmanaged() { + local MAC UNMANAGED WAS_EMPTY x + networkmanager_exists || return 1 + + [[ -d ${NETWORKMANAGER_CONF%/*} ]] || mkdir -p ${NETWORKMANAGER_CONF%/*} + [[ -f ${NETWORKMANAGER_CONF} ]] || touch ${NETWORKMANAGER_CONF} + + if [[ $NM_OLDER_VERSION -eq 1 ]]; then + if [[ -z "$2" ]]; then + MAC=$(get_macaddr "$1") + else + MAC="$2" + fi + [[ -z "$MAC" ]] && return 1 + fi + + mutex_lock + UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf) + + WAS_EMPTY=0 + [[ -z "$UNMANAGED" ]] && WAS_EMPTY=1 + UNMANAGED=$(echo "$UNMANAGED" | sed 's/unmanaged-devices=//' | tr ';,' ' ') + + # if it exists, do nothing + for x in $UNMANAGED; do + if [[ $x == "mac:${MAC}" ]] || + [[ $NM_OLDER_VERSION -eq 0 && $x == "interface-name:${1}" ]]; then + mutex_unlock + return 2 + fi + done + + if [[ $NM_OLDER_VERSION -eq 1 ]]; then + UNMANAGED="${UNMANAGED} mac:${MAC}" + else + UNMANAGED="${UNMANAGED} interface-name:${1}" + fi + + UNMANAGED=$(echo $UNMANAGED | sed -e 's/^ //') + UNMANAGED="${UNMANAGED// /;}" + UNMANAGED="unmanaged-devices=${UNMANAGED}" + + if ! grep -E '^\[keyfile\]' ${NETWORKMANAGER_CONF} > /dev/null 2>&1; then + echo -e "\n\n[keyfile]\n${UNMANAGED}" >> ${NETWORKMANAGER_CONF} + elif [[ $WAS_EMPTY -eq 1 ]]; then + sed -e "s/^\(\[keyfile\].*\)$/\1\n${UNMANAGED}/" -i ${NETWORKMANAGER_CONF} + else + sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF} + fi + + ADDED_UNMANAGED="${ADDED_UNMANAGED} ${1} " + mutex_unlock + + local nm_pid=$(pidof NetworkManager) + [[ -n "$nm_pid" ]] && kill -HUP $nm_pid + + return 0 +} + +networkmanager_rm_unmanaged() { + local MAC UNMANAGED + networkmanager_exists || return 1 + [[ ! -f ${NETWORKMANAGER_CONF} ]] && return 1 + + if [[ $NM_OLDER_VERSION -eq 1 ]]; then + if [[ -z "$2" ]]; then + MAC=$(get_macaddr "$1") + else + MAC="$2" + fi + [[ -z "$MAC" ]] && return 1 + fi + + mutex_lock + UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf | sed 's/unmanaged-devices=//' | tr ';,' ' ') + + if [[ -z "$UNMANAGED" ]]; then + mutex_unlock + return 1 + fi + + [[ -n "$MAC" ]] && UNMANAGED=$(echo $UNMANAGED | sed -e "s/mac:${MAC}\( \|$\)//g") + UNMANAGED=$(echo $UNMANAGED | sed -e "s/interface-name:${1}\( \|$\)//g") + UNMANAGED=$(echo $UNMANAGED | sed -e 's/ $//') + + if [[ -z "$UNMANAGED" ]]; then + sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF} + else + UNMANAGED="${UNMANAGED// /;}" + UNMANAGED="unmanaged-devices=${UNMANAGED}" + sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF} + fi + + ADDED_UNMANAGED="${ADDED_UNMANAGED/ ${1} /}" + mutex_unlock + + local nm_pid=$(pidof NetworkManager) + [[ -n "$nm_pid" ]] && kill -HUP $nm_pid + + return 0 +} + +networkmanager_fix_unmanaged() { + [[ -f ${NETWORKMANAGER_CONF} ]] || return + + mutex_lock + sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF} + mutex_unlock + + local nm_pid=$(pidof NetworkManager) + [[ -n "$nm_pid" ]] && kill -HUP $nm_pid +} + +networkmanager_rm_unmanaged_if_needed() { + [[ $ADDED_UNMANAGED =~ .*\ ${1}\ .* ]] && networkmanager_rm_unmanaged $1 $2 +} + +networkmanager_wait_until_unmanaged() { + local RES + networkmanager_is_running || return 1 + while :; do + networkmanager_iface_is_unmanaged "$1" + RES=$? + [[ $RES -eq 0 ]] && break + [[ $RES -eq 2 ]] && die "Interface '${1}' does not exist. + It's probably renamed by a udev rule." + sleep 1 + done + sleep 2 + return 0 +} + + +CHANNEL=default +GATEWAY=192.168.12.1 +WPA_VERSION=1+2 +ETC_HOSTS=0 +ADDN_HOSTS= +DHCP_DNS=gateway +NO_DNS=0 +NO_DNSMASQ=0 +DNS_PORT= +HIDDEN=0 +MAC_FILTER=0 +MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept +ISOLATE_CLIENTS=0 +SHARE_METHOD=nat +IEEE80211N=0 +IEEE80211AC=0 +HT_CAPAB='[HT40+]' +VHT_CAPAB= +DRIVER=nl80211 +NO_VIRT=0 +COUNTRY= +FREQ_BAND=2.4 +NEW_MACADDR= +DAEMONIZE=0 +DAEMON_PIDFILE= +DAEMON_LOGFILE=/dev/null +NO_HAVEGED=0 +USE_PSK=0 + +HOSTAPD_DEBUG_ARGS= +REDIRECT_TO_LOCALHOST=0 + +CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS + SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND + NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE + SSID PASSPHRASE USE_PSK) + +FIX_UNMANAGED=0 +LIST_RUNNING=0 +STOP_ID= +LIST_CLIENTS_ID= + +STORE_CONFIG= +LOAD_CONFIG= + +CONFDIR= +WIFI_IFACE= +VWIFI_IFACE= +INTERNET_IFACE= +BRIDGE_IFACE= +OLD_MACADDR= +IP_ADDRS= +ROUTE_ADDRS= + +HAVEGED_WATCHDOG_PID= + +_cleanup() { + local PID x + + trap "" SIGINT SIGUSR1 SIGUSR2 EXIT + mutex_lock + disown -a + + # kill haveged_watchdog + [[ -n "$HAVEGED_WATCHDOG_PID" ]] && kill $HAVEGED_WATCHDOG_PID + + # kill processes + for x in $CONFDIR/*.pid; do + # even if the $CONFDIR is empty, the for loop will assign + # a value in $x. so we need to check if the value is a file + [[ -f $x ]] && kill -9 $(cat $x) + done + + rm -rf $CONFDIR + + local found=0 + for x in $(list_running_conf); do + if [[ -f $x/nat_internet_iface && $(cat $x/nat_internet_iface) == $INTERNET_IFACE ]]; then + found=1 + break + fi + done + + if [[ $found -eq 0 ]]; then + cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding \ + /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding + rm -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding + fi + + # if we are the last create_ap instance then set back the common values + if ! has_running_instance; then + # kill common processes + for x in $COMMON_CONFDIR/*.pid; do + [[ -f $x ]] && kill -9 $(cat $x) + done + + # set old ip_forward + if [[ -f $COMMON_CONFDIR/ip_forward ]]; then + cp -f $COMMON_CONFDIR/ip_forward /proc/sys/net/ipv4 + rm -f $COMMON_CONFDIR/ip_forward + fi + + # set old bridge-nf-call-iptables + if [[ -f $COMMON_CONFDIR/bridge-nf-call-iptables ]]; then + if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then + cp -f $COMMON_CONFDIR/bridge-nf-call-iptables /proc/sys/net/bridge + fi + rm -f $COMMON_CONFDIR/bridge-nf-call-iptables + fi + + rm -rf $COMMON_CONFDIR + fi + + if [[ "$SHARE_METHOD" != "none" ]]; then + if [[ "$SHARE_METHOD" == "nat" ]]; then + iptables -w -t nat -D POSTROUTING -s ${GATEWAY%.*}.0/24 ! -o ${WIFI_IFACE} -j MASQUERADE + iptables -w -D FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT + iptables -w -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT + elif [[ "$SHARE_METHOD" == "bridge" ]]; then + if ! is_bridge_interface $INTERNET_IFACE; then + ip link set dev $BRIDGE_IFACE down + ip link set dev $INTERNET_IFACE down + ip link set dev $INTERNET_IFACE promisc off + ip link set dev $INTERNET_IFACE nomaster + ip link delete $BRIDGE_IFACE type bridge + ip addr flush $INTERNET_IFACE + ip link set dev $INTERNET_IFACE up + dealloc_iface $BRIDGE_IFACE + + for x in "${IP_ADDRS[@]}"; do + x="${x/inet/}" + x="${x/secondary/}" + x="${x/dynamic/}" + x=$(echo $x | sed 's/\([0-9]\)sec/\1/g') + x="${x/${INTERNET_IFACE}/}" + ip addr add $x dev $INTERNET_IFACE + done + + ip route flush dev $INTERNET_IFACE + + for x in "${ROUTE_ADDRS[@]}"; do + [[ -z "$x" ]] && continue + [[ "$x" == default* ]] && continue + ip route add $x dev $INTERNET_IFACE + done + + for x in "${ROUTE_ADDRS[@]}"; do + [[ -z "$x" ]] && continue + [[ "$x" != default* ]] && continue + ip route add $x dev $INTERNET_IFACE + done + + networkmanager_rm_unmanaged_if_needed $INTERNET_IFACE + fi + fi + fi + + if [[ "$SHARE_METHOD" != "bridge" ]]; then + if [[ $NO_DNS -eq 0 ]]; then + iptables -w -D INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT + iptables -w -D INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT + iptables -w -t nat -D PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \ + -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT + iptables -w -t nat -D PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \ + -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT + fi + iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT + fi + + if [[ $NO_VIRT -eq 0 ]]; then + if [[ -n "$VWIFI_IFACE" ]]; then + ip link set down dev ${VWIFI_IFACE} + ip addr flush ${VWIFI_IFACE} + networkmanager_rm_unmanaged_if_needed ${VWIFI_IFACE} ${OLD_MACADDR} + iw dev ${VWIFI_IFACE} del + dealloc_iface $VWIFI_IFACE + fi + else + ip link set down dev ${WIFI_IFACE} + ip addr flush ${WIFI_IFACE} + if [[ -n "$NEW_MACADDR" ]]; then + ip link set dev ${WIFI_IFACE} address ${OLD_MACADDR} + fi + networkmanager_rm_unmanaged_if_needed ${WIFI_IFACE} ${OLD_MACADDR} + fi + + mutex_unlock + cleanup_lock + + if [[ $RUNNING_AS_DAEMON -eq 1 && -n "$DAEMON_PIDFILE" && -f "$DAEMON_PIDFILE" ]]; then + rm $DAEMON_PIDFILE + fi +} + +cleanup() { + echo + echo -n "Doing cleanup.. " + _cleanup > /dev/null 2>&1 + echo "done" +} + +die() { + [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2 + # send die signal to the main process + [[ $BASHPID -ne $$ ]] && kill -USR2 $$ + # we don't need to call cleanup because it's traped on EXIT + exit 1 +} + +clean_exit() { + # send clean_exit signal to the main process + [[ $BASHPID -ne $$ ]] && kill -USR1 $$ + # we don't need to call cleanup because it's traped on EXIT + exit 0 +} + +list_running_conf() { + local x + mutex_lock + for x in /tmp/create_ap.*; do + if [[ -f $x/pid && -f $x/wifi_iface && -d /proc/$(cat $x/pid) ]]; then + echo $x + fi + done + mutex_unlock +} + +list_running() { + local IFACE wifi_iface x + mutex_lock + for x in $(list_running_conf); do + IFACE=${x#*.} + IFACE=${IFACE%%.*} + wifi_iface=$(cat $x/wifi_iface) + + if [[ $IFACE == $wifi_iface ]]; then + echo $(cat $x/pid) $IFACE + else + echo $(cat $x/pid) $IFACE '('$(cat $x/wifi_iface)')' + fi + done + mutex_unlock +} + +get_wifi_iface_from_pid() { + list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E "^${1} " | cut -d' ' -f2 +} + +get_pid_from_wifi_iface() { + list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E " ${1}$" | cut -d' ' -f1 +} + +get_confdir_from_pid() { + local IFACE x + mutex_lock + for x in $(list_running_conf); do + if [[ $(cat $x/pid) == "$1" ]]; then + echo $x + break + fi + done + mutex_unlock +} + +print_client() { + local line ipaddr hostname + local mac="$1" + + if [[ -f $CONFDIR/dnsmasq.leases ]]; then + line=$(grep " $mac " $CONFDIR/dnsmasq.leases | tail -n 1) + ipaddr=$(echo $line | cut -d' ' -f3) + hostname=$(echo "$line" | cut -d' ' -f4) + fi + + [[ -z "$ipaddr" ]] && ipaddr="*" + [[ -z "$hostname" ]] && hostname="*" + + printf "%-20s %-18s %s\n" "$mac" "$ipaddr" "$hostname" +} + +list_clients() { + local wifi_iface pid + + # If PID is given, get the associated wifi iface + if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then + pid="$1" + wifi_iface=$(get_wifi_iface_from_pid "$pid") + [[ -z "$wifi_iface" ]] && die "'$pid' is not the pid of a running $PROGNAME instance." + fi + + [[ -z "$wifi_iface" ]] && wifi_iface="$1" + is_wifi_interface "$wifi_iface" || die "'$wifi_iface' is not a WiFi interface." + + [[ -z "$pid" ]] && pid=$(get_pid_from_wifi_iface "$wifi_iface") + [[ -z "$pid" ]] && die "'$wifi_iface' is not used from $PROGNAME instance.\n\ + Maybe you need to pass the virtual interface instead.\n\ + Use --list-running to find it out." + [[ -z "$CONFDIR" ]] && CONFDIR=$(get_confdir_from_pid "$pid") + + if [[ $USE_IWCONFIG -eq 0 ]]; then + local awk_cmd='($1 ~ /Station$/) {print $2}' + local client_list=$(iw dev "$wifi_iface" station dump | awk "$awk_cmd") + + if [[ -z "$client_list" ]]; then + echo "No clients connected" + return + fi + + printf "%-20s %-18s %s\n" "MAC" "IP" "Hostname" + + local mac + for mac in $client_list; do + print_client $mac + done + else + die "This option is not supported for the current driver." + fi +} + +has_running_instance() { + local PID x + + mutex_lock + for x in /tmp/create_ap.*; do + if [[ -f $x/pid ]]; then + PID=$(cat $x/pid) + if [[ -d /proc/$PID ]]; then + mutex_unlock + return 0 + fi + fi + done + mutex_lock + + return 1 +} + +is_running_pid() { + list_running | grep -E "^${1} " > /dev/null 2>&1 +} + +send_stop() { + local x + + mutex_lock + # send stop signal to specific pid + if is_running_pid $1; then + kill -USR1 $1 + mutex_unlock + return + fi + + # send stop signal to specific interface + for x in $(list_running | grep -E " \(?${1}( |\)?\$)" | cut -f1 -d' '); do + kill -USR1 $x + done + mutex_unlock +} + +# Storing configs +write_config() { + local i=1 + + if ! eval 'echo -n > "$STORE_CONFIG"' > /dev/null 2>&1; then + echo "ERROR: Unable to create config file $STORE_CONFIG" >&2 + exit 1 + fi + + WIFI_IFACE=$1 + if [[ "$SHARE_METHOD" == "none" ]]; then + SSID="$2" + PASSPHRASE="$3" + else + INTERNET_IFACE="$2" + SSID="$3" + PASSPHRASE="$4" + fi + + for config_opt in "${CONFIG_OPTS[@]}"; do + eval echo $config_opt=\$$config_opt + done >> "$STORE_CONFIG" + + echo -e "Config options written to '$STORE_CONFIG'" + exit 0 +} + +is_config_opt() { + local elem opt="$1" + + for elem in "${CONFIG_OPTS[@]}"; do + if [[ "$elem" == "$opt" ]]; then + return 0 + fi + done + return 1 +} + +# Load options from config file +read_config() { + local opt_name opt_val line + + while read line; do + # Read switches and their values + opt_name="${line%%=*}" + opt_val="${line#*=}" + if is_config_opt "$opt_name" ; then + eval $opt_name="\$opt_val" + else + echo "WARN: Unrecognized configuration entry $opt_name" >&2 + fi + done < "$LOAD_CONFIG" +} + + +ARGS=( "$@" ) + +# Preprocessing for --config before option-parsing starts +for ((i=0; i<$#; i++)); do + if [[ "${ARGS[i]}" = "--config" ]]; then + if [[ -f "${ARGS[i+1]}" ]]; then + LOAD_CONFIG="${ARGS[i+1]}" + read_config + else + echo "ERROR: No config file found at given location" >&2 + exit 1 + fi + break + fi +done + +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","mkconfig:","config:" -n "$PROGNAME" -- "$@") +[[ $? -ne 0 ]] && exit 1 +eval set -- "$GETOPT_ARGS" + +while :; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + --version) + echo $VERSION + exit 0 + ;; + --hidden) + shift + HIDDEN=1 + ;; + --mac-filter) + shift + MAC_FILTER=1 + ;; + --mac-filter-accept) + shift + MAC_FILTER_ACCEPT="$1" + shift + ;; + --isolate-clients) + shift + ISOLATE_CLIENTS=1 + ;; + -c) + shift + CHANNEL="$1" + shift + ;; + -w) + shift + WPA_VERSION="$1" + [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2 + shift + ;; + -g) + shift + GATEWAY="$1" + shift + ;; + -d) + shift + ETC_HOSTS=1 + ;; + -e) + shift + ADDN_HOSTS="$1" + shift + ;; + -n) + shift + SHARE_METHOD=none + ;; + -m) + shift + SHARE_METHOD="$1" + shift + ;; + --ieee80211n) + shift + IEEE80211N=1 + ;; + --ieee80211ac) + shift + IEEE80211AC=1 + ;; + --ht_capab) + shift + HT_CAPAB="$1" + shift + ;; + --vht_capab) + shift + VHT_CAPAB="$1" + shift + ;; + --driver) + shift + DRIVER="$1" + shift + ;; + --no-virt) + shift + NO_VIRT=1 + ;; + --fix-unmanaged) + shift + FIX_UNMANAGED=1 + ;; + --country) + shift + COUNTRY="$1" + shift + ;; + --freq-band) + shift + FREQ_BAND="$1" + shift + ;; + --mac) + shift + NEW_MACADDR="$1" + shift + ;; + --dhcp-dns) + shift + DHCP_DNS="$1" + shift + ;; + --daemon) + shift + DAEMONIZE=1 + ;; + --pidfile) + shift + DAEMON_PIDFILE="$1" + shift + ;; + --logfile) + shift + DAEMON_LOGFILE="$1" + shift + ;; + --stop) + shift + STOP_ID="$1" + shift + ;; + --list) + shift + LIST_RUNNING=1 + echo -e "WARN: --list is deprecated, use --list-running instead.\n" >&2 + ;; + --list-running) + shift + LIST_RUNNING=1 + ;; + --list-clients) + shift + LIST_CLIENTS_ID="$1" + shift + ;; + --no-haveged) + shift + NO_HAVEGED=1 + ;; + --psk) + shift + USE_PSK=1 + ;; + --no-dns) + shift + NO_DNS=1 + ;; + --no-dnsmasq) + shift + NO_DNSMASQ=1 + ;; + --redirect-to-localhost) + shift + REDIRECT_TO_LOCALHOST=1 + ;; + --hostapd-debug) + shift + if [ "x$1" = "x1" ]; then + HOSTAPD_DEBUG_ARGS="-d" + elif [ "x$1" = "x2" ]; then + HOSTAPD_DEBUG_ARGS="-dd" + else + printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1" + exit 1 + fi + shift + ;; + --mkconfig) + shift + STORE_CONFIG="$1" + shift + ;; + --config) + shift + shift + ;; + --) + shift + break + ;; + esac +done + +# Load positional args from config file, if needed +if [[ -n "$LOAD_CONFIG" && $# -eq 0 ]]; then + i=0 + # set arguments in order + for x in WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE; do + if eval "[[ -n \"\$${x}\" ]]"; then + eval "set -- \"\${@:1:$i}\" \"\$${x}\"" + ((i++)) + fi + # we unset the variable to avoid any problems later + eval "unset $x" + done +fi + +# Check if required number of positional args are present +if [[ $# -lt 1 && $FIX_UNMANAGED -eq 0 && -z "$STOP_ID" && + $LIST_RUNNING -eq 0 && -z "$LIST_CLIENTS_ID" ]]; then + usage >&2 + exit 1 +fi + +# Set NO_DNS, if dnsmasq is disabled +if [[ $NO_DNSMASQ -eq 1 ]]; then + NO_DNS=1 +fi + +trap "cleanup_lock" EXIT + +if ! init_lock; then + echo "ERROR: Failed to initialize lock" >&2 + exit 1 +fi + +# if the user press ctrl+c or we get USR1 signal +# then run clean_exit() +trap "clean_exit" SIGINT SIGUSR1 +# if we get USR2 signal then run die(). +trap "die" SIGUSR2 + +[[ -n "$STORE_CONFIG" ]] && write_config "$@" + +if [[ $LIST_RUNNING -eq 1 ]]; then + echo -e "List of running $PROGNAME instances:\n" + list_running + exit 0 +fi + +if [[ -n "$LIST_CLIENTS_ID" ]]; then + list_clients "$LIST_CLIENTS_ID" + exit 0 +fi + +if [[ $(id -u) -ne 0 ]]; then + echo "You must run it as root." >&2 + exit 1 +fi + +if [[ -n "$STOP_ID" ]]; then + echo "Trying to kill $PROGNAME instance associated with $STOP_ID..." + send_stop "$STOP_ID" + exit 0 +fi + +if [[ $FIX_UNMANAGED -eq 1 ]]; then + echo "Trying to fix unmanaged status in NetworkManager..." + networkmanager_fix_unmanaged + exit 0 +fi + +if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then + # Assume we're running underneath a service manager if PIDFILE is set + # and don't clobber it's output with a useless message + if [ -z "$DAEMON_PIDFILE" ]; then + echo "Running as Daemon..." + fi + # run a detached create_ap + RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" >>$DAEMON_LOGFILE 2>&1 & + exit 0 +elif [[ $RUNNING_AS_DAEMON -eq 1 && -n "$DAEMON_PIDFILE" ]]; then + echo $$ >$DAEMON_PIDFILE +fi + +if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then + echo "ERROR: Invalid frequency band" >&2 + exit 1 +fi + +if [[ $CHANNEL == default ]]; then + if [[ $FREQ_BAND == 2.4 ]]; then + CHANNEL=1 + else + CHANNEL=36 + fi +fi + +if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then + echo "Channel number is greater than 14, assuming 5GHz frequency band" + FREQ_BAND=5 +fi + +WIFI_IFACE=$1 + +if ! is_wifi_interface ${WIFI_IFACE}; then + echo "ERROR: '${WIFI_IFACE}' is not a WiFi interface" >&2 + exit 1 +fi + +if ! can_be_ap ${WIFI_IFACE}; then + echo "ERROR: Your adapter does not support AP (master) mode" >&2 + exit 1 +fi + +if ! can_be_sta_and_ap ${WIFI_IFACE}; then + if is_wifi_connected ${WIFI_IFACE}; then + echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2 + exit 1 + elif [[ $NO_VIRT -eq 0 ]]; then + echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2 + NO_VIRT=1 + fi +fi + +HOSTAPD=$(which hostapd) + +if [[ ! -x "$HOSTAPD" ]]; then + echo "ERROR: hostapd not found." >&2 + exit 1 +fi + +if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then + if ! strings "$HOSTAPD" | grep -m1 rtl871xdrv > /dev/null 2>&1; then + echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2 + exit 1 + fi + + if [[ $DRIVER != "rtl871xdrv" ]]; then + echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2 + DRIVER=rtl871xdrv + fi +fi + +if [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" != "none" ]]; then + echo "ERROR: Wrong Internet sharing method" >&2 + echo + usage >&2 + exit 1 +fi + +if [[ -n "$NEW_MACADDR" ]]; then + if ! is_macaddr "$NEW_MACADDR"; then + echo "ERROR: '${NEW_MACADDR}' is not a valid MAC address" >&2 + exit 1 + fi + + if ! is_unicast_macaddr "$NEW_MACADDR"; then + echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2 + exit 1 + fi + + if [[ $(get_all_macaddrs | grep -c ${NEW_MACADDR}) -ne 0 ]]; then + echo "WARN: MAC address '${NEW_MACADDR}' already exists. Because of this, you may encounter some problems" >&2 + fi +fi + +if [[ "$SHARE_METHOD" != "none" ]]; then + MIN_REQUIRED_ARGS=2 +else + MIN_REQUIRED_ARGS=1 +fi + +if [[ $# -gt $MIN_REQUIRED_ARGS ]]; then + if [[ "$SHARE_METHOD" != "none" ]]; then + if [[ $# -ne 3 && $# -ne 4 ]]; then + usage >&2 + exit 1 + fi + INTERNET_IFACE="$2" + SSID="$3" + PASSPHRASE="$4" + else + if [[ $# -ne 2 && $# -ne 3 ]]; then + usage >&2 + exit 1 + fi + SSID="$2" + PASSPHRASE="$3" + fi +else + if [[ "$SHARE_METHOD" != "none" ]]; then + if [[ $# -ne 2 ]]; then + usage >&2 + exit 1 + fi + INTERNET_IFACE="$2" + fi + if tty -s; then + while :; do + read -p "SSID: " SSID + if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then + echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 + continue + fi + break + done + while :; do + if [[ $USE_PSK -eq 0 ]]; then + read -p "Passphrase: " -s PASSPHRASE + echo + if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then + echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2 + continue + fi + read -p "Retype passphrase: " -s PASSPHRASE2 + echo + if [[ "$PASSPHRASE" != "$PASSPHRASE2" ]]; then + echo "Passphrases do not match." + else + break + fi + else + read -p "PSK: " PASSPHRASE + echo + if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then + echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2 + continue + fi + fi + done + else + read SSID + read PASSPHRASE + fi +fi + +if [[ "$SHARE_METHOD" != "none" ]] && ! is_interface $INTERNET_IFACE; then + echo "ERROR: '${INTERNET_IFACE}' is not an interface" >&2 + exit 1 +fi + +if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then + echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 + exit 1 +fi + +if [[ $USE_PSK -eq 0 ]]; then + if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then + echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2 + exit 1 + fi +elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then + echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2 + exit 1 +fi + +if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then + if [[ -n "$PASSPHRASE" ]]; then + echo "WARN: Realtek drivers usually have problems with WPA1, enabling -w 2" >&2 + WPA_VERSION=2 + fi + echo "WARN: If AP doesn't work, please read: howto/realtek.md" >&2 +fi + +if [[ $NO_VIRT -eq 1 && "$WIFI_IFACE" == "$INTERNET_IFACE" ]]; then + echo -n "ERROR: You can not share your connection from the same" >&2 + echo " interface if you are using --no-virt option." >&2 + exit 1 +fi + +mutex_lock +trap "cleanup" EXIT +CONFDIR=$(mktemp -d /tmp/create_ap.${WIFI_IFACE}.conf.XXXXXXXX) +echo "Config dir: $CONFDIR" +echo "PID: $$" +echo $$ > $CONFDIR/pid + +# to make --list-running work from any user, we must give read +# permissions to $CONFDIR and $CONFDIR/pid +chmod 755 $CONFDIR +chmod 444 $CONFDIR/pid + +COMMON_CONFDIR=/tmp/create_ap.common.conf +mkdir -p $COMMON_CONFDIR + +if [[ "$SHARE_METHOD" == "nat" ]]; then + echo $INTERNET_IFACE > $CONFDIR/nat_internet_iface + cp_n /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding \ + $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding +fi +cp_n /proc/sys/net/ipv4/ip_forward $COMMON_CONFDIR +if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then + cp_n /proc/sys/net/bridge/bridge-nf-call-iptables $COMMON_CONFDIR +fi +mutex_unlock + +if [[ "$SHARE_METHOD" == "bridge" ]]; then + if is_bridge_interface $INTERNET_IFACE; then + BRIDGE_IFACE=$INTERNET_IFACE + else + BRIDGE_IFACE=$(alloc_new_iface br) + fi +fi + +if [[ $USE_IWCONFIG -eq 0 ]]; then + iw dev ${WIFI_IFACE} set power_save off +fi + +if [[ $NO_VIRT -eq 0 ]]; then + VWIFI_IFACE=$(alloc_new_iface ap) + + # in NetworkManager 0.9.9 and above we can set the interface as unmanaged without + # the need of MAC address, so we set it before we create the virtual interface. + if networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]]; then + echo -n "Network Manager found, set ${VWIFI_IFACE} as unmanaged device... " + networkmanager_add_unmanaged ${VWIFI_IFACE} + # do not call networkmanager_wait_until_unmanaged because interface does not + # exist yet + echo "DONE" + fi + + if is_wifi_connected ${WIFI_IFACE}; then + WIFI_IFACE_FREQ=$(iw dev ${WIFI_IFACE} link | grep -i freq | awk '{print $2}') + WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel ${WIFI_IFACE_FREQ}) + echo -n "${WIFI_IFACE} is already associated with channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" + if is_5ghz_frequency $WIFI_IFACE_FREQ; then + FREQ_BAND=5 + else + FREQ_BAND=2.4 + fi + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then + echo ", fallback to channel ${WIFI_IFACE_CHANNEL}" + CHANNEL=$WIFI_IFACE_CHANNEL + else + echo + fi + fi + + VIRTDIEMSG="Maybe your WiFi adapter does not fully support virtual interfaces. + Try again with --no-virt." + echo -n "Creating a virtual WiFi interface... " + + if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then + # now we can call networkmanager_wait_until_unmanaged + networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]] && networkmanager_wait_until_unmanaged ${VWIFI_IFACE} + echo "${VWIFI_IFACE} created." + else + VWIFI_IFACE= + die "$VIRTDIEMSG" + fi + OLD_MACADDR=$(get_macaddr ${VWIFI_IFACE}) + if [[ -z "$NEW_MACADDR" && $(get_all_macaddrs | grep -c ${OLD_MACADDR}) -ne 1 ]]; then + NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE}) + fi + WIFI_IFACE=${VWIFI_IFACE} +else + OLD_MACADDR=$(get_macaddr ${WIFI_IFACE}) +fi + +mutex_lock +echo $WIFI_IFACE > $CONFDIR/wifi_iface +chmod 444 $CONFDIR/wifi_iface +mutex_unlock + +if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then + iw reg set "$COUNTRY" +fi + +can_transmit_to_channel ${WIFI_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz." + +if networkmanager_exists && ! networkmanager_iface_is_unmanaged ${WIFI_IFACE}; then + echo -n "Network Manager found, set ${WIFI_IFACE} as unmanaged device... " + networkmanager_add_unmanaged ${WIFI_IFACE} + + if networkmanager_is_running; then + networkmanager_wait_until_unmanaged ${WIFI_IFACE} + fi + + echo "DONE" +fi + +[[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!" + +[[ $MAC_FILTER -eq 1 ]] && echo "MAC address filtering is enabled!" + +[[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!" + +# hostapd config +cat << EOF > $CONFDIR/hostapd.conf +beacon_int=100 +ssid=${SSID} +interface=${WIFI_IFACE} +driver=${DRIVER} +channel=${CHANNEL} +ctrl_interface=$CONFDIR/hostapd_ctrl +ctrl_interface_group=0 +ignore_broadcast_ssid=$HIDDEN +ap_isolate=$ISOLATE_CLIENTS +EOF + +if [[ -n "$COUNTRY" ]]; then + cat << EOF >> $CONFDIR/hostapd.conf +country_code=${COUNTRY} +ieee80211d=1 +EOF +fi + +if [[ $FREQ_BAND == 2.4 ]]; then + echo "hw_mode=g" >> $CONFDIR/hostapd.conf +else + echo "hw_mode=a" >> $CONFDIR/hostapd.conf +fi + +if [[ $MAC_FILTER -eq 1 ]]; then + cat << EOF >> $CONFDIR/hostapd.conf +macaddr_acl=${MAC_FILTER} +accept_mac_file=${MAC_FILTER_ACCEPT} +EOF +fi + +if [[ $IEEE80211N -eq 1 ]]; then + cat << EOF >> $CONFDIR/hostapd.conf +ieee80211n=1 +ht_capab=${HT_CAPAB} +EOF +fi + +if [[ $IEEE80211AC -eq 1 ]]; then + echo "ieee80211ac=1" >> $CONFDIR/hostapd.conf +fi + +if [[ -n "$VHT_CAPAB" ]]; then + echo "vht_capab=${VHT_CAPAB}" >> $CONFDIR/hostapd.conf +fi + +if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then + echo "wmm_enabled=1" >> $CONFDIR/hostapd.conf +fi + +if [[ -n "$PASSPHRASE" ]]; then + [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 + if [[ $USE_PSK -eq 0 ]]; then + WPA_KEY_TYPE=passphrase + else + WPA_KEY_TYPE=psk + fi + cat << EOF >> $CONFDIR/hostapd.conf +wpa=${WPA_VERSION} +wpa_${WPA_KEY_TYPE}=${PASSPHRASE} +wpa_key_mgmt=WPA-PSK +wpa_pairwise=TKIP CCMP +rsn_pairwise=CCMP +EOF +fi + +if [[ "$SHARE_METHOD" == "bridge" ]]; then + echo "bridge=${BRIDGE_IFACE}" >> $CONFDIR/hostapd.conf +elif [[ $NO_DNSMASQ -eq 0 ]]; then + # dnsmasq config (dhcp + dns) + DNSMASQ_VER=$(dnsmasq -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+') + version_cmp $DNSMASQ_VER 2.63 + if [[ $? -eq 1 ]]; then + DNSMASQ_BIND=bind-interfaces + else + DNSMASQ_BIND=bind-dynamic + fi + if [[ "$DHCP_DNS" == "gateway" ]]; then + DHCP_DNS="$GATEWAY" + fi + cat << EOF > $CONFDIR/dnsmasq.conf +listen-address=${GATEWAY} +${DNSMASQ_BIND} +dhcp-range=${GATEWAY%.*}.1,${GATEWAY%.*}.254,255.255.255.0,24h +dhcp-option-force=option:router,${GATEWAY} +dhcp-option-force=option:dns-server,${DHCP_DNS} +EOF + MTU=$(get_mtu $INTERNET_IFACE) + [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> $CONFDIR/dnsmasq.conf + [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf + [[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> $CONFDIR/dnsmasq.conf + if [[ "$SHARE_METHOD" == "none" && "$REDIRECT_TO_LOCALHOST" == "1" ]]; then + cat << EOF >> $CONFDIR/dnsmasq.conf +address=/#/$GATEWAY +EOF + fi +fi + +# initialize WiFi interface +if [[ $NO_VIRT -eq 0 && -n "$NEW_MACADDR" ]]; then + ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die "$VIRTDIEMSG" +fi + +ip link set down dev ${WIFI_IFACE} || die "$VIRTDIEMSG" +ip addr flush ${WIFI_IFACE} || die "$VIRTDIEMSG" + +if [[ $NO_VIRT -eq 1 && -n "$NEW_MACADDR" ]]; then + ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die +fi + +if [[ "$SHARE_METHOD" != "bridge" ]]; then + ip link set up dev ${WIFI_IFACE} || die "$VIRTDIEMSG" + ip addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${WIFI_IFACE} || die "$VIRTDIEMSG" +fi + +# enable Internet sharing +if [[ "$SHARE_METHOD" != "none" ]]; then + echo "Sharing Internet using method: $SHARE_METHOD" + if [[ "$SHARE_METHOD" == "nat" ]]; then + iptables -w -t nat -I POSTROUTING -s ${GATEWAY%.*}.0/24 ! -o ${WIFI_IFACE} -j MASQUERADE || die + iptables -w -I FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT || die + iptables -w -I FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT || die + echo 1 > /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding || die + echo 1 > /proc/sys/net/ipv4/ip_forward || die + # to enable clients to establish PPTP connections we must + # load nf_nat_pptp module + modprobe nf_nat_pptp > /dev/null 2>&1 + elif [[ "$SHARE_METHOD" == "bridge" ]]; then + # disable iptables rules for bridged interfaces + if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then + echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables + fi + + # to initialize the bridge interface correctly we need to do the following: + # + # 1) save the IPs and route table of INTERNET_IFACE + # 2) if NetworkManager is running set INTERNET_IFACE as unmanaged + # 3) create BRIDGE_IFACE and attach INTERNET_IFACE to it + # 4) set the previously saved IPs and route table to BRIDGE_IFACE + # + # we need the above because BRIDGE_IFACE is the master interface from now on + # and it must know where is connected, otherwise connection is lost. + if ! is_bridge_interface $INTERNET_IFACE; then + echo -n "Create a bridge interface... " + OLD_IFS="$IFS" + IFS=$'\n' + + IP_ADDRS=( $(ip addr show $INTERNET_IFACE | grep -A 1 -E 'inet[[:blank:]]' | paste - -) ) + ROUTE_ADDRS=( $(ip route show dev $INTERNET_IFACE) ) + + IFS="$OLD_IFS" + + if networkmanager_is_running; then + networkmanager_add_unmanaged $INTERNET_IFACE + networkmanager_wait_until_unmanaged $INTERNET_IFACE + fi + + # create bridge interface + ip link add name $BRIDGE_IFACE type bridge || die + ip link set dev $BRIDGE_IFACE up || die + # set 0ms forward delay + echo -n 0 > /sys/class/net/$BRIDGE_IFACE/bridge/forward_delay + + # attach internet interface to bridge interface + ip link set dev $INTERNET_IFACE promisc on || die + ip link set dev $INTERNET_IFACE up || die + ip link set dev $INTERNET_IFACE master $BRIDGE_IFACE || die + + ip addr flush $INTERNET_IFACE + for x in "${IP_ADDRS[@]}"; do + x="${x/inet/}" + x="${x/secondary/}" + x="${x/dynamic/}" + x=$(echo $x | sed 's/\([0-9]\)sec/\1/g') + x="${x/${INTERNET_IFACE}/}" + ip addr add $x dev $BRIDGE_IFACE || die + done + + # remove any existing entries that were added from 'ip addr add' + ip route flush dev $INTERNET_IFACE + ip route flush dev $BRIDGE_IFACE + + # we must first add the entries that specify the subnets and then the + # gateway entry, otherwise 'ip addr add' will return an error + for x in "${ROUTE_ADDRS[@]}"; do + [[ "$x" == default* ]] && continue + ip route add $x dev $BRIDGE_IFACE || die + done + + for x in "${ROUTE_ADDRS[@]}"; do + [[ "$x" != default* ]] && continue + ip route add $x dev $BRIDGE_IFACE || die + done + + echo "$BRIDGE_IFACE created." + fi + fi +else + echo "No Internet sharing" +fi + +# start dhcp + dns (optional) +if [[ "$SHARE_METHOD" != "bridge" ]]; then + if [[ $NO_DNS -eq 0 ]]; then + DNS_PORT=5353 + iptables -w -I INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT || die + iptables -w -I INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT || die + iptables -w -t nat -I PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \ + -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die + iptables -w -t nat -I PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \ + -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die + else + DNS_PORT=0 + fi + + if [[ $NO_DNSMASQ -eq 0 ]]; then + iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT || die + + if which complain > /dev/null 2>&1; then + # openSUSE's apparmor does not allow dnsmasq to read files. + # remove restriction. + complain dnsmasq + fi + + umask 0033 + dnsmasq -C $CONFDIR/dnsmasq.conf -x $CONFDIR/dnsmasq.pid -l $CONFDIR/dnsmasq.leases -p $DNS_PORT || die + umask $SCRIPT_UMASK + fi +fi + +# start access point +echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" + +if [[ $NO_HAVEGED -eq 0 ]]; then + haveged_watchdog & + HAVEGED_WATCHDOG_PID=$! +fi + +# start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout) +STDBUF_PATH=`which stdbuf` +if [ $? -eq 0 ]; then + STDBUF_PATH=$STDBUF_PATH" -oL" +fi +$STDBUF_PATH $HOSTAPD $HOSTAPD_DEBUG_ARGS $CONFDIR/hostapd.conf & +HOSTAPD_PID=$! +echo $HOSTAPD_PID > $CONFDIR/hostapd.pid + +if ! wait $HOSTAPD_PID; then + echo -e "\nError: Failed to run hostapd, maybe a program is interfering." >&2 + if networkmanager_is_running; then + echo "If an error like 'n80211: Could not configure driver mode' was thrown" >&2 + echo "try running the following before starting create_ap:" >&2 + if [[ $NM_OLDER_VERSION -eq 1 ]]; then + echo " nmcli nm wifi off" >&2 + else + echo " nmcli r wifi off" >&2 + fi + echo " rfkill unblock wlan" >&2 + fi + die +fi + +clean_exit + +# Local Variables: +# tab-width: 4 +# indent-tabs-mode: nil +# End: + +# vim: et sts=4 sw=4 diff --git a/external/packages/bsp/rk3588/usr/local/bin/set_lcd_rotate.sh b/external/packages/bsp/rk3588/usr/local/bin/set_lcd_rotate.sh index e63d48ea2596..a79e23e40204 100755 --- a/external/packages/bsp/rk3588/usr/local/bin/set_lcd_rotate.sh +++ b/external/packages/bsp/rk3588/usr/local/bin/set_lcd_rotate.sh @@ -7,44 +7,6 @@ else exit fi -user=$(cat /etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf | grep "autologin-user=" | cut -d "=" -f 2) -#echo $user - -if [[ $user == "root" ]]; then - - lcd_num=$(sudo xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | wc -l) - [[ $lcd_num == 1 ]] && id=$(sudo xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | cut -d '=' -f2 | cut -d " " -f 1 | cut -d "[" -f 1) - - if [[ $lcd_num == 2 ]]; then - - id1=$(sudo xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | head -1 | cut -d "=" -f2 | cut -d "[" -f1) - id2=$(sudo xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | tail -1 | cut -d "=" -f2 | cut -d "[" -f1) - #echo "id1 = $id1" - #echo "id2 = $id2" - - fi - -fi - -if [[ $user != "root" ]]; then - - lcd_num=$(xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | wc -l) - [[ $lcd_num == 1 ]] && id=$(xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | cut -d '=' -f2 | cut -d " " -f 1 | cut -d "[" -f 1) - - if [[ $lcd_num == 2 ]]; then - - id1=$(xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | head -1 | cut -d "=" -f2 | cut -d "[" -f1) - id2=$(xinput | grep "Goodix Capacitive TouchScreen" | grep "pointer" | tail -1 | cut -d "=" -f2 | cut -d "[" -f1) - #echo "id1 = $id1" - #echo "id2 = $id2" - - fi - -fi - -#echo $lcd_num -#echo $id - case $1 in left) rotate=3 @@ -64,24 +26,12 @@ none) ;; esac -[[ -f /etc/profile.d/lcd.sh ]] && sudo rm /etc/profile.d/lcd.sh -sudo bash -c "echo '#!/bin/bash' >> /etc/profile.d/lcd.sh" -sudo bash -c "echo ' ' >> /etc/profile.d/lcd.sh" -sudo bash -c "echo '[[ \$XDG_SESSION_TYPE == x11 ]] && \' >> /etc/profile.d/lcd.sh" -if [[ $lcd_num == 2 ]]; then -sudo bash -c "echo xinput set-prop $id1 \'Coordinate Transformation Matrix\' ${matrix} >> /etc/profile.d/lcd.sh" -sudo bash -c "echo '[[ \$XDG_SESSION_TYPE == x11 ]] && \' >> /etc/profile.d/lcd.sh" -sudo bash -c "echo xinput set-prop $id2 \'Coordinate Transformation Matrix\' ${matrix} >> /etc/profile.d/lcd.sh" -else -sudo bash -c "echo xinput set-prop $id \'Coordinate Transformation Matrix\' ${matrix} >> /etc/profile.d/lcd.sh" -fi - -#xrandr -o $1 -#sed -i '/xrandr -o/d' ~/.bashrc -#echo "xrandr -o $1" >> ~/.bashrc +sudo sed -i '/TransformationMatrix/d' /usr/share/X11/xorg.conf.d/40-libinput.conf +sudo sed -i "/libinput touchscreen catchall/a Option \"TransformationMatrix\" \"${matrix}\"" /usr/share/X11/xorg.conf.d/40-libinput.conf sudo sed -i '/extraargs=fbcon=rotate/d' /boot/orangepiEnv.txt sudo bash -c "echo extraargs=fbcon=rotate:${rotate} >> /boot/orangepiEnv.txt" +sudo sed -i 's/bootlogo=true/bootlogo=false/g' /boot/orangepiEnv.txt sudo sync sudo reboot diff --git a/external/packages/plymouth-theme-orangepi/bullet.png b/external/packages/plymouth-theme-orangepi/bullet.png new file mode 100755 index 0000000000000000000000000000000000000000..5799dda51fa02c12c6895faaf846bca64a232859 GIT binary patch literal 616 zcmV-u0+;=XP)EX>4Tx04R}tkv&MmKpe$iTcuL!2iQSGBtvzwAS&XhRVYG*P%E_RU~=gfG-*gu zTpR`0f`cE6RR6U!!TkJGxa%9Ou}<~-NVP%yBN>%KKJM7R&pi-d;;+-(+!JwgLrz= z(mC%FM_5r(h|h_~47wokBiCh@-#8Z>_Vdh$kxtDMM~H<&8_R9XiiS!&MI2RBjq?2& zmle)ioYiubHSft^7|v-c%Uq{9gaj6`1Q7ycR8c}17Gkt&q?kz2e%!-9==eo)$>b`5 zkz)ZBsE`~#_#gc4*33^%xJltS(D`E9A0t3;7iiRM`}^3o8z(^E8Mx9~{z@H~`6Rv8 z(xOK|?>2C8-O}Ve;Bp5Tc+w?9a-;xFe?AYqpV2pEf&N<{wC48K+{ftykfyGZH^9Lm zFj}DOb&q#mg00006VoOIv0RI600RN!9r;`8x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru;|dNCCo_*&+#LV_0A)!;K~xyim5{*=fFKM-pN!Bj zhC_JjG&qe+!-*jr!!U!FVu(S-cWQoKn%}}8Qyoe<79ap>Q39ff&zES@2F$lbJFtrQ z>?{Z!3CjXN74@Z_w&EwQDgH!i#c0Lp920-NXP6V3Qy2~r_YoTa0000EX>4Tx04R}tkv&MmKpe$iQ$;OR2P=p;WT;LSMMWI73Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLxH>7iNQwVT3N2ziIPS;0dyl(!fKV+m&1xG5G~G56 zv8b3zuZkV72%raD7(>6zEMrcR;%GU(?&0I>U4&<~KKJM7Rx=g@d?N8IGfbO!gLrz= zHaPDShge=#iO-2gO}ZfQBi9v=-#F)77IteDHam6A8p|ubo~;!6mk{7 z$gzMDG{~+W{11M2Yh@=Vyrf_hXn%2>k71x=7pPSn=lj@kYA1mI8Mx9L{!$f~`6Rv4 z(85PR?>2C8-O!Xh;Bp5Tcrs*Db|pVeA)5u>&*+=dK;JD8So3wPsF@hv1(u9pRJN?OhX4-84wZ=9BPmYX6(PwVB4WpC0I<~P4(H$ z!lmF`{IiN-7@qWcz1{ItoD)eEhT#b=f=MyGO7d%&7l_C+t@W|fh/dev/null 2>&1; then + # For Debian + plymouth-set-default-theme orangepi + else + # For Ubuntu + update-alternatives \ + --install /usr/share/plymouth/themes/default.plymouth default.plymouth \ + /usr/share/plymouth/themes/orangepi/orangepi.plymouth 150 + fi + + if which update-initramfs >/dev/null 2>&1; then + update-initramfs -u + fi +fi diff --git a/external/packages/plymouth-theme-orangepi/debian/postrm b/external/packages/plymouth-theme-orangepi/debian/postrm new file mode 100644 index 000000000000..75d395e44fd6 --- /dev/null +++ b/external/packages/plymouth-theme-orangepi/debian/postrm @@ -0,0 +1,7 @@ +#!/bin/sh -e + +if [ "x$1" = xremove ]; then + if which update-initramfs >/dev/null 2>&1; then + update-initramfs -u + fi +fi diff --git a/external/packages/plymouth-theme-orangepi/debian/prerm b/external/packages/plymouth-theme-orangepi/debian/prerm new file mode 100644 index 000000000000..3033c126ff53 --- /dev/null +++ b/external/packages/plymouth-theme-orangepi/debian/prerm @@ -0,0 +1,13 @@ +#!/bin/sh -e + +if [ "x$1" = xremove ]; then + if which plymouth-set-default-theme >/dev/null 2>&1; then + # For Debian + plymouth-set-default-theme -r + else + # For Ubuntu + update-alternatives \ + --remove default.plymouth \ + /usr/share/plymouth/themes/orangepi/orangepi.plymouth + fi +fi diff --git a/external/packages/plymouth-theme-orangepi/entry.png b/external/packages/plymouth-theme-orangepi/entry.png new file mode 100755 index 0000000000000000000000000000000000000000..4a22e7fb146e98a66e5214f6b885adb71750c8df GIT binary patch literal 8999 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 N002ovPDHLkV1iZGko*7u literal 0 HcmV?d00001 diff --git a/external/packages/plymouth-theme-orangepi/keyboard.png b/external/packages/plymouth-theme-orangepi/keyboard.png new file mode 100755 index 0000000000000000000000000000000000000000..f532ad08b3c47b9bb8afcef741d2d57c7dcd1f3a GIT binary patch literal 946 zcmV;j15NyiP)EX>4Tx04R}tkv&MmP!xqvQ>9X>9qb_DkfAzR5EXIMDionYs1;guFnQ@8G%+M8 zE{=k0!NH%!s)LKOt`4q(Aov5~;_9U6A|>9J6k5di;PO7sd*^W9eSpxYGR^8512o+> zGpVGQ%dd!`SA@|=6-7v9mN6?yY51XW}PQqY%|xK1^M6c(@u2_h8KP(c+o613~2SjfKlnXct2i<4B}I}z_lx6v3dmcnj?)JqOS4Mf00)P_ zNQtu7eBRyDIk$iBwC48%^UHE{QHz7R00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNliru;|dN65(tgc(J24`0k26!K~z}7?UylY!ax+q-$jFi z#&FFT$Pg$aBi=irsBd+Kk zF7hT`UNe-yFpM4{1Q9}zVHiCC0PmU*g8t$O1dQ9*bFn^$y4|je5Q-eaD=h#(I?Om4 zjmEZZe*gdof^dW}&JTyfXD_cPN^w(9(3+t@l+xEqr9uDz+U>TEF+MMs%V%C**L8PO z&q_VCi*l{iLzZQIQA%Ha4zN>6k`4xg!IPI)RkgIKC#Z)OfOK7Vcd;vepxBLldfglR z6SRsHMJa9-$Ui}=Xx%o5cgY;b`Sp$8YPBB!6ToqtU?57VjWHI&9-yjf=|6!erQ^Vo znWlNg7>jK58Dp+#n%AKp`He>7IG4-aW-^(>ZNkiEv(L$7a#yd{-;;l>M2YrV-(e`( U0p3St#Q*>R07*qoM6N<$f>XG!@Bjb+ literal 0 HcmV?d00001 diff --git a/external/packages/plymouth-theme-orangepi/keymap-render.png b/external/packages/plymouth-theme-orangepi/keymap-render.png new file mode 100755 index 0000000000000000000000000000000000000000..4aaed5abb487524c3a2ac064cbeba1eb6656a89a GIT binary patch literal 26362 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 literal 0 HcmV?d00001 diff --git a/external/packages/plymouth-theme-orangepi/lock.png b/external/packages/plymouth-theme-orangepi/lock.png new file mode 100755 index 0000000000000000000000000000000000000000..c1538df283d662609e988f0e5de774e210e17ac4 GIT binary patch literal 1997 zcmV;;2Qv7HP)EX>4Tx04R}tkv&MmKpe$iQ>9X>9V{r~kfAzR@C$L&DionYs1;guFuC+YXws0h zxHt-~1qVMCs}3&Cx;nTDg5U>;i>s5Oi!ES_(b9vW|$S?b>gYb ziotoGIKqmuN_UyKw^epMfjAz1bM0hc>K|C1q`vLpFv3i&+nen#Jv1$u9R;HukOb04Py{D4^000SaNLh0L z04^f{04^f|c%?sf00007bV*G`2jdD35C<*b)5Y8X000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}000G~Nkl zy9jEb!+>dK{2zvdfQUN9Bx4~G5=dt{!PLQ4#BvHh(1butAw$X#Qz)o2CYSe~z1B*x zKh8O0r4yLj-1lRDto5vCJ?q)>)P-lWh;rk{*RB8;#ml3inY;1HDNpk0xvQ@OmjUip zAOQK(b60-_To#NUeD)5fzxpeae}kFh?ubA{j13~%vPcv&08&!S3>C#A2zNvk5g{T_ z)zw-3q-f_!`=5}3CjgHB{Vu0JzfMF@+68r^AR?O#BAmGd5Qx-3L=+DP1WkzuM^!1a zflAxgFSn7Ddq9Awpz4Pw0gk@>3lTv?AOeTO0o61DP!)1cBRg%G_w4FEA;NLDfkw({ zgKSTr1{b8Hh&BXWcNOaSYqTBi?x@!6Qc_gw=6NneKuQS+R1>N?E)x+%wn4fFW{#?$ zDjRfDssV#kMAuv}_m*+5Hr+xh zSO?QHlLqAyq=+z0nP{Ad2vS3?XI6QzP_v`fOBjI4f?^NM&1=Huj6OE=v8XRpO|4TL zvs&v2$D&@|4^K&fO5~iUQHCv7z$02oYT`L3O7AdX2`0i3QB;M9rM9&^jIyPaF*BZc z{HHv3=_2mVJkMi&N{QWW$KO8rJ8!)C$8q_(oFa<5aX9#f(7MDe4Q3&w)XLNADI3js z_QH9dyL6G0laoy#6=7q)-}A`B5An;NUml6(oLeK*dsMaEBbXH+7GxGdiUDu`-F@AT z&iQAaX20LB;Le+1+?|t?6MpjGgH0SO!j-sbP$I%`kCA*{BcrNVDTpfJ&NNMw))7_2 zGDoNG8G#%f9r35P-r~IvJ|gFYnQ`vySzdne1@`+rhr?mTn@S8bA3SrX@hvI`Hw1G- zRGFq+0~-2K+g(NY&wux0{mq-V_~65jo4^GT@XvpJ#^+yrG1knbY{=Zjv7$}mXzRZ1 zsFE>f)(43Q0^jP6oD&|g(Hm9S@MyQ20AZS@QC3zoD08XASG`?lXah1f2e}(TjNtm` zFwc!+b&sl0N@2I#Eo%;SjhVHQKr|f_0Znz}6tgvf6|>UjQLS$&Hel_+%`FpvGsnmL z_O(|B64SI}E;DD2j|Z>%9{0el5X4aH-c`M$B2%f5y48~_rLqi z_x37Ru3j6Z?C3=VIcG|#Gf%e{(*~f98PkzT`OZyOwQcBxy>TMa}X!9lE z)rWM&yfb7LuT)1&9}QJX%zX()RhwjkhZF9^N~AhUck;1Pn5H~N#+t9UmC2hYsio=) zJow{wM}fE-dCCpt#WyXs)wiOTngDgt%Q>~dX8#w?^ue1`8Uok}9l^GnYDpH)+n*49 z3|zT-ZPdK}Z<${yDS}|`!y9eS?bcy=;w(l>DP>-eS-bmglFY14Ss$=g1J33pF^so+ zoA$fb%8O318kCEcE#Eokt-0!=v}lVo@}`vz)eC#3eRdAdtU@U>?mpg0s&x>hrYXxi zOa{VmTbbOADNnVVV&PD?oNo0!R9}y2BV;|$ZrGPs#-b~07f|hH4YZG;tbX{$b$8mP zA2Qjk*3R9%ci`FqZLoDT`nQ{n!>c!uw!fp(UkeZ+nx8{p>s7r1rrQ~2)8*xWD8IWPW0 zg}IdRqV#r2SJkdf-rnCGtx9HAB$kcA5)tId3qR9;Jn+gNfJ?xA+{KRy5f9w>_4B~{ fz;*S*T?^)aILPWZ$8h*V00000NkvXXu0mjfH^{z@ literal 0 HcmV?d00001 diff --git a/external/packages/plymouth-theme-orangepi/orangepi-logo.png b/external/packages/plymouth-theme-orangepi/orangepi-logo.png new file mode 100755 index 0000000000000000000000000000000000000000..a41b8b6744d1b828dd68200340be8e200d270dd0 GIT binary patch literal 14421 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 "${tmp_dir}/${plymouth_theme_orangepi_dir}"/DEBIAN/control + Package: orangepi-plymouth-theme + Version: $REVISION + Architecture: all + Maintainer: $MAINTAINER <$MAINTAINERMAIL> + Depends: plymouth, plymouth-themes + Section: universe/x11 + Priority: optional + Description: boot animation, logger and I/O multiplexer - orangepi theme + END + + cp "${EXTER}"/packages/plymouth-theme-orangepi/debian/{postinst,prerm,postrm} \ + "${tmp_dir}/${plymouth_theme_orangepi_dir}"/DEBIAN/ + chmod 755 "${tmp_dir}/${plymouth_theme_orangepi_dir}"/DEBIAN/{postinst,prerm,postrm} + + #convert -resize 256x256 \ + # "${EXTER}"/packages/plymouth-theme-orangepi/orangepi-logo.png \ + # "${tmp_dir}/${plymouth_theme_orangepi_dir}"/usr/share/plymouth/themes/orangepi/bgrt-fallback.png + + # convert -resize 52x52 \ + # "${EXTER}"/packages/plymouth-theme-orangepi/spinner.gif \ + # "${tmp_dir}/${plymouth_theme_orangepi_dir}"/usr/share/plymouth/themes/orangepi/animation-%04d.png + + convert -resize 52x52 \ + "${EXTER}"/packages/plymouth-theme-orangepi/spinner.gif \ + "${tmp_dir}/${plymouth_theme_orangepi_dir}"/usr/share/plymouth/themes/orangepi/throbber-%04d.png + + cp "${EXTER}"/packages/plymouth-theme-orangepi/watermark.png \ + "${tmp_dir}/${plymouth_theme_orangepi_dir}"/usr/share/plymouth/themes/orangepi/ + + cp "${EXTER}"/packages/plymouth-theme-orangepi/{bullet,capslock,entry,keyboard,keymap-render,lock}.png \ + "${tmp_dir}/${plymouth_theme_orangepi_dir}"/usr/share/plymouth/themes/orangepi/ + + cp "${EXTER}"/packages/plymouth-theme-orangepi/orangepi.plymouth \ + "${tmp_dir}/${plymouth_theme_orangepi_dir}"/usr/share/plymouth/themes/orangepi/ + + fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "${tmp_dir}/${plymouth_theme_orangepi_dir}" > /dev/null + rsync --remove-source-files -rq "${tmp_dir}/${plymouth_theme_orangepi_dir}.deb" "${DEB_STORAGE}/" + rm -rf "${tmp_dir}" +} compile_orangepi-config() { diff --git a/scripts/configuration.sh b/scripts/configuration.sh index fa3d252b238d..60f83262c0f2 100755 --- a/scripts/configuration.sh +++ b/scripts/configuration.sh @@ -24,6 +24,7 @@ HOSTRELEASE=$(cat /etc/os-release | grep VERSION_CODENAME | cut -d"=" -f2) cd "${SRC}" || exit [[ -z "${ROOTFSCACHE_VERSION}" ]] && ROOTFSCACHE_VERSION=11 [[ -z "${CHROOT_CACHE_VERSION}" ]] && CHROOT_CACHE_VERSION=7 +[[ -z $PLYMOUTH ]] && PLYMOUTH="yes" cd ${SRC}/scripts BUILD_REPOSITORY_URL=$(improved_git remote get-url $(improved_git remote 2>/dev/null | grep origin) 2>/dev/null) diff --git a/scripts/debootstrap.sh b/scripts/debootstrap.sh index 8e126910bbff..fd1040f19dd1 100755 --- a/scripts/debootstrap.sh +++ b/scripts/debootstrap.sh @@ -137,7 +137,7 @@ create_rootfs_cache() local apt_extra="-o Acquire::http::Proxy=\"http://${APT_PROXY_ADDR:-localhost:3142}\"" local apt_mirror="http://${APT_PROXY_ADDR:-localhost:3142}/$APT_MIRROR" else - local apt_mirror="https://$APT_MIRROR" + local apt_mirror="http://$APT_MIRROR" fi # fancy progress bars diff --git a/scripts/distributions.sh b/scripts/distributions.sh index 5e19ac8b733c..ad5986a35926 100755 --- a/scripts/distributions.sh +++ b/scripts/distributions.sh @@ -392,6 +392,15 @@ POST_INSTALL_KERNEL_DEBS fi fi + # install plymouth-theme-orangepi + if [[ $PLYMOUTH == yes ]]; then + if [[ "${REPOSITORY_INSTALL}" != *plymouth-theme-orangepi* ]]; then + install_deb_chroot "${DEB_STORAGE}/orangepi-plymouth-theme_${REVISION}_all.deb" + else + install_deb_chroot "orangepi-plymouth-theme" "remote" + fi + fi + # install kernel sources if [[ -f ${DEB_STORAGE}/${CHOSEN_KSRC}_${REVISION}_all.deb && $INSTALL_KSRC == yes ]]; then install_deb_chroot "${DEB_STORAGE}/${CHOSEN_KSRC}_${REVISION}_all.deb" diff --git a/scripts/general.sh b/scripts/general.sh index 840430be3ada..bbe8ad1a2ebd 100755 --- a/scripts/general.sh +++ b/scripts/general.sh @@ -54,6 +54,7 @@ cleaning() find "${DEB_STORAGE}" -name "${CHOSEN_UBOOT}_*.deb" -delete find "${DEB_STORAGE}" \( -name "${CHOSEN_KERNEL}_*.deb" -o \ -name "orangepi-*.deb" -o \ + -name "plymouth-theme-orangepi_*.deb" -o \ -name "${CHOSEN_KERNEL/image/dtb}_*.deb" -o \ -name "${CHOSEN_KERNEL/image/headers}_*.deb" -o \ -name "${CHOSEN_KERNEL/image/source}_*.deb" -o \ @@ -1493,7 +1494,7 @@ prepare_host() fi mkdir -p $DEST/debs/{extra,u-boot} $DEST/{config,debug,patch,images} $USERPATCHES_PATH/overlay $EXTER/cache/{debs,sources,hash} $SRC/toolchains $SRC/.tmp -# build aarch64 + # build aarch64 if [[ $(dpkg --print-architecture) == amd64 ]]; then if [[ "${SKIP_EXTERNAL_TOOLCHAINS}" != "yes" ]]; then @@ -1835,8 +1836,11 @@ install_docker() { ;; esac - #mirror_url=https://mirrors.aliyun.com - mirror_url=https://repo.huaweicloud.com + if [[ ${SELECTED_CONFIGURATION} == desktop ]]; then + mirror_url=https://repo.huaweicloud.com + else + mirror_url=https://mirrors.aliyun.com + fi chroot "${SDCARD}" /bin/bash -c "curl -fsSL ${mirror_url}/docker-ce/linux/${distributor_id}/gpg | apt-key add -" echo "deb [arch=${ARCH}] ${mirror_url}/docker-ce/linux/${distributor_id} ${RELEASE} stable" > "${SDCARD}"/etc/apt/sources.list.d/docker.list diff --git a/scripts/main.sh b/scripts/main.sh index 25e6018aaf23..24418998c15b 100755 --- a/scripts/main.sh +++ b/scripts/main.sh @@ -442,7 +442,7 @@ if [[ ${IGNORE_UPDATES} != yes ]]; then fi - if [[ ${BOARD} =~ orangepi5 && $RELEASE =~ bullseye|jammy ]]; then + if [[ ${BOARD} =~ orangepi5 && $RELEASE =~ bullseye|focal|jammy ]]; then [[ ${BUILD_OPT} == image ]] && fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/rk3588_packages_${RELEASE}" "branch:rk3588_packages_${RELEASE}" @@ -525,9 +525,13 @@ if [[ $BUILD_OPT == rootfs || $BUILD_OPT == image ]]; then [[ "${REPOSITORY_INSTALL}" != *orangepi-zsh* ]] && compile_orangepi-zsh fi + # Compile plymouth-theme-orangepi if packed .deb does not exist or use the one from repository + if [[ ! -f ${DEB_STORAGE}/plymouth-theme-orangepi_${REVISION}_all.deb ]]; then + + [[ "${REPOSITORY_INSTALL}" != *plymouth-theme-orangepi* ]] && compile_plymouth-theme-orangepi + fi + # Compile orangepi-firmware if packed .deb does not exist or use the one from repository - - if [[ "${REPOSITORY_INSTALL}" != *orangepi-firmware* ]]; then if ! ls "${DEB_STORAGE}/orangepi-firmware_${REVISION}_all.deb" 1> /dev/null 2>&1; then @@ -550,21 +554,14 @@ if [[ $BUILD_OPT == rootfs || $BUILD_OPT == image ]]; then overlayfs_wrapper "cleanup" - - - # create board support package [[ -n $RELEASE && ! -f ${DEB_STORAGE}/$RELEASE/${BSP_CLI_PACKAGE_FULLNAME}.deb ]] && create_board_package - - # create desktop package #[[ -n $RELEASE && $DESKTOP_ENVIRONMENT && ! -f ${DEB_STORAGE}/$RELEASE/${CHOSEN_DESKTOP}_${REVISION}_all.deb ]] && create_desktop_package #[[ -n $RELEASE && $DESKTOP_ENVIRONMENT && ! -f ${DEB_STORAGE}/${RELEASE}/${BSP_DESKTOP_PACKAGE_FULLNAME}.deb ]] && create_bsp_desktop_package [[ -n $RELEASE && $DESKTOP_ENVIRONMENT ]] && create_desktop_package [[ -n $RELEASE && $DESKTOP_ENVIRONMENT ]] && create_bsp_desktop_package - - # build additional packages [[ $EXTERNAL_NEW == compile ]] && chroot_build_packages