diff --git a/build.sh b/build.sh index d6bf0fa8..5e00d404 100755 --- a/build.sh +++ b/build.sh @@ -49,6 +49,8 @@ CUSTOM_FEED_URL="${CUSTOM_FEED_URL}" OMR_OPENWRT=${OMR_OPENWRT:-default} +OMR_FORCE_DSA=${OMR_FORCE_DSA:-0} + if [ ! -f "$OMR_TARGET_CONFIG" ]; then echo "Target $OMR_TARGET not found !" #exit 1 @@ -64,6 +66,8 @@ elif [ "$OMR_TARGET" = "wrt3200acm" ]; then OMR_REAL_TARGET="arm_cortex-a9_vfpv3" elif [ "$OMR_TARGET" = "wrt32x" ]; then OMR_REAL_TARGET="arm_cortex-a9_vfpv3" +elif [ "$OMR_TARGET" = "bpi-r1" ]; then + OMR_REAL_TARGET="arm_cortex-a7_neon-vfpv4" elif [ "$OMR_TARGET" = "bpi-r2" ]; then OMR_REAL_TARGET="arm_cortex-a7_neon-vfpv4" elif [ "$OMR_TARGET" = "bpi-r64" ]; then @@ -200,6 +204,98 @@ if [ "$OMR_PACKAGES" = "mini" ]; then echo "CONFIG_PACKAGE_${OMR_DIST}-mini=y" >> "$OMR_TARGET/source/.config" fi +if [ "$OMR_TARGET" = "bpi-r1" -a "$OMR_OPENWRT" = "master" ]; then + # We disable mc in master, because it leads to unknown compilation errors on bpi-r1 target + # No time to check this, now, cause i am focused on make this target work + # Maybe someone can do this later + echo -n "Disabling error causing midnight commander (mc) package..." + sed -i "s/CONFIG_PACKAGE_mc=y/# CONFIG_PACKAGE_mc is not set/" "$OMR_TARGET/source/.config" + sed -i "s/CONFIG_MC_EDITOR=y/# CONFIG_MC_EDITOR is not set/" "$OMR_TARGET/source/.config" + sed -i "s/CONFIG_MC_SUBSHELL=y/# CONFIG_MC_SUBSHELL is not set/" "$OMR_TARGET/source/.config" + sed -i "s/CONFIG_MC_CHARSET=y/# CONFIG_MC_CHARSET is not set/" "$OMR_TARGET/source/.config" + sed -i "s/CONFIG_MC_VFS=y/# CONFIG_MC_VFS is not set/" "$OMR_TARGET/source/.config" + echo "done" + + # 2021-03-05 Oliver Welter +fi + +if [ "$OMR_TARGET" = "bpi-r1" ]; then + # Check kernel version + if [ "$OMR_KERNEL" != "5.4" ]; then + echo "Sorry, but for now kernel 5.4 is the only supported one." + exit 1 + fi + + # Remove the 310-Revert-ARM-dts-sun7i-Add-BCM53125-switch-nodes-to-th patch + echo -n "Removing unwanted patches from kernel $OMR_KERNEL..." + rm -f "$OMR_TARGET/source/target/linux/sunxi/patches-$OMR_KERNEL/310-Revert-ARM-dts-sun7i-Add-BCM53125-switch-nodes-to-th.patch" >/dev/null 2>&1 + echo "done" + + if [ "$OMR_FORCE_DSA" = "1" ]; then + # Remove support for swconfig + echo -n "Removing swconfig support from openwrt config..." + for i in DEFAULT_swconfig PACKAGE_swconfig PACKAGE_kmod-swconfig; do + sed -i "s/CONFIG_${i}/# CONFIG_${i} is not set/" "$OMR_TARGET/source/.config" + done + echo "done" + echo -n "Removing B53 swconfig support from kernel $OMR_KERNEL..." + for i in SWCONFIG_B53 SWCONFIG_B53_PHY_DRIVER SWCONFIG_LEDS LED_TRIGGER_PHY SWCONFIG_B53_PHY_FIXUP SWCONFIG_B53_SPI_DRIVER SWCONFIG_B53_MMAP_DRIVER SWCONFIG_B53_SRAB_DRIVER; do + sed -i "s/CONFIG_${i}/# CONFIG_${i} is not set/" "$OMR_TARGET/source/target/linux/sunxi/config-$OMR_KERNEL" + sed -i "s/CONFIG_${i}/# CONFIG_${i} is not set/" "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" + done + echo "done" + + # Add support for distributed switch architecture + echo -n "Adding B53 DSA support to kernel $OMR_KERNEL..." + for i in B53 B53_MDIO_DRIVER BRIDGE_VLAN_FILTERING MDIO_BUS_MUX_MULTIPLEXER NET_DSA NET_DSA_TAG_8021Q NET_DSA_TAG_BRCM NET_DSA_TAG_BRCM_PREPEND; do + check_sunxi_config=`grep "CONFIG_${i}=y" "$OMR_TARGET/source/target/linux/sunxi/config-$OMR_KERNEL" || true` + check_cortexa7_config=`grep "CONFIG_${i}=y" "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" || true` + + [ "$check_sunxi_config" = "" -a "$check_cortexa7_config" = "" ] && echo "CONFIG_${i}=y" >> "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" + done + echo "done" + + # Create DSA port map file (will be filled on first boot, by uci-defaults and tells the system, that it is in DSA mode) + touch "$OMR_TARGET/source/target/linux/sunxi/base-files/etc/dsa.map" + + # Remove the b53 hack in preinit + rm -f "$OMR_TARGET/source/target/linux/sunxi/base-files/lib/preinit/03_b53_hack.sh" + else + # Remove ip-bridge + echo -n "Removing ip-bridge support from openwrt config..." + for i in PACKAGE_ip-bridge; do + sed -i "s/CONFIG_${i}/# CONFIG_${i} is not set/" "$OMR_TARGET/source/.config" + done + echo "done" + + # Remove swconfig parts + echo -n "Removing unneeded B53 swconfig parts from kernel $OMR_KERNEL..." + for i in SWCONFIG_B53_PHY_FIXUP SWCONFIG_B53_SPI_DRIVER SWCONFIG_B53_MMAP_DRIVER SWCONFIG_B53_SRAB_DRIVER; do + sed -i "s/CONFIG_${i}/# CONFIG_${i} is not set/" "$OMR_TARGET/source/target/linux/sunxi/config-$OMR_KERNEL" + sed -i "s/CONFIG_${i}/# CONFIG_${i} is not set/" "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" + done + echo "done" + fi + + # Add led support + echo -n "Adding LED TRIGGER support to kernel $OMR_KERNEL..." + if [ "$OMR_FORCE_DSA" != "1" ]; then + for i in SWCONFIG_LEDS LED_TRIGGER_PHY; do + check_sunxi_config=`grep "CONFIG_${i}=y" "$OMR_TARGET/source/target/linux/sunxi/config-$OMR_KERNEL" || true` + check_cortexa7_config=`grep "CONFIG_${i}=y" "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" || true` + + [ "$check_sunxi_config" = "" -a "$check_cortexa7_config" = "" ] && echo "CONFIG_${i}=y" >> "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" + done + fi + for i in TIMER ONESHOT DISK MTD HEARTBEAT BACKLIGHT CPU ACTIVITY GPIO DEFAULT_ON TRANSIENT CAMERA PANIC NETDEV PATTERN AUDIO; do + check_sunxi_config=`grep "CONFIG_LEDS_TRIGGER_${i}=y" "$OMR_TARGET/source/target/linux/sunxi/config-$OMR_KERNEL" || true` + check_cortexa7_config=`grep "CONFIG_LEDS_TRIGGER_${i}=y" "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" || true` + + [ "$check_sunxi_config" = "" -a "$check_cortexa7_config" = "" ] && echo "CONFIG_LEDS_TRIGGER_${i}=y" >> "$OMR_TARGET/source/target/linux/sunxi/cortexa7/config-$OMR_KERNEL" + done + echo "done" +fi + cd "$OMR_TARGET/source" #if [ "$OMR_UEFI" = "yes" ] && [ "$OMR_TARGET" = "x86_64" ]; then diff --git a/config-bpi-r1 b/config-bpi-r1 new file mode 100644 index 00000000..7fb4a74a --- /dev/null +++ b/config-bpi-r1 @@ -0,0 +1,59 @@ +CONFIG_TARGET_BOARD="sunxi" +CONFIG_TARGET_sunxi=y +CONFIG_TARGET_sunxi_cortexa7=y +CONFIG_TARGET_sunxi_cortexa7_DEVICE_lamobo_lamobo-r1=y +CONFIG_TARGET_SUBTARGET="cortexa7" +CONFIG_TARGET_PROFILE="DEVICE_lamobo_lamobo-r1" +CONFIG_TARGET_ROOTFS_EXT4FS=y +CONFIG_TARGET_ROOTFS_SQUASHFS=y +CONFIG_PACKAGE_u-boot-Lamobo_R1=y +CONFIG_PACKAGE_uboot-envtools=y +CONFIG_PACKAGE_attr=y +CONFIG_PACKAGE_f2fs-tools=y +CONFIG_PACKAGE_f2fsck=y +CONFIG_PACKAGE_mkf2fs=y +CONFIG_PACKAGE_rtl8188eu-firmware=y +CONFIG_PACKAGE_ath9k-htc-firmware=y +CONFIG_PACKAGE_mt7601u-firmware=y +CONFIG_PACKAGE_rt2800-usb-firmware=y +CONFIG_PACKAGE_rtl8192cu-firmware=y +CONFIG_PACKAGE_rtl8192su-firmware=y +CONFIG_PACKAGE_kmod-switch-bcm53xx=y +CONFIG_PACKAGE_kmod-switch-bcm53xx-mdio=y +CONFIG_PACKAGE_ip-bridge=y +CONFIG_PACKAGE_swconfig=y +CONFIG_PACKAGE_kmod-swconfig=y +CONFIG_PACKAGE_kmod-ste10xp=y +CONFIG_PACKAGE_kmod-can-bcm=y +CONFIG_PACKAGE_kmod-ata-sunxi=y +CONFIG_PACKAGE_kmod-rtl8192cu=y +CONFIG_PACKAGE_kmod-ath9k-common=y +CONFIG_PACKAGE_kmod-ath9k-htc=y +CONFIG_PACKAGE_kmod-net-rtl8192su=y +CONFIG_PACKAGE_kmod-rtl8192c-common=y +CONFIG_PACKAGE_kmod-rtl8192cu=y +CONFIG_PACKAGE_kmod-rtl8xxxu=y +CONFIG_PACKAGE_kmod-sunxi-ir=y +CONFIG_PACKAGE_kmod-sound-soc-sunxi=y +CONFIG_PACKAGE_kmod-rtlwifi-usb=y +CONFIG_PACKAGE_kmod-rtlwifi=y +CONFIG_PACKAGE_kmod-scsi-core=y +CONFIG_PACKAGE_kmod-slhc=y +CONFIG_PACKAGE_kmod-usb-core=y +CONFIG_PACKAGE_kmod-leds-gpio=y +CONFIG_PACKAGE_kmod-ledtrig-activity=y +CONFIG_PACKAGE_kmod-ledtrig-gpio=y +CONFIG_PACKAGE_kmod-ledtrig-oneshot=y +CONFIG_PACKAGE_kmod-ledtrig-transient=y +CONFIG_PACKAGE_kmod-ledtrig-disk=y +CONFIG_PACKAGE_kmod-ledtrig-mtd=y +CONFIG_PACKAGE_kmod-ledtrig-heartbeat=y +CONFIG_PACKAGE_kmod-ledtrig-backlight=y +CONFIG_PACKAGE_kmod-ledtrig-cpu=y +CONFIG_PACKAGE_kmod-ledtrig-panic=y +CONFIG_PACKAGE_kmod-ledtrig-netdev=y +CONFIG_PACKAGE_kmod-ledtrig-pattern=y +CONFIG_PACKAGE_kmod-ledtrig-audio=y +CONFIG_PACKAGE_kmod-ipt-led=y +CONFIG_PACKAGE_kmod-usb-ledtrig-usbport=y +CONFIG_KERNEL_ARM_MODULE_PLTS=y diff --git a/contributors/welterrocks.md b/contributors/welterrocks.md new file mode 100644 index 00000000..43b2f0a0 --- /dev/null +++ b/contributors/welterrocks.md @@ -0,0 +1,9 @@ +2021-03-05 + +I hereby agree to the terms of the "OpenMPTCProuter Individual Contributor License Agreement", with MD5 checksum bc827a07eb93611d793ddb7c75083c00. + +I furthermore declare that I am authorized and able to make this agreement and sign this declaration. + +Signed, + +Oliver Welter https://github.com/welterrocks diff --git a/root/target/linux/sunxi/base-files/etc/uci-defaults/99-switch-config b/root/target/linux/sunxi/base-files/etc/uci-defaults/99-switch-config new file mode 100644 index 00000000..2eb372c6 --- /dev/null +++ b/root/target/linux/sunxi/base-files/etc/uci-defaults/99-switch-config @@ -0,0 +1,55 @@ +if [ -f "/etc/dsa.map" ]; then +echo 'ports="0 1 2 3 4 8" +port_3="wan" +port_4="lan1" +port_0="lan2" +port_1="lan3" +port_2="lan4" +port_8="eth0" +port_3_name="lan" +port_4_name="wan1" +port_0_name="wan2" +port_1_name="wan3" +port_2_name="wan4" +port_8_name="cpu" +port_cpu="8" +' > /etc/dsa.map +/sbin/swconfig-wrapper.sh setup-wrapper +fi + +uci delete network.@switch_vlan[0] +uci delete network.@switch_vlan[1] + +uci add network switch_vlan +uci set network.@switch_vlan[0].vlan=10 +uci set network.@switch_vlan[0].ports="8t 3" +uci set network.@switch_vlan[0].device="switch0" + +uci add network switch_vlan +uci set network.@switch_vlan[1].vlan=11 +uci set network.@switch_vlan[1].ports="8t 4" +uci set network.@switch_vlan[1].device="switch0" + +uci add network switch_vlan +uci set network.@switch_vlan[2].vlan=12 +uci set network.@switch_vlan[2].ports="8t 0" +uci set network.@switch_vlan[2].device="switch0" + +uci add network switch_vlan +uci set network.@switch_vlan[3].vlan=13 +uci set network.@switch_vlan[3].ports="8t 1" +uci set network.@switch_vlan[3].device="switch0" + +uci add network switch_vlan +uci set network.@switch_vlan[4].vlan=14 +uci set network.@switch_vlan[4].ports="8t 2" +uci set network.@switch_vlan[4].device="switch0" + +uci set network.lan.ifname="eth0.10" +uci set network.wan1.ifname="eth0.11" +uci set network.wan2.ifname="eth0.12" +uci set network.wan3.ifname="eth0.13" +uci set network.wan4.ifname="eth0.14" + +uci commit +exit 0 diff --git a/root/target/linux/sunxi/base-files/sbin/swconfig-wrapper.sh b/root/target/linux/sunxi/base-files/sbin/swconfig-wrapper.sh new file mode 100755 index 00000000..aeccbc9e --- /dev/null +++ b/root/target/linux/sunxi/base-files/sbin/swconfig-wrapper.sh @@ -0,0 +1,350 @@ +#!/bin/sh +# swconfig wrapper for BPI-R1 switch in DSA enabled environment +# Copyright (c) 2021 Oliver Welter + +SWCONFIG="/sbin/swconfig" +SWCONFIG_REAL="$SWCONFIG.real" +SWCONFIG_DSA="$SWCONFIG.dsa" +SWCONFIG_WRAPPER="$SWCONFIG-wrapper.sh" +SWCONFIG_LINK=`readlink $SWCONFIG` + +DSA_MAP="/etc/dsa.map" +DSA_MODE=0 + +UCI="/sbin/uci" +GREP="/bin/grep" +CUT="/usr/bin/cut" +AWK="/usr/bin/awk" +IP="/sbin/ip" + +SWITCHNULL="switch0" + +[ -f "$DSA_MAP" ] && DSA_MODE=1 + +if [ "$1" = "setup-wrapper" ]; then + if [ "$SWCONFIG_LINK" = "$SWCONFIG_WRAPPER" ]; then + echo "Already linked to wrapper" >/dev/stderr + exit 1 + elif [ -x "$SWCONFIG" ]; then + mv $SWCONFIG $SWCONFIG_REAL && \ + ln -sf $SWCONFIG_WRAPPER $SWCONFIG && \ + exit 0 || exit $? + else + echo "Unable to find swconfig binary" >/dev/stderr + exit 2 + fi +elif [ "$DSA_MODE" = 0 ]; then + if [ "$1" = "" ]; then + $SWCONFIG_REAL && exit 0 || exit $? + elif [ "$2" = "" ]; then + $SWCONFIG_REAL $1 && exit 0 || exit $? + elif [ "$3" = "" ]; then + $SWCONFIG_REAL $1 $2 && exit 0 || exit $? + elif [ "$4" = "" ]; then + $SWCONFIG_REAL $1 $2 $3 && exit 0 || exit $? + elif [ "$5" = "" ]; then + $SWCONFIG_REAL $1 $2 $3 $4 && exit 0 || exit $? + elif [ "$6" = "" ]; then + $SWCONFIG_REAL $1 $2 $3 $4 $5 && exit 0 || exit $? + elif [ "$7" = "" ]; then + $SWCONFIG_REAL $1 $2 $3 $4 $5 $6 && exit 0 || exit $? + else + exit 255 + fi +fi + +. $DSA_MAP + + get_interface_by_portlist() { + local ports="$1" + + for port in $ports; do + port_id=`echo $port | $CUT -d "t" -f1` + port_tagged=`echo $port | $GREP "t" >/dev/null 2>&1 && echo 1 || echo 0` + interface=`eval echo "\${port_$port_id}"` + name=`eval echo "\${port_name_$port_id}"` + + echo "$port_id:$port_tagged:$interface:$name" + done +} + +swconfig_usage() { + echo "WARNING: swconfig runs in DSA wrapper mode" + $SWCONFIG_REAL && exit 0 || exit $? +} + +swconfig_port_get() { + local port="$1" + local key="$2" + + return 0 +} + +swconfig_vlan_get() { + local vlan="$1" + local key="$2" + + return 0 +} + +swconfig_get() { + local key="$1" + + case $key in + reset|reset_mib|apply) + # This is ignored, but leads to exit code 0 to not confuse the networking scripts + return 0 + ;; + *) + echo "Unknown key $key for device" >/dev/stderr + return 1 + ;; + esac + + return 0 +} + +swconfig_port_set() { + local port="$1" + local key="$2" + local val="$3" + + case $key in + *) + echo "Unknown key $key for port" >/dev/stderr + return 1 + ;; + esac + + return 0 +} + +swconfig_vlan_set() { + local vlan="$1" + local key="$2" + local val="$3" + + case $key in + *) + echo "Unknown key $key for vlan" >/dev/stderr + return 1 + ;; + esac + + return 0 +} + +swconfig_set() { + local key="$1" + local val="$2" + + case $key in + reset|reset_mib|apply) + # This is ignored, but leads to exit code 0 to not confuse the networking scripts + return 0 + ;; + *) + echo "Unknown key $key for device" >/dev/stderr + return 1 + ;; + esac + + return 0 +} + +swconfig_port_load() { + local port="$1" + local config="$2" + + return 0 +} + +swconfig_vlan_load() { + local vlan="$1" + local config="$2" + + return 0 +} + +swconfig_load() { + local config="$1" + + # This is the part, where the magic happens. + # Due to its structure, swconfig gets the configuration to use by itself. + # At this point, we use uci to fetch the configuration for the vlans to setup. + + [ "$config" != "network" ] && return 1 + + # Set the CPU port + local CPUPORT=`eval echo "\${port_$port_cpu}"` + + # Bring up the CPU port + $IP link set $CPUPORT up + + for section in `$UCI show $config | $GREP "=switch_vlan" | $CUT -d "=" -f1`; do + section_id=`$UCI show $section | $GREP "=switch_vlan" | $CUT -d "=" -f1 | $CUT -d "." -f2` + + vlan=`$UCI show $config.$section_id.vlan | $CUT -d "=" -f2 | $CUT -d "'" -f2` + ports=`$UCI show $config.$section_id.ports | $CUT -d "=" -f2 | $CUT -d "'" -f2` + device=`$UCI show $config.$section_id.device | $CUT -d "=" -f2 | $CUT -d "'" -f2` + + [ "$device" != "$SWITCHNULL" ] && continue + + for iface in `get_interface_by_portlist $ports`; do + port_id=`echo $iface | $CUT -d ":" -f1` + + # We just want the CPU ports here + [ "$port_id" != "$port_cpu" ] && continue + + port_tagged=`echo $iface | $CUT -d ":" -f2` + interface=`echo $iface | $CUT -d ":" -f3` + name=`echo $iface | $CUT -d ":" -f4` + + # At this point, we have all we need. + if [ "$port_tagged" = 1 ]; then + # Tag the traffic on CPU port as master interface + $IP link add link $interface name $interface.$vlan type vlan id $vlan + + # Bring up the master interface before the slaves + $IP link set $interface.$vlan up + fi + done + + for iface in `get_interface_by_portlist $ports`; do + port_id=`echo $iface | $CUT -d ":" -f1` + + # We just want the slave ports here + [ "$port_id" = "$port_cpu" ] && continue + + port_tagged=`echo $iface | $CUT -d ":" -f2` + interface=`echo $iface | $CUT -d ":" -f3` + name=`echo $iface | $CUT -d ":" -f4` + + if [ "$port_tagged" = 1 ]; then + interface="$interface.$vlan" + fi + + # Bring up the slave interface + $IP link set $interface up + + # Create the bridge + $IP link add name $name type bridge + + # Set VLAN filtering and PVID + $IP link set dev $name type bridge vlan_filtering 1 vlan_default_pvid $vlan + done + + for iface in `get_interface_by_portlist $ports`; do + port_id=`echo $iface | $CUT -d ":" -f1` + port_tagged=`echo $iface | $CUT -d ":" -f2` + interface=`echo $iface | $CUT -d ":" -f3` + name=`echo $iface | $CUT -d ":" -f4` + + if [ "$port_tagged" = 1 ]; then + interface="$interface.$vlan" + fi + + # Add port to its corresponding bridge + $IP link set dev $interface master $name + done + done + + return 0 +} + +swconfig_port_show() { + local port="$1" + + return 0 +} + +swconfig_vlan_show() { + local vlan="$1" + + return 0 +} + +swconfig_show() { + return 0 +} + +case $1 in + dev) + device="$2" + mode="$3" + op="$5" + + key="$6" + val="$7" + + port="" + vlan="" + + case $3 in + port) + port="$4" + ;; + vlan) + vlan="$4" + ;; + *) + mode="switch" + op="$3" + key="$4" + val="$5" + ;; + esac + + case $op in + help) + $SWCONFIG_REAL $1 $2 $3 $4 && exit 0 || exit $? + ;; + set) + if [ "$mode" = "port" ]; then + swconfig_port_set $port $key $val && exit 0 || exit $? + elif [ "$mode" = "vlan" ]; then + swconfig_vlan_set $vlan $key $val && exit 0 || exit $? + else + swconfig_set $key $val && exit 0 || exit $? + fi + ;; + get) + if [ "$mode" = "port" ]; then + swconfig_port_get $port $key && exit 0 || exit $? + elif [ "$mode" = "vlan" ]; then + swconfig_vlan_get $vlan $key && exit 0 || exit $? + else + swconfig_get $key && exit 0 || exit $? + fi + ;; + load) + if [ "$mode" = "port" ]; then + swconfig_port_load $port $key && exit 0 || exit $? + elif [ "$mode" = "vlan" ]; then + swconfig_vlan_load $vlan $key && exit 0 || exit $? + else + swconfig_load $key && exit 0 || exit $? + fi + ;; + show) + if [ "$mode" = "port" ]; then + swconfig_port_show $port && exit 0 || exit $? + elif [ "$mode" = "vlan" ]; then + swconfig_vlan_show $vlan && exit 0 || exit $? + else + swconfig_show && exit 0 || exit $? + fi + ;; + *) + swconfig_usage + ;; + esac + ;; + list) + echo $SWITCHNULL + exit 0 + ;; + *) + swconfig_usage + ;; +esac