]> git.ipfire.org Git - people/ms/network.git/commitdiff
Major rewrite of hotplug handling
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 10 Dec 2014 02:02:53 +0000 (02:02 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 10 Dec 2014 02:02:53 +0000 (02:02 +0000)
13 files changed:
Makefile.am
src/functions/functions.batman-adv
src/functions/functions.constants
src/functions/functions.device
src/functions/functions.hotplug [new file with mode: 0644]
src/functions/functions.phy
src/functions/functions.ports
src/functions/functions.util
src/hooks/ports/batman-adv
src/hooks/ports/wireless-adhoc [moved from src/hooks/ports/batman-adv-port with 72% similarity]
src/hooks/ports/wireless-ap
src/udev/network-hotplug
src/udev/rules.d/60-net.rules

index 9ba352f5e1a87e42d8295098d72b05db67e75813..5b26284cc86d9d984ee3acaf84e581bcca66dd5c 100644 (file)
@@ -119,6 +119,7 @@ dist_network_SCRIPTS = \
        src/functions/functions.he \
        src/functions/functions.hook \
        src/functions/functions.hostapd \
+       src/functions/functions.hotplug \
        src/functions/functions.http \
        src/functions/functions.ip \
        src/functions/functions.iptables \
@@ -185,12 +186,12 @@ dist_hooks_configs_SCRIPTS = \
 
 dist_hooks_ports_SCRIPTS = \
        src/hooks/ports/batman-adv \
-       src/hooks/ports/batman-adv-port \
        src/hooks/ports/bonding \
        src/hooks/ports/dummy \
        src/hooks/ports/ethernet \
        src/hooks/ports/macvlan \
        src/hooks/ports/vlan \
+       src/hooks/ports/wireless-adhoc \
        src/hooks/ports/wireless-ap
 
 dist_hooks_zones_SCRIPTS = \
index 01c1c8c27c9d0463db0542a1c5468fbfa04ca0d0..23ed6119b8e1df2aad5c7dc92ade73f5906d926a 100644 (file)
@@ -24,7 +24,31 @@ function batman_adv_start() {
        module_load "batman-adv"
 }
 
-function batman_adv_interface_add() {
+function batman_adv_add() {
+       local device="${1}"
+       assert isset device
+
+       local cmd="ip link add name ${device} type batadv"
+       cmd_quiet "${cmd}"
+       local ret=$?
+
+       if [ ${ret} -eq ${EXIT_OK} ]; then
+               log DEBUG "batman-adv device '${device}' has been created"
+       else
+               log ERROR "batman-adv device '${device}' could not be created: ${ret}"
+       fi
+
+       return ${ret}
+}
+
+function batman_adv_delete() {
+       local device="${1}"
+       assert isset device
+
+       device_delete "${device}"
+}
+
+function batman_adv_attach() {
        local device=${1}
        assert isset device
 
@@ -37,7 +61,7 @@ function batman_adv_interface_add() {
        fwrite "${SYS_CLASS_NET}/${port}/batman_adv/mesh_iface" "${device}"
 }
 
-function batman_adv_interface_del() {
+function batman_adv_detach() {
        local port=${1}
        assert isset port
 
index 1d353831e54d35fcedaa0a76faa832a0b552a33b..6c11c4ac7e9cfdeb8acd6e48ebc0aad5c132f8ba 100644 (file)
@@ -84,6 +84,6 @@ DEVICE_PRINT_LINE1="    %-24s %s\n"
 PORT_PATTERN="pN"
 PORT_PATTERN_ACCESSPOINT="apN"
 PORT_PATTERN_BATMAN_ADV="batN"
-PORT_PATTERN_BATMAN_ADV_PORT="batpN"
 PORT_PATTERN_WIRELESS="wN"
+PORT_PATTERN_WIRELESS_ADHOC="adhocN"
 PORT_PATTERN_WIRELESS_MONITOR="wmonN"
index 3f1a7e46e015ffc32b041484741ccc90c47f4b53..600dd837c575f49016237765e357cfc69142b739 100644 (file)
@@ -164,8 +164,8 @@ function device_is_batman_adv() {
        [ -d "${SYS_CLASS_NET}/${1}/mesh" ]
 }
 
-# Check if the device is a batman-adv bridge port
-function device_is_batman_adv_port() {
+# Check if the device is a batman-adv slave port
+function device_is_batman_adv_slave() {
        local device="${1}"
 
        if [ -d "${SYS_CLASS_NET}/${device}/batman_adv" ]; then
@@ -214,6 +214,14 @@ function device_is_wireless_monitor() {
                device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_MONITOR}"
 }
 
+function device_is_wireless_adhoc() {
+       local device="${1}"
+       assert isset device
+
+       device_is_wireless "${device}" && \
+               device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_ADHOC}"
+}
+
 function device_get_bridge() {
        local device=${1}
        assert isset device
@@ -356,12 +364,12 @@ function device_get_type() {
        elif device_is_batman_adv ${device}; then
                echo "batman-adv"
 
-       elif device_is_batman_adv_port ${device}; then
-               echo "batman-adv-port"
-
        elif device_is_loopback ${device}; then
                echo "loopback"
 
+       elif device_is_wireless_adhoc ${device}; then
+               echo "wireless-adhoc"
+
        elif device_is_wireless ${device}; then
                echo "wireless"
 
diff --git a/src/functions/functions.hotplug b/src/functions/functions.hotplug
new file mode 100644 (file)
index 0000000..6e71e0c
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2014  IPFire Network Development Team                         #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+function hotplug_assert_in_hotplug_event() {
+       assert [ -n "${IN_HOTPLUG_EVENT}" ]
+}
+
+function hotplug_action() {
+       hotplug_assert_in_hotplug_event
+
+       echo "${ACTION}"
+}
+
+function hotplug_propagate_all_ports() {
+       hotplug_assert_in_hotplug_event
+
+       # Create configured child devices.
+       local port
+       for port in $(ports_get_all); do
+               port_hotplug_event "${port}"
+               local ret="${?}"
+
+               # Log warning for crashed hooks
+               case "${ret}" in
+                       ${EXIT_OK}|${EXIT_NOT_HANDLED})
+                               : # do nothing
+                               ;;
+                       *)
+                               log WARNING "Unknown exit code for port '${port}': ${ret}"
+                               ;;
+               esac
+       done
+}
+
+function hotplug_event_port_is_interface() {
+       hotplug_assert_in_hotplug_event
+
+       local port="${1}"
+       assert isset port
+
+       [ "${port}" = "${INTERFACE}" ]
+}
+
+function hotplug_event_port_is_slave() {
+       hotplug_assert_in_hotplug_event
+
+       local port="${1}"
+       assert isset port
+
+       # Return false if INTERFACE is not set
+       isset INTERFACE || return ${EXIT_FALSE}
+
+       local slaves="$(port_get_slaves "${port}")"
+       list_match "${INTERFACE}" ${SLAVES}
+}
+
+function hotplug_event_port_uses_phy() {
+       hotplug_assert_in_hotplug_event
+
+       local port="${1}"
+       assert isset port
+
+       # Return false if PHY is not set
+       isset PHY || return ${EXIT_FALSE}
+
+       # Returns true if port uses PHY
+       port_uses_phy "${port}" "${PHY}"
+}
index 35f2b863b0d9b09b649e1b39b1ef6e8c99873af1..79a356ed2e0ffb51cd8571c0d6b5469f9c0f3663 100644 (file)
@@ -90,3 +90,17 @@ function phy_get_address() {
 
        print "$(<${path})"
 }
+
+function phy_get_devices() {
+       local phy="${1}"
+       assert isset phy
+
+       local device
+       for device in $(device_get_all); do
+               local p="$(device_get_phy "${device}")"
+
+               if [ "${phy}" = "${p}" ]; then
+                       print "${device}"
+               fi
+       done
+}
index 836a377913e9650977eca7647da5252ac16955be..638d7ea13e1a444c80ff98ec0a8cf557efd2b18b 100644 (file)
@@ -297,3 +297,58 @@ function port_zone() {
 
        return ${EXIT_OK}
 }
+
+function port_hotplug_event() {
+       local port="${1}"
+       assert isset port
+
+       hotplug_assert_in_hotplug_event
+
+       port_cmd "hotplug" "${port}"
+}
+
+function port_get_slaves() {
+       local port="${1}"
+
+       port_settings_read "${port}" \
+               --ignore-superfluous-settings SLAVES
+       print "${SLAVES}"
+}
+
+function port_device_is_slave() {
+       assert [ $# -eq 2 ]
+
+       local port="${1}"
+       local device="${2}"
+
+       # Get slaves of port
+       local slaves="$(port_get_slaves "${port}")"
+
+       # Returns true if device is in slaves
+       list_match "${device}" ${slaves}
+}
+
+function port_get_phy() {
+       local port="${1}"
+
+       port_settings_read "${port}" \
+               --ignore-superfluous-settings PHY
+       print "${PHY}"
+}
+
+function port_uses_phy() {
+       assert [ $# -eq 2 ]
+
+       local port="${1}"
+       local phy="${2}"
+
+       # Nothing to do if an empty argument is given
+       if ! isset phy; then
+               return ${EXIT_FALSE}
+       fi
+
+       phy="$(phy_get_address "${phy}")"
+
+       local port_phy="$(port_get_phy "${port}")"
+       [ "${port_phy}" = "${phy}" ]
+}
index 179656ea505fdecfe450b6d020b422477a1ebffd..f627d99dd0c779cca3efc1180ec45ba752cd983a 100644 (file)
@@ -356,6 +356,11 @@ function cmd_not_implemented() {
        assert false "not implemented"
 }
 
+# Increase security of the read command
+function read() {
+       builtin read -r $@
+}
+
 function seq() {
        if [ $# -eq 2 ]; then
                eval echo {${1}..${2}}
index 418c851c3fc19f725e73e09b3c7b9f18ed0cf53b..15e8a96f120a673727dd0059adebbe8d4ea30848 100644 (file)
@@ -100,22 +100,16 @@ function hook_up() {
 
        port_settings_read "${port}" ${HOOK_SETTINGS}
 
-       # This cannot be started manually, but is created automatically
-       # when a slave device is brought up and set up by _hotplug.
+       # Create batman device if it does not exist, yet.
+       if ! device_exists "${port}"; then
+               batman_adv_add "${port}"
+       fi
 
-       local slave
-       for slave in ${SLAVES}; do
-               port_up "${slave}"
-       done
+       # Set the address.
+       device_set_address "${port}" "${ADDRESS}"
 
-       # If the port has been created (does not happen, when there are
-       # no slaves), we bring it up.
-       if device_exists "${port}"; then
-               # Set the address.
-               device_set_address "${port}" "${ADDRESS}"
-
-               device_set_up "${port}"
-       fi
+       # Bring up the port
+       device_set_up "${port}"
 
        exit ${EXIT_OK}
 }
@@ -131,21 +125,66 @@ function hook_down() {
                port_down "${slave}"
        done
 
+       # Remove the batman device
+       device_exists "${port}" && batman_adv_delete "${port}"
+
        exit ${EXIT_OK}
 }
 
-#function hook_hotplug() {
-#      local port=${1}
-#      assert isset port
-#
-#      local phy=${2}
-#      assert isset phy
-#
-#      # Bring up the device.
-#      port_up "${port}"
-#
-#      exit ${EXIT_OK}
-#}
+function hook_hotplug() {
+       local port="${1}"
+       assert isset port
+
+       case "$(hotplug_action)" in
+               add)
+                       # Don't handle this event if the batman
+                       # device has not been started, yet.
+                       #if ! device_exists "${port}"; then
+                       #       exit ${EXIT_NOT_HANDLED}
+                       #fi
+
+                       # Handle events of the same interface
+                       if hotplug_event_port_is_interface "${port}"; then
+                               # Read configuration
+                               port_settings_read "${port}"
+
+                               # Bring up all slaves
+                               # They will be attached by their own hotplug event
+                               local slave
+                               for slave in ${SLAVES}; do
+                                       if port_exists "${slave}"; then
+                                               port_up "${slave}"
+                                       fi
+                               done
+
+                               exit ${EXIT_OK}
+
+                       # Handle slave devices that have just been created and
+                       # attach them.
+                       elif hotplug_event_port_is_slave "${port}"; then
+                               device_exists "${port}" || port_up "${port}"
+
+                               batman_adv_attach "${port}" "${INTERFACE}"
+                       fi
+
+                       exit ${EXIT_OK}
+                       ;;
+
+               remove)
+                       # Bring down all slaves when the batman device went down
+                       local slave
+                       for slave in ${SLAVES}; do
+                               port_down "${slave}"
+                       done
+
+                       exit ${EXIT_OK}
+                       ;;
+
+               *)
+                       exit ${EXIT_NOT_HANDLED}
+                       ;;
+       esac
+}
 
 function hook_status() {
        local port=${1}
similarity index 72%
rename from src/hooks/ports/batman-adv-port
rename to src/hooks/ports/wireless-adhoc
index 4e8ffb127cd172c6fc329f4f8706544b8427d993..515c9057e277037871ac9c384b1f676d98871319 100644 (file)
 
 . /usr/lib/network/header-port
 
-HOOK_SETTINGS="HOOK ADDRESS MESH_ID SSID CHANNEL PHY"
+HOOK_SETTINGS="HOOK ADDRESS BSSID SSID CHANNEL MTU PHY"
 
 ADDRESS=$(mac_generate)
+BSSID=
 CHANNEL=1
-MESH_ID=
+MTU=1500
 PHY=
 SSID=
 
-# batman-adv inserts an additional header of 28 bytes, so we set the MTU
-# to 1560, that normal ethernet packets with 1500 bytes can pass the network.
-MTU=1560
-
 function hook_check() {
        assert isset ADDRESS
        assert ismac ADDRESS
        assert isset CHANNEL
-       assert isset MESH_ID
-       assert ismac MESH_ID
+       assert isset BSSID
+       assert ismac BSSID
        assert isset PHY
        assert ismac PHY
        assert isset SSID
@@ -50,18 +47,21 @@ function hook_create() {
                        --address=*)
                                ADDRESS=$(cli_get_val ${1})
                                ;;
+                       --bssid=*)
+                               BSSID=$(cli_get_val ${1})
+                               ;;
                        --channel=*)
                                CHANNEL=$(cli_get_val ${1})
                                ;;
+                       --mtu=*)
+                               MTU="$(cli_get_val "${1}")"
+                               ;;
                        --phy=*)
                                PHY=$(cli_get_val ${1})
                                ;;
                        --ssid=*)
                                SSID=$(cli_get_val ${1})
                                ;;
-                       --mesh-id=*)
-                               MESH_ID=$(cli_get_val ${1})
-                               ;;
                        *)
                                warning "Ignoring unknown argument '${1}'"
                                ;;
