| #!/bin/sh |
| # SUBSYSTEM, ACTION, DEVPATH, and FIRMWARE are all provided by the kernel |
| # when this script is started. |
| exec >/dev/kmsg 2>&1 |
| |
| . /etc/utils.sh |
| |
| |
| get_random_mac() { |
| echo -n $(get_mac_addr_for_interface "$1" | cut -c1-8) |
| randomdata 0 3 | hexdump -e '3/1 ":%02x"' |
| } |
| |
| create_client_interface() { |
| local interface="$1" |
| local wlan_mac=$(cat /sys/class/net/"$interface"/address) |
| local mac=$(mac_addr_increment "$wlan_mac" 1) |
| local client_interface=$(echo "$interface" | sed s/^wlan/wcli/) |
| if ! interface_exists "$client_interface"; then |
| if is_quantenna_interface "$interface"; then |
| echo "add $client_interface 2" >/sys/class/net/quantenna/vlan |
| mac=$(get_locally_administered_mac_addr "$mac") |
| else |
| local phy=$(find_phy_for_interface "$interface") |
| iw phy "$phy" interface add "$client_interface" type station |
| fi |
| ip link set dev "$client_interface" address "$mac" |
| fi |
| # Disable IPv6 autoconfiguration of the interface, which breaks gftests. |
| # accept_ra means "Accept Router Advertisements, and autoconfigure this |
| # interface with received data."; disabling this prevents the problematic |
| # autoconfiguration of routes. |
| # TODO(rofrankel): Find a way not to need to disable this, e.g. by making it |
| # so that autoconfigured br0 routes have a lower metric than wcli* routes. |
| echo 0 >/proc/sys/net/ipv6/conf/wcli0/accept_ra |
| } |
| |
| load_firmware() { |
| echo "Trying firmware '$1'" && |
| [ -r "$1" ] && |
| echo 1 >/sys/$DEVPATH/loading && |
| cat "$1" >/sys/$DEVPATH/data && |
| echo 0 >/sys/$DEVPATH/loading && |
| echo " ...loaded firmware '$1'" |
| } |
| |
| set_mac_address() |
| { |
| local interface="$1" |
| # Set the mac address from values in hnvram. |
| if is-windcharger; then |
| case "$interface" in |
| wan0) |
| set_mac_from_hnvram wan0 MAC_ADDR1 |
| ;; |
| lan0) |
| set_mac_from_hnvram lan0 MAC_ADDR2 |
| ;; |
| esac |
| fi |
| case "$interface" in |
| wlan0) |
| set_mac_from_hnvram wlan0 MAC_ADDR_WIFI |
| ;; |
| wlan1) |
| set_mac_from_hnvram wlan1 MAC_ADDR_WIFI2 |
| ;; |
| esac |
| } |
| |
| create_secondary_interface() { |
| local interface="$1" |
| local suffix="$2" |
| local mac=$(get_random_mac "$interface") |
| local secondary_interface="${interface}${suffix}" |
| |
| if ! interface_exists "$secondary_interface"; then |
| if is_quantenna_interface "$interface"; then |
| echo "add $secondary_interface 4" >/sys/class/net/quantenna/vlan |
| mac=$(get_locally_administered_mac_addr "$mac") |
| else |
| local phy=$(find_phy_for_interface "$interface") |
| iw phy "$phy" interface add "$secondary_interface" type managed |
| fi |
| ip link set dev "$secondary_interface" address "$mac" |
| brctl addif br1 "$secondary_interface" |
| fi |
| } |
| |
| |
| network_add() { |
| interface="$1" |
| set_mac_address "$interface" |
| # At boot or device reset, a net add event is delivered for the primary |
| # interface. Use this event to create a client interface, which is |
| # created in user space unlike the primary interface. |
| if startswith "$interface" "wlan"; then |
| if is-wireless-client; then |
| create_client_interface "$interface" |
| fi |
| fi |
| if is-network-box && startswith "$interface" wlan && ! contains "$interface" _portal; then |
| create_secondary_interface "$interface" _portal |
| fi |
| } |
| |
| case "$SUBSYSTEM-$ACTION" in |
| input-add) |
| # BlueZ: adjust repeat speed on remotes |
| if [ -c "/dev/$DEVNAME" ]; then |
| echo "hotplug: setting autorepeat on $DEVNAME" |
| input-repeat -f "/dev/$DEVNAME" -d 600 |
| # Allow user to access input device |
| chmod 666 "/dev/$DEVNAME" |
| fi |
| ;; |
| |
| bluetooth-add) |
| # BlueZ: Configure hci0 interface link mode |
| hcidev=${DEVPATH##*/} |
| if [ "$hcidev" = "hci0" ]; then |
| echo "hotplug: configuring $hcidev" |
| hciconfig "$hcidev" lm ACCEPT,MASTER |
| fi |
| ;; |
| |
| hidraw-add) |
| if [ -c "/dev/$DEVNAME" ]; then |
| echo "Trying gfrm100-rcu-audio for $DEVNAME" |
| # Allow user to access input device |
| chmod 666 "/dev/$DEVNAME" |
| # gfrm100-rcu-audio will exit if not a GFRM100 or daemonize itself |
| # if it is, so we run it in the foreground. The timeout is for |
| # safety to not hang the hotplug script, just in case. |
| timeout 5 setuid appclient:video gfrm100-rcu-audio "/dev/$DEVNAME" 2>&1 | logos "gfrm100_audio" |
| fi |
| ;; |
| |
| firmware-add) |
| echo "hotplug: sys=$SUBSYSTEM act=$ACTION fw=$FIRMWARE dev=$DEVPATH" |
| register_experiment RwFirmware |
| if experiment RwFirmware; then |
| load_firmware "/rw/firmware/$FIRMWARE" || |
| load_firmware "/rw/firmware/$(basename "$FIRMWARE")" |
| else |
| false # fall back |
| fi || |
| load_firmware "/lib/firmware/$FIRMWARE" || |
| echo -1 >"/sys/$DEVPATH/loading" |
| ;; |
| |
| net-add) |
| echo "hotplug: net-add if=$INTERFACE act=$ACTION" |
| network_add "$INTERFACE" |
| ;; |
| esac |
| |
| # DirectFB apps listen for an AF_UNIX message for hotplug events, which |
| # dfb_input_hotplug sends using the ACTION and DEVPATH in the environment. |
| if [ "$SUBSYSTEM" = "input" ] && [ "$ACTION" = "add" -o "$ACTION" = "remove" ]; then |
| for dir in /usr/local/bin/directfb/* ; do |
| if [ -d "$dir" ]; then |
| export PATH="$PATH":"$dir" |
| fi |
| done |
| if runnable dfb_input_hotplug; then |
| dfb_input_hotplug |
| fi |
| fi |