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 \
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 = \
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
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
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"
[ -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
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
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"
--- /dev/null
+#!/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}"
+}
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
+}
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}" ]
+}
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}}
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}
}
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}
. /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
--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}'"
;;
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}
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})
# 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() {
fi
# Start the hostapd service.
- hostapd_start ${port}
+ #hostapd_start ${port}
local ret=$?
if [ ${ret} -ne ${EXIT_OK} ]; then
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}
}
# #
###############################################################################
+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}
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"