@@ -73,7 +73,7 @@ function hook_create() {
        PHY=$(phy_get ${PHY})
        PHY=$(phy_get_address ${PHY})
 
-       local port=$(port_find_free ${PORT_PATTERN_BATMAN_ADV_PORT})
+       local port=$(port_find_free ${PORT_PATTERN_WIRELESS_ADHOC})
        assert isset port
 
        port_settings_write "${port}" ${HOOK_SETTINGS}
@@ -90,11 +90,14 @@ function hook_edit() {
 
        while [ $# -gt 0 ]; do
                case "${1}" in
+                       --bssid=*)
+                               BSSID=$(cli_get_val ${1})
+                               ;;
                        --channel=*)
                                CHANNEL=$(cli_get_val ${1})
                                ;;
-                       --mesh-id=*)
-                               MESH_ID=$(cli_get_val ${1})
+                       --mtu=*)
+                               MTU="$(cli_get_val "${1}")"
                                ;;
                        --ssid=*)
                                SSID=$(cli_get_val ${1})
@@ -126,71 +129,62 @@ function hook_up() {
 
        # Create the wireless device, if it does not exist, yet.
        if ! device_exists ${port}; then
-               wireless_create ${port} \
-                       --address="${ADDRESS}" \
-                       --phy="${phy}" \
-                       --type="ibss"
-       fi
-
-       # Set the MTU.
-       device_set_mtu "${port}" "${MTU}"
-
-       # Join the ad-hoc network.
-       wireless_ibss_join "${port}" --channel="${CHANNEL}" \
-               --bssid="${MESH_ID}" --essid="${SSID}"
-
-       # Add the device as a batman-adv device.
-       local parent="$(hook_find_parent ${port})"
-       if isset parent; then
-               batman_adv_interface_add "${parent}" "${port}"
+               wireless_create ${port} --address="${ADDRESS}" \
+                       --phy="${phy}" --type="ibss"
        fi
 
        exit ${EXIT_OK}
 }
 
 function hook_down() {
-       local port=${1}
+       local port="${1}"
        assert isset port
 
-       # Remove the batman-adv device.
-       batman_adv_interface_del "${port}"
+       # Do nothing if the device already went away
+       if ! device_exists "${port}"; then
+               exit ${EXIT_OK}
+       fi
 
        # Leave the ad-hoc network.
        wireless_ibss_leave "${port}"
 
        # Remove the device if it is still present.
-       if device_exists ${port}; then
-               wireless_remove ${port}
-       fi
+       wireless_remove "${port}"
 
        exit ${EXIT_OK}
 }
 
 function hook_hotplug() {
-       local port=${1}
+       local port="${1}"
        assert isset port
 
-       local phy=${2}
-       assert isset phy
-
-       assert port_exists ${port}
-
-       # Read configuration of port.
        port_settings_read "${port}" ${HOOK_SETTINGS}
 
-       # Get the address of the phy.
-       local phy_address=$(phy_get_address "${phy}")
+       case "$(hotplug_action)" in
+               add)
+                       # Join the adhoc network after the device has
+                       # been created...
+                       if hotplug_event_port_is_interface "${port}"; then
+                               # Set the MTU.
+                               if isinteger MTU; then
+                                       device_set_mtu "${port}" "${MTU}"
+                               fi
+
+                               wireless_ibss_join "${port}" --channel="${CHANNEL}" \
+                                       --bssid="${BSSID}" --essid="${SSID}"
+
+                       # Bring up the port when the phy is plugged in
+                       elif hotplug_event_port_uses_phy "${port}"; then
+                               hook_up "${port}"
+                       fi
+                       ;;
+
+               *)
+                       exit ${EXIT_NOT_HANDLED}
+                       ;;
+       esac
 
-       # Check if the phy is the same we have
-       # read from the configuration file.
-       if [ "${PHY}" = "${phy_address}" ]; then
-               # Bring up the device.
-               port_up "${port}"
-
-               exit ${EXIT_OK}
-       fi
-
-       exit ${EXIT_NOT_HANDLED}
+       exit ${EXIT_OK}
 }
 
 function hook_find_parent() {
index 8a0f81c8a076d819739d3ecafe215130716d2b23..4983f9c268b4122c0b5daa60addd0bb5cdbdeca7 100644 (file)
@@ -159,7 +159,7 @@ function hook_up() {
        fi
 
        # Start the hostapd service.
-       hostapd_start ${port}
+       #hostapd_start ${port}
        local ret=$?
 
        if [ ${ret} -ne ${EXIT_OK} ]; then
@@ -174,37 +174,41 @@ function hook_down() {
        local port=${1}
        assert isset port
 
-       # Stop the hostapd daemon.
-       hostapd_stop ${port}
-
-       # Remove the device if it is still present.
-       if device_exists ${port}; then
-               wireless_remove ${port}
+       # Remove the device if present
+       if device_exists "${port}"; then
+               wireless_remove "${port}"
        fi
 
        exit ${EXIT_OK}
 }
 
 function hook_hotplug() {
-       local port=${1}
+       local port="${1}"
        assert isset port
 
-       local phy=${2}
-       assert isset phy
-
-       assert port_exists ${port}
-
-       # Read configuration of port.
-       port_settings_read "${port}" ${HOOK_SETTINGS}
+       case "$(hotplug_action)" in
+               add)
+                       # Start hostapd after the port has been brought up
+                       if hotplug_event_port_is_interface "${port}"; then
+                               hostapd_start "${port}"
+
+                       # Bring up the port when the phy is plugged in
+                       elif hotplug_event_port_uses_phy "${port}"; then
+                               hook_up "${port}"
+                       fi
+                       ;;
+
+               remove)
+                       # Stop hostapd
+                       if hotplug_event_port_is_interface "${port}"; then
+                               hostapd_stop "${port}"
+                       fi
+                       ;;
+
+               *)
+                       exit ${EXIT_NOT_HANDLED}
+                       ;;
+       esac
 
-       # Get the address of the phy.
-       local phy_address=$(phy_get_address ${phy})
-
-       # Check if the phy is the same we have
-       # read from the configuration file.
-       if [ "${PHY}" = "${phy_address}" ]; then
-               hook_up "${port}"
-       fi
-
-       exit ${EXIT_NOT_HANDLED}
+       exit ${EXIT_OK}
 }
index 0690066eae3411b474f7a6611a7764f8d9c44370..416a9ff1e3675c87f75c9a784590c74b2434a268 100644 (file)
 #                                                                             #
 ###############################################################################
 
+IN_HOTPLUG_EVENT=1
+
+# Setup logging.
+LOG_FACILITY="network-hotplug"
+
 . /usr/lib/network/functions
 
 # Read network settings
 network_settings_read
 
-# Setup logging.
-LOG_FACILITY="network-hotplug"
-
-log DEBUG "Called with ACTION='${ACTION}', INTERFACE='${INTERFACE}'."
+log DEBUG "Called with SUBSYSTEM='${SUBSYSTEM}', ACTION='${ACTION}'"
 
 # Check if the udev environment variables are properly set.
 assert isset ACTION
-assert isset INTERFACE
 
-# Check, if the device is a physical network interface and
-# if we can handle it.
-if device_exists ${INTERFACE}; then
-       # Skip wireless monitor devices
-       if device_is_wireless_monitor "${INTERFACE}"; then
-               exit ${EXIT_OK}
-       fi
+case "${SUBSYSTEM}" in
+       ieee80211)
+               PHY="$(basename "${DEVPATH}")"
+               if phy_exists "${PHY}"; then
+                       PHY_ADDRESS="$(phy_get_address "${PHY}")"
+                       log DEBUG "  PHY='${PHY}', PHY_ADDRESS='${PHY_ADDRESS}'"
+               else
+                       PHY=""
+               fi
 
-       type="$(device_get_type "${INTERFACE}")"
-       case "${type}" in
-               # Remove automatically created bonding interface without any configuration
-               bonding)
-                       port_exists "${INTERFACE}" || bonding_remove "${INTERFACE}"
-                       exit ${EXIT_OK}
-                       ;;
-               ethernet)
-                       log DEBUG "Called for interface '${INTERFACE}' which is a virtual interface. Exiting."
-                       exit ${EXIT_OK}
-                       ;;
-       esac
-fi
+               # Propagate the hotplug event to all configured port hooks
+               hotplug_propagate_all_ports || exit ${EXIT_ERROR}
+               ;;
+
+       net)
+               assert isset INTERFACE
 
-case "${ACTION}" in
-       add|register)
-               # Handle hotplug events for zones.
+               # Don't do anything for zones
                if zone_exists "${INTERFACE}"; then
-                       # TODO When e.g. a wireless device is plugged in,
-                       # the right zone needs to be searched and started.
                        exit ${EXIT_OK}
+               fi
 
-               # Check, if there is a port configuration for that device.
-               elif port_exists ${INTERFACE}; then
-                       port=${INTERFACE}
+               # Get the internal type of the device for later processing
+               TYPE="$(device_get_type "${INTERFACE}")"
 
-               # Create new configuration for _real_ network devices.
-               else
-                       type=$(device_get_type ${INTERFACE})
-                       case "${type}" in
-                               # If the given device was not configured,
-                               # we create an initial configuration.
-                               ethernet|real)
-                                       port_create ethernet ${INTERFACE}
-                                       ;;
-
-                               # Handle batman-adv and wireless devices.
-                               batman-adv|batman-adv-port|wireless)
-                                       # Load regulatory domain for wireless devices
-                                       wireless_init_reg_domain
-
-                                       # Save the phy of this device for later.
-                                       phy=$(phy_get ${INTERFACE})
-                                       assert isset phy
-
-                                       # Remove the unconfigured wireless device.
-                                       wireless_remove ${INTERFACE}
-
-                                       # Create configured child devices.
-                                       for port in $(ports_get_all); do
-                                               port_cmd hotplug "${port}" "${phy}"
-                                               ret=$?
-
-                                               case "${ret}" in
-                                                       ${EXIT_OK})
-                                                               log DEBUG "phy '${phy}' was handled by port '${port}'"
-                                                               ;;
-                                                       ${EXIT_NOT_HANDLED})
-                                                               : # do nothing
-                                                               ;;
-                                                       *)
-                                                               log WARNING "Unknown exit code for port '${port}': ${ret}"
-                                                               ;;
-                                               esac
-                                       done
-                                       ;;
-
-                               # Do nothing for all the rest.
-                               *)
-                                       log DEBUG "Don't create a port configuration for device '${INTERFACE}' of type '${type}'."
-                                       ;;
-                       esac
+               log DEBUG "  INTERFACE='${INTERFACE}', TYPE='${TYPE}'"
+
+               # Stop processing rules for wireless monitoring devices
+               if device_is_wireless_monitor "${INTERFACE}"; then
                        exit ${EXIT_OK}
                fi
 
-               # Check, if the device is configured in a zone.
-               # If not, there is nothing to do.
-               zone=$(port_zone "${port}")
-               if isset zone; then
-                       zone_hotplug_event "${zone}"
-                       exit ${?}
+               # Handle special cases like removing automatically created
+               # devices that we don't want
+               case "${ACTION},${TYPE}" in
+                       # Bonding
+                       add,bonding)
+                               # Remove bonding devices without configuration
+                               if ! port_exists "${INTERFACE}"; then
+                                       bonding_remove "${INTERFACE}"
+                                       exit ${EXIT_OK}
+                               fi
+                               ;;
+
+                       # Ethernet
+                       add,ethernet)
+                               # Create a default port for all ethernet devices
+                               if ! port_exists "${INTERFACE}"; then
+                                       port_create "ethernet" "${INTERFACE}"
+                                       exit ${EXIT_OK}
+                               fi
+                               ;;
+
+                       # Wireless devices
+                       add,wireless)
+                               # Remove wireless devices without configuration
+                               if ! port_exists "${INTERFACE}"; then
+                                       wireless_remove "${INTERFACE}"
+                                       exit ${EXIT_OK}
+                               fi
+
+                               # Load regulatory domain for wireless devices
+                               wireless_init_reg_domain
+                               ;;
+
+                       # Don't propagate removal events for ports that don't exist
+                       remove,*)
+                               if ! port_exists "${INTERFACE}"; then
+                                       exit ${EXIT_OK}
+                               fi
+                               ;;
+               esac
+
+               if ! port_exists "${INTERFACE}"; then
+                       log ERROR "Got to hotplug event for a port which does not exist: ${INTERFACE}"
+                       exit ${EXIT_ERROR}
                fi
+
+               # Propagate the hotplug event to all configured port hooks
+               hotplug_propagate_all_ports || exit ${EXIT_ERROR}
+
+               # Check, if the device is configured in a zone.
+               # If so, propagate the event to the zone, too.
+               case "${ACTION}" in
+                       add)
+                               zone="$(port_zone "${INTERFACE}")"
+                               if isset zone; then
+                                       zone_hotplug_event "${zone}" || exit ${EXIT_ERROR}
+                               fi
+                               ;;
+               esac
+
+               exit ${EXIT_OK}
                ;;
 
-       remove|unregister)
-               # After the interface has been removed/unplugged,
-               # there are often daemons (like hostapd) which need
-               # to be stopped.
-               port_exists ${INTERFACE} && port_down ${INTERFACE}
+       *)
+               log ERROR "Called for an unsupported subsystem: ${SUBSYSTEM}"
+               exit ${EXIT_ERROR}
                ;;
 esac
 
-exit ${EXIT_OK}
+exit ${EXIT_NOT_HANDLED}
index 78d6963b08bbdca5be8672d544d27b9d76c16faa..27580cbdda34279bc768115787aa89a08e7b3ad1 100644 (file)
@@ -5,7 +5,7 @@
 ACTION=="add", SUBSYSTEM=="net", PROGRAM="/usr/lib/udev/network-hotplug-rename", RESULT=="?*", NAME="$result"
 
 # Handle all plugged-in devices.
-SUBSYSTEM=="net", RUN+="/usr/lib/udev/network-hotplug"
+ACTION=="add|remove", SUBSYSTEM=="net|ieee80211", RUN+="/usr/lib/udev/network-hotplug"
 
 # Handle all serial devices (like modems and so on...).
 KERNEL=="ttyUSB*", ENV{NETWORK_USB_SERIAL_DEVICE_IGNORE}!="1", RUN+="/usr/lib/udev/network-hotplug-serial"