]> git.ipfire.org Git - people/ms/network.git/blobdiff - src/network
network: Show when a PHY supports ACS
[people/ms/network.git] / src / network
index eccf2f43c9990101173a61e0b95b89c0694d91ef..3535133d586434695fcde2689da6bd68734559e7 100644 (file)
@@ -38,64 +38,77 @@ done
 # Read network settings
 network_settings_read
 
-function cli_settings() {
-       if cli_help_requested $@; then
+cli_settings() {
+       if cli_help_requested "$@"; then
                cli_show_man network-settings
                exit ${EXIT_OK}
        fi
 
        if [ -n "${1}" ]; then
-               settings_set $@
+               network_settings_set "$@"
                network_settings_write
        else
                network_settings_print
        fi
 }
 
-function cli_device() {
-       if cli_help_requested $@; then
+cli_device() {
+       if cli_help_requested "$@"; then
                cli_show_man network-device
                exit ${EXIT_OK}
        fi
 
-       local device=${1}
-       local action=${2}
-       shift 2
-
-       if ! isset device; then
-               cli_show_man network-device
-               return ${EXIT_ERROR}
-       fi
-
-       assert device_exists ${device}
+       local action="${1}"
+       shift
 
        case "${action}" in
-               discover)
-                       cli_device_discover ${device} $@
-                       ;;
-               monitor)
-                       cli_device_monitor "${device}" $@
-                       ;;
-               status)
-                       cli_device_status ${device}
-                       ;;
-               unlock)
-                       cli_device_serial_unlock ${device} $@
-                       ;;
-               ussd)
-                       cli_device_send_ussd_command "${device}" $@
+               list)
+                       cli_device_list "$@"
                        ;;
                *)
-                       cli_show_man network-device
+                       local device="${action}"
+                       action="${1}"
+                       shift
+
+                       if ! isset device; then
+                               cli_show_man network-device
+                               return ${EXIT_ERROR}
+                       fi
+
+                       assert device_exists ${device}
+
+                       case "${action}" in
+                               discover)
+                                       cli_device_discover ${device} "$@"
+                                       ;;
+                               identify)
+                                       device_identify "${device}" "$@"
+                                       ;;
+                               monitor)
+                                       cli_device_monitor "${device}" "$@"
+                                       ;;
+                               status)
+                                       cli_device_status ${device}
+                                       ;;
+                               unlock)
+                                       cli_device_serial_unlock ${device} "$@"
+                                       ;;
+                               ussd)
+                                       cli_device_send_ussd_command "${device}" "$@"
+                                       ;;
+                               *)
+                                       cli_show_man network-device
+                                       ;;
+                       esac
                        ;;
        esac
 
        return ${EXIT_OK}
 }
 
-function cli_device_status() {
-       local device=${1}
-       assert device_exists ${device}
+cli_device_status() {
+       local device="${1}"
+       assert isset device
 
        # Disable debugging output here.
        local log_disable_stdout=${LOG_DISABLE_STDOUT}
@@ -107,11 +120,17 @@ function cli_device_status() {
        cli_headline 1 "Device status: ${device}"
        cli_print_fmt1 1 "Name"         "${device}"
 
-       # Handle serial devices.
-       if [ "${type}" = "serial" ]; then
-               cli_device_status_serial ${device}
-               return $?
-       fi
+       # Handle special devices
+       case "${type}" in
+               phy)
+                       cli_device_status_phy "${device}"
+                       return $?
+                       ;;
+               serial)
+                       cli_device_status_serial "${device}"
+                       return $?
+                       ;;
+       esac
 
        # Print the device status.
        device_is_up ${device} &>/dev/null
@@ -128,6 +147,17 @@ function cli_device_status() {
 
        cli_print_fmt1 1 "Status"       "${status}"
        cli_print_fmt1 1 "Type"         "${type}"
+
+       # Print the driver name
+       local driver="$(device_get_driver "${device}")"
+       if isset driver; then
+               cli_print_fmt1 1 "Driver" "${driver}"
+       fi
+
+       # Ethernet-compatible?
+       device_is_ethernet_compatible "${device}" &>/dev/null
+       cli_print_fmt1 1 "Ethernet-compatible" "$(cli_print_bool $?)"
+
        cli_print_fmt1 1 "Address"      "$(device_get_address ${device})"
        cli_space
 
@@ -151,8 +181,15 @@ function cli_device_status() {
 
        device_is_promisc ${device} &>/dev/null
        cli_print_fmt1 1 "Promisc"      "$(cli_print_bool $?)"
+
+       # Supports multiqueue?
+       if device_supports_multiqueue ${device}; then
+               cli_print_fmt1 1 "Multiqueue" "Supported"
+       fi
        cli_space
 
+       cli_device_show_queues 2 ${device}
+
        # Print all vlan devices.
        local vlans=$(device_get_vlans ${device})
        if [ -n "${vlans}" ]; then
@@ -165,11 +202,23 @@ function cli_device_status() {
                cli_space
        fi
 
+       case "${type}" in
+               wireless*)
+                       local phy="$(device_get_phy "${device}")"
+                       if isset phy; then
+                               cli_headline 2 "PHY"
+                               cli_print_fmt1 2 "Name" "${phy}"
+                               cli_print_fmt1 2 "Address" "$(phy_get_address "${phy}")"
+                               cli_space
+                       fi
+                       ;;
+       esac
+
        # Reset the logging level.
        LOG_DISABLE_STDOUT=${log_disable_stdout}
 }
 
-function cli_device_status_serial() {
+cli_device_status_serial() {
        local device=${1}
        assert device_is_serial ${device}
 
@@ -189,53 +238,63 @@ function cli_device_status_serial() {
        cli_print_fmt1 1 "Software version" \
                "$(modem_get_software_version ${device})"
 
-       if modem_is_mobile ${device}; then
+       # Mobile
+       if modem_is_mobile "${device}"; then
                cli_print_fmt1 1 "IMEI" \
                        "$(modem_get_device_imei ${device})"
+       fi
+       cli_space
+
+       if modem_is_mobile "${device}"; then
+               modem_mobile_network_status "${device}" 2
                cli_space
+       fi
+}
 
-               cli_headline 2 "Network status"
-               modem_sim_status ${device} &>/dev/null
-               local sim_status_code=$?
+cli_device_status_phy() {
+       local phy="${1}"
+       assert phy_exists "${phy}"
 
-               local sim_status="unknown"
-               case "${sim_status_code}" in
-                       ${EXIT_SIM_READY})
-                               sim_status="SIM ready"
-                               ;;
-                       ${EXIT_SIM_PIN})
-                               sim_status="PIN locked"
-                               ;;
-                       ${EXIT_SIM_PUK})
-                               sim_status="PUK locked"
-                               ;;
-               esac
-               cli_print_fmt1 2 "SIM status" "${sim_status}"
-
-               if [ ${sim_status_code} -eq ${EXIT_SIM_READY} ]; then
-                       cli_print_fmt1 2 "IMSI" \
-                               "$(modem_get_sim_imsi ${device})"
-                       cli_print_fmt1 2 "Operator" \
-                               "$(modem_get_network_operator ${device})"
-                       cli_print_fmt1 2 "Mode" \
-                               "$(modem_get_network_mode ${device})"
-                       cli_print_fmt1 2 "Signal quality" \
-                               "$(modem_get_signal_quality ${device}) dBm"
-
-                       local ber=$(modem_get_bit_error_rate ${device})
-                       isset ber || ber="unknown"
-                       cli_print_fmt1 2 "Bit Error Rate" "${ber}"
-               fi
+       local address="$(phy_get_address "${phy}")"
+       cli_print_fmt1 1 "Address" "${address}"
+
+       # Show kernel module
+       local driver="$(phy_get_driver "${phy}")"
+       if isset driver; then
+               cli_print_fmt1 1 "Driver" "${driver}"
        fi
+
        cli_space
+
+       local devices="$(phy_get_devices "${phy}")"
+       if isset devices; then
+               cli_headline 2 "Soft interfaces"
+
+               local device
+               for device in ${devices}; do
+                       cli_print 2 "* %s" "${device}"
+               done
+               cli_space
+       fi
+
+       cli_headline 2 "Features"
+
+       cli_print_fmt1 2 "Automatic Channel Selection" \
+               "$(phy_supports_acs "${phy}" && print "Supported" || print "Not Supported")"
+       cli_print_fmt1 2 "DFS" \
+               "$(phy_supports_dfs "${phy}" && print "Supported" || print "Not Supported")"
+
+       cli_space
+
+       return ${EXIT_OK}
 }
 
-function cli_device_discover() {
+cli_device_discover() {
        local device=${1}
        shift
 
-       local device_type=$(device_get_type ${device})
-       if [ "${device_type}" != "real" ]; then
+       # This can only be executed for ethernet (or compatible) devices
+       if ! device_is_ethernet_compatible "${device}"; then
                return ${EXIT_OK}
        fi
 
@@ -301,8 +360,8 @@ function cli_device_discover() {
        [ "${up}" = "1" ] || device_set_down ${device}
 }
 
-function cli_device_serial_unlock() {
-       if cli_help_requested $@; then
+cli_device_serial_unlock() {
+       if cli_help_requested "$@"; then
                cli_show_man network-device
                exit ${EXIT_OK}
        fi
@@ -387,7 +446,7 @@ function cli_device_serial_unlock() {
        exit $?
 }
 
-function cli_device_send_ussd_command() {
+cli_device_send_ussd_command() {
        local device="${1}"
        assert isset device
        shift
@@ -422,7 +481,7 @@ function cli_device_send_ussd_command() {
        exit $?
 }
 
-function cli_device_monitor() {
+cli_device_monitor() {
        local device="${1}"
        assert isset device
 
@@ -435,8 +494,17 @@ function cli_device_monitor() {
        exit $?
 }
 
-function cli_hostname() {
-       if cli_help_requested $@; then
+cli_device_list() {
+       local device
+       for device in $(device_list); do
+               cli_device_status "${device}"
+       done
+
+       exit ${EXIT_OK}
+}
+
+cli_hostname() {
+       if cli_help_requested "$@"; then
                cli_show_man network
                exit ${EXIT_OK}
        fi
@@ -454,8 +522,8 @@ function cli_hostname() {
        exit ${EXIT_OK}
 }
 
-function cli_port() {
-       if cli_help_requested $@; then
+cli_port() {
+       if cli_help_requested "$@"; then
                cli_show_man network-port
                exit ${EXIT_OK}
        fi
@@ -469,8 +537,14 @@ function cli_port() {
                shift 2
 
                case "${action}" in
-                       edit|create|remove|up|down|status)
-                               port_${action} "${port}" $@
+                       edit|create|remove|up|down|status|identify)
+                               port_${action} "${port}" "$@"
+                               ;;
+                       color)
+                               color_cli "port" "${port}" "$@"
+                               ;;
+                       description)
+                               description_cli "port" "${port}" "$@"
                                ;;
                        *)
                                error "Unrecognized argument: ${action}"
@@ -483,7 +557,7 @@ function cli_port() {
 
                case "${action}" in
                        new|destroy)
-                               port_${action} $@
+                               port_${action} "$@"
                                ;;
                        *)
                                error "Unrecognized argument: ${action}"
@@ -493,8 +567,8 @@ function cli_port() {
        fi
 }
 
-function cli_zone() {
-       if cli_help_requested $@; then
+cli_zone() {
+       if cli_help_requested "$@"; then
                cli_show_man network-zone
                exit ${EXIT_OK}
        fi
@@ -502,7 +576,7 @@ function cli_zone() {
        local action
        local zone
 
-       if zone_name_is_valid ${1}; then
+       if zone_exists ${1}; then
                zone=${1}
                action=${2}
                shift 2
@@ -521,8 +595,20 @@ function cli_zone() {
                esac
 
                case "${action}" in
-                       config|disable|down|edit|enable|port|status|up)
-                               zone_${action} ${zone} $@
+                       port)
+                               cli_zone_port "${zone}" "$@"
+                               ;;
+                       rename)
+                               cli_zone_rename "${zone}" "$@"
+                               ;;
+                       config|disable|down|edit|enable|identify|status|up)
+                               zone_${action} ${zone} "$@"
+                               ;;
+                       color)
+                               color_cli "zone" "${zone}" "$@"
+                               ;;
+                       description)
+                               description_cli "zone" ${zone} "$@"
                                ;;
                        *)
                                error "Unrecognized argument: ${action}"
@@ -535,14 +621,11 @@ function cli_zone() {
                shift
 
                case "${action}" in
-                       create)
-                               zone_${action} $@
+                       new)
+                               cli_zone_new "$@"
                                ;;
-                       remove)
-                               cli_zone_remove $@
-                               ;;
-                       list-hooks)
-                               cli_list_hooks zone $@
+                       destroy)
+                               cli_zone_destroy "$@"
                                ;;
                        ""|*)
                                if [ -n "${action}" ]; then
@@ -557,34 +640,126 @@ function cli_zone() {
        fi
 }
 
+cli_zone_new() {
+       if cli_help_requested "$@" || [ $# -lt 2 ]; then
+               cli_show_man network-zone-new
+               exit ${EXIT_OK}
+       fi
+
+       zone_new "$@"
+}
+
 # Removes a zone either immediately, if it is currently down,
 # or adds a tag that the removal will be done when the zone
 # is brought down the next time.
-function cli_zone_remove() {
-       if cli_help_requested $@; then
+cli_zone_destroy() {
+       if cli_help_requested "$@"; then
                cli_show_man network-zone
                exit ${EXIT_OK}
        fi
 
-       local zone=${1}
-       assert zone_exists ${zone}
+       local zone="${1}"
+
+       # Check if the zone exists
+       if ! zone_exists "${zone}"; then
+               error "Zone '${zone}' does not exist"
+               return ${EXIT_ERROR}
+       fi
+
+       echo "Removing zone '${zone}'..."
+       zone_destroy "${zone}" || exit $?
+}
+
+cli_zone_port() {
+       if cli_help_requested "$@"; then
+               cli_show_man network-zone-port
+               exit ${EXIT_OK}
+       fi
+
+       local zone="${1}"
+       assert zone_exists "${zone}"
+
+       if port_exists "${2}"; then
+               local port="${2}"
+               local action="${3}"
+               shift 3
 
-       if zone_is_up ${zone}; then
-               echo "Zone '${zone}' is up and will be removed when it goes down the next time."
-               zone_remove ${zone}
+               case "${action}" in
+                       edit)
+                               zone_port_edit "${zone}" "${port}" "$@"
+                               ;;
+                       *)
+                               error "Unrecognised argument: ${action}"
+                               exit ${EXIT_ERROR}
+                               ;;
+               esac
        else
-               echo "Removing zone '${zone}' now..."
-               zone_remove_now ${zone}
+               local action="${2}"
+               shift 2
+
+               case "${action}" in
+                       attach)
+                               zone_port_attach "${zone}" "$@"
+                               ;;
+                       detach)
+                               zone_port_detach "${zone}" "$@"
+                               ;;
+                       *)
+                               error "Unrecognised argument: ${action}"
+                               exit ${EXIT_ERROR}
+                               ;;
+               esac
+       fi
+
+       exit ${EXIT_OK}
+}
+
+cli_zone_rename() {
+       if cli_help_requested "$@"; then
+               cli_show_man network-zone
+               exit ${EXIT_OK}
+       fi
+
+       local zone="${1}"
+       local name="${2}"
+       shift 2
+
+       if ! isset name; then
+               error "You need to pass a new name"
+               exit ${EXIT_ERROR}
+       fi
+
+       if ! zone_name_is_valid "${name}"; then
+               error "Invalid new zone name: ${name}"
+               exit ${EXIT_ERROR}
+       fi
+
+       # Check if the zone exists
+       if ! zone_exists "${zone}"; then
+               error "Zone ${zone} does not exist"
+               exit ${EXIT_ERROR}
+       fi
+
+       # Check if a zone with the new name already exists
+       if zone_exists "${name}"; then
+               error "Zone ${name} already exists"
+               exit ${EXIT_ERROR}
+       fi
+
+       # Rename
+       if ! zone_rename "${zone}" "${name}"; then
+               error "Could not rename zone ${zone} to ${name}"
+               exit ${EXIT_ERROR}
        fi
 
        exit ${EXIT_OK}
 }
 
-function cli_list_hooks() {
+cli_list_hooks() {
        local type=${1}
        shift
 
-       if cli_help_requested $@; then
+       if cli_help_requested "$@"; then
                cli_show_man network-zone
                exit ${EXIT_OK}
        fi
@@ -600,48 +775,11 @@ function cli_list_hooks() {
        done | sort -u
 }
 
-function cli_route() {
-       if cli_help_requested $@; then
-               cli_show_man network-route
-               exit ${EXIT_OK}
-       fi
-
-       local action=${1}
-       shift
-
-       case "${action}" in
-               # Add a new route.
-               add)
-                       route_add $@
-                       ;;
-               # Remove an existing route.
-               remove)
-                       route_remove $@
-                       ;;
-               # List all routes.
-               list)
-                       route_list $@
-                       return ${EXIT_OK}
-                       ;;
-               *)
-                       error "Unrecognized action: ${action}"
-                       cli_run_help network route
-
-                       exit ${EXIT_ERROR}
-                       ;;
-       esac
-
-       # Applying all routes.
-       route_apply
-
-       exit ${EXIT_OK}
-}
-
-function cli_dhcpd() {
+cli_dhcpd() {
        local proto=${1}
        shift
 
-       if cli_help_requested $@; then
+       if cli_help_requested "$@"; then
                cli_show_man network-dhcp
                exit ${EXIT_OK}
        fi
@@ -651,22 +789,28 @@ function cli_dhcpd() {
 
        case "${action}" in
                edit)
-                       dhcpd_edit ${proto} $@
+                       dhcpd_edit ${proto} "$@"
                        ;;
                start)
                        dhcpd_start ${proto}
+
+                       # Make this permanent
+                       dhcpd_enable ${proto}
                        ;;
                stop)
                        dhcpd_stop ${proto}
+
+                       # Make this permanent
+                       dhcpd_disable ${proto}
                        ;;
                restart|reload)
                        dhcpd_reload ${proto}
                        ;;
                subnet)
-                       cli_dhcpd_subnet ${proto} $@
+                       cli_dhcpd_subnet ${proto} "$@"
                        ;;
                show|"")
-                       cli_dhcpd_show ${proto} $@
+                       cli_dhcpd_show ${proto} "$@"
                        ;;
                *)
                        error "Unrecognized action: ${action}"
@@ -679,7 +823,7 @@ function cli_dhcpd() {
        exit ${EXIT_OK}
 }
 
-function cli_dhcpd_show() {
+cli_dhcpd_show() {
        local proto=${1}
        assert isset proto
 
@@ -695,11 +839,11 @@ function cli_dhcpd_show() {
                ipv6)
                        cli_headline 2 "Lease times"
                        if isinteger VALID_LIFETIME; then
-                               cli_print_fmt1 2 "Valid lifetime" "${VALID_LIFETIME}s"
+                               cli_print_fmt1 2 "Valid lifetime" "$(format_time ${VALID_LIFETIME})"
                        fi
 
                        if isinteger PREFERRED_LIFETIME; then
-                               cli_print_fmt1 2 "Preferred lifetime" "${PREFERRED_LIFETIME}s"
+                               cli_print_fmt1 2 "Preferred lifetime" "$(format_time ${PREFERRED_LIFETIME})"
                        fi
 
                        cli_space
@@ -709,11 +853,11 @@ function cli_dhcpd_show() {
                        cli_space
 
                        cli_headline 2 "Lease times"
-                       cli_print_fmt1 2 "Default lease time" "${DEFAULT_LEASE_TIME}s"
-                       cli_print_fmt1 2 "Max. lease time" "${MAX_LEASE_TIME}s"
+                       cli_print_fmt1 2 "Default lease time" "$(format_time ${DEFAULT_LEASE_TIME})"
+                       cli_print_fmt1 2 "Max. lease time" "$(format_time ${MAX_LEASE_TIME})"
 
                        if isset MIN_LEASE_TIME; then
-                               cli_print_fmt1 2 "Min. lease time" "${MIN_LEASE_TIME}s"
+                               cli_print_fmt1 2 "Min. lease time" "$(format_time ${MIN_LEASE_TIME})"
                        fi
 
                        cli_space
@@ -722,7 +866,7 @@ function cli_dhcpd_show() {
 
        # Read the options.
        local -A options
-       dhcpd_global_options_read ${proto} ${subnet_id}
+       dhcpd_global_options_read ${proto}
 
        # Print the options if any.
        if [ ${#options[*]} -gt 0 ]; then
@@ -742,18 +886,20 @@ function cli_dhcpd_show() {
        local subnets=$(dhcpd_subnet_list ${proto})
        if [ -n "${subnets}" ]; then
                cli_headline 2 "Subnets"
-               local subnet_id
-               for subnet_id in ${subnets}; do
-                       cli_dhcpd_subnet_show ${proto} ${subnet_id} 2
+               local subnet
+               for subnet in ${subnets}; do
+                       cli_dhcpd_subnet_show ${proto} ${subnet} 2
                done
        fi
 }
 
-function cli_dhcpd_subnet() {
+cli_dhcpd_subnet() {
+       assert [ $# -ge 1 ]
+
        local proto=${1}
        shift
 
-       if cli_help_requested $@; then
+       if cli_help_requested "$@"; then
                cli_show_man network-dhcp-subnet
                exit ${EXIT_OK}
        fi
@@ -763,16 +909,16 @@ function cli_dhcpd_subnet() {
 
        case "${action}" in
                new)
-                       dhcpd_subnet_new ${proto} $@
+                       dhcpd_subnet_new ${proto} "$@"
                        ;;
                remove)
-                       dhcpd_subnet_remove ${proto} $@
+                       dhcpd_subnet_remove ${proto} "$@"
                        ;;
-               [0-9]*)
-                       local subnet_id=${action}
+               *:*/*|*.*.*.*/*)
+                       local subnet=${action}
 
-                       if ! dhcpd_subnet_exists ${proto} ${subnet_id}; then
-                               error "The given subnet with ID ${subnet_id} does not exist."
+                       if ! dhcpd_subnet_exists ${proto} ${subnet}; then
+                               error "Subnet ${subnet} does not exist"
                                return ${EXIT_ERROR}
                        fi
 
@@ -782,7 +928,7 @@ function cli_dhcpd_subnet() {
 
                        case "${action}" in
                                edit)
-                                       dhcpd_subnet_edit ${proto} ${subnet_id} $@
+                                       dhcpd_subnet_edit ${proto} ${subnet} "$@"
                                        local ret=$?
 
                                        if [ ${ret} -eq ${EXIT_OK} ]; then
@@ -791,15 +937,15 @@ function cli_dhcpd_subnet() {
                                        exit ${ret}
                                        ;;
                                range)
-                                       cli_dhcpd_subnet_range ${proto} ${subnet_id} $@
+                                       cli_dhcpd_subnet_range ${proto} ${subnet} "$@"
                                        exit $?
                                        ;;
                                show)
-                                       cli_dhcpd_subnet_show ${proto} ${subnet_id} $@
+                                       cli_dhcpd_subnet_show ${proto} ${subnet} "$@"
                                        exit $?
                                        ;;
                                options)
-                                       cli_dhcpd_subnet_options ${proto} ${subnet_id} $@
+                                       cli_dhcpd_subnet_options ${proto} ${subnet} "$@"
                                        exit $?
                                        ;;
                                *)
@@ -810,9 +956,9 @@ function cli_dhcpd_subnet() {
                        esac
                        ;;
                show)
-                       local subnet_id
-                       for subnet_id in $(dhcpd_subnet_list ${proto}); do
-                               cli_dhcpd_subnet_show ${proto} ${subnet_id}
+                       local subnet
+                       for subnet in $(dhcpd_subnet_list ${proto}); do
+                               cli_dhcpd_subnet_show ${proto} ${subnet}
                        done
                        ;;
                *)
@@ -826,26 +972,20 @@ function cli_dhcpd_subnet() {
        exit ${EXIT_OK}
 }
 
-function cli_dhcpd_subnet_range() {
-       local proto=${1}
-       assert isset proto
-       shift
-
-       local subnet_id=${1}
-       assert isset subnet_id
-       shift
+cli_dhcpd_subnet_range() {
+       assert [ $# -ge 2 ]
 
-       local action=${1}
-       shift
+       local proto=${1}
+       local subnet=${2}
+       local action=${3}
+       shift 3
 
        case "${action}" in
                new)
-                       dhcpd_subnet_range_new ${proto} ${subnet_id} $@
-                       exit $?
+                       dhcpd_subnet_range_new ${proto} ${subnet} "$@" || exit ${EXIT_ERROR}
                        ;;
                remove)
-                       dhcpd_subnet_range_remove ${proto} ${subnet_id} $@
-                       exit $?
+                       dhcpd_subnet_range_remove ${proto} ${subnet} "$@" || exit ${EXIT_ERROR}
                        ;;
                *)
                        error "Unrecognized action: ${action}"
@@ -853,14 +993,16 @@ function cli_dhcpd_subnet_range() {
                        exit ${EXIT_ERROR}
                        ;;
        esac
+
+       dhcpd_reload ${proto}
+       return ${EXIT_OK}
 }
 
-function cli_dhcpd_subnet_show() {
-       local proto=${1}
-       assert isset proto
+cli_dhcpd_subnet_show() {
+       assert [ $# -ge 2 -a $# -le 3 ]
 
-       local subnet_id=${2}
-       assert isset subnet_id
+       local proto=${1}
+       local subnet=${2}
 
        local level=${3}
        isset level || level=0
@@ -868,24 +1010,23 @@ function cli_dhcpd_subnet_show() {
        local $(dhcpd_subnet_settings ${proto})
 
        # Read in configuration settings.
-       dhcpd_subnet_read ${proto} ${subnet_id}
+       dhcpd_subnet_read ${proto} ${subnet}
 
-       cli_headline $(( ${level} + 1 )) \
-               "DHCP${proto/ip/} subnet declaration #${subnet_id}"
+       cli_headline $(( ${level} + 1 )) "DHCP Subnet Declaration"
        cli_print_fmt1 $(( ${level} + 1 )) \
                "Subnet" "${ADDRESS}/${PREFIX}"
        cli_space
 
        # Read the options.
        local -A options
-       dhcpd_subnet_options_read ${proto} ${subnet_id}
+       dhcpd_subnet_options_read "${proto}" "${subnet}"
 
        # Print the options if any.
        if [ ${#options[*]} -gt 0 ]; then
                cli_headline $(( ${level} + 2 )) "Options"
 
                local option
-               for option in $(dhcpd_subnet_options ${proto}); do
+               for option in $(dhcpd_subnet_options_list ${proto}); do
                        [ -n "${options[${option}]}" ] || continue
 
                        cli_print_fmt1 $(( ${level} + 2 )) \
@@ -897,14 +1038,13 @@ function cli_dhcpd_subnet_show() {
        # Ranges.
        cli_headline $(( ${level} + 2 )) "Ranges"
 
-       local ranges=$(dhcpd_subnet_range_list ${proto} ${subnet_id})
+       local ranges=$(dhcpd_subnet_range_list ${proto} ${subnet})
        if isset ranges; then
-               local range_id $(dhcpd_subnet_range_settings ${proto})
-               for range_id in ${ranges}; do
-                       dhcpd_subnet_range_read ${proto} ${subnet_id} ${range_id}
+               local range $(dhcpd_subnet_range_settings ${proto})
+               for range in ${ranges}; do
+                       dhcpd_subnet_range_read ${proto} ${subnet} ${range}
 
-                       cli_print $(( ${level} + 2 )) \
-                               "#%d: %s - %s" ${range_id} ${START} ${END}
+                       cli_print $(( ${level} + 2 )) "%s - %s" ${START} ${END}
                done
        else
                cli_print $(( ${level} + 2 )) "No ranges have been defined."
@@ -913,36 +1053,32 @@ function cli_dhcpd_subnet_show() {
        cli_space
 }
 
-function cli_dhcpd_options() {
-       local proto=${1}
-       assert isset proto
-       shift
+cli_dhcpd_subnet_options() {
+       assert [ $# -ge 2 ]
 
-       local subnet_id=${1}
-       assert isset subnet_id
-       shift
-
-       local valid_options=$(dhcpd_subnet_options ${proto})
+       local proto=${1}
+       local subnet=${2}
 
        local key val
        while [ $# -gt 0 ]; do
                case "${1}" in
                        *=*)
                                key=$(cli_get_key ${1})
-                               val=$(cli_get_val ${1})
+                               val=$(cli_get_val "${1}")
 
-                               dhcpd_subnet_option_set ${proto} ${subnet_id} ${key} ${val}
+                               dhcpd_subnet_option_set ${proto} ${subnet} ${key} ${val}
                esac
+               shift
        done
 }
 
-function cli_start() {
-       if cli_help_requested $@; then
+cli_start() {
+       if cli_help_requested "$@"; then
                cli_show_man network
                exit ${EXIT_OK}
        fi
 
-       local zones=$(zones_get $@)
+       local zones=$(zones_get "$@")
 
        local zone
        for zone in ${zones}; do
@@ -952,13 +1088,13 @@ function cli_start() {
        wait # until everything is settled
 }
 
-function cli_stop() {
-       if cli_help_requested $@; then
+cli_stop() {
+       if cli_help_requested "$@"; then
                cli_show_man network
                exit ${EXIT_OK}
        fi
 
-       local zones=$(zones_get $@)
+       local zones=$(zones_get "$@")
 
        local zone
        for zone in ${zones}; do
@@ -968,22 +1104,22 @@ function cli_stop() {
        wait # until everything is settled
 }
 
-function cli_restart() {
-       if cli_help_requested $@; then
+cli_restart() {
+       if cli_help_requested "$@"; then
                cli_show_man network
                exit ${EXIT_OK}
        fi
 
-       cli_stop $@
+       cli_stop "$@"
 
        # Give the system some time to calm down
        sleep ${TIMEOUT_RESTART}
 
-       cli_start $@
+       cli_start "$@"
 }
 
-function cli_status() {
-       if cli_help_requested $@; then
+cli_status() {
+       if cli_help_requested "$@"; then
                cli_show_man network
                exit ${EXIT_OK}
        fi
@@ -994,25 +1130,53 @@ function cli_status() {
        local log_disable_stdout=${LOG_DISABLE_STDOUT}
        LOG_DISABLE_STDOUT="true"
 
-       local zones=$(zones_get $@)
+       local arguments=( $@ )
 
-       local zone
-       for zone in ${zones}; do
-               zone_status ${zone}
+       # Show all zones when no arguments are given
+       if ! isset arguments; then
+               local zone
+               for zone in $(zones_get_all); do
+                       zone_status "${zone}"
+               done
+
+               return ${EXIT_OK}
+       fi
+
+       local arg
+       for arg in ${arguments[@]}; do
+               # Is this a zone?
+               if zone_exists "${arg}"; then
+                       zone_status "${arg}"
+
+               # Is this a port?
+               elif port_exists "${arg}"; then
+                       port_status "${arg}"
+
+               # Is this a PHY?
+               elif phy_exists "${arg}"; then
+                       cli_device_status "${arg}"
+
+               # Is this a device?
+               elif device_exists "${arg}"; then
+                       cli_device_status "${arg}"
+
+               # Unknown argument
+               else
+                       error "Unknown argument: ${arg}"
+               fi
        done
 
        # Reset logging.
        LOG_DISABLE_STDOUT=${log_disable_stdout}
 }
 
-function cli_reset() {
-       if cli_help_requested $@; then
+cli_reset() {
+       if cli_help_requested "$@"; then
                cli_show_man network
                exit ${EXIT_OK}
        fi
 
        warning_log "Will reset the whole network configuration!!!"
-
        # Force mode is disabled by default
        local force=0
 
@@ -1033,21 +1197,41 @@ function cli_reset() {
                fi
        fi
 
+       # Destroy all IPsec VPN connections
+       local connection
+       for connection in $(ipsec_list_connections); do
+               ipsec_connection_destroy "${connection}"
+       done
+
+       local pool
+       for pool in $(ipsec_list_pools); do
+               ipsec_pool_destroy "${pool}"
+       done
+
+       # Stop strongswan
+       ipsec_strongswan_autostart
+
+       # Destroy all user-defined security policies
+       local secpol
+       for secpol in $(vpn_security_policies_list_user); do
+               vpn_security_policies_destroy "${secpol}"
+       done
+
        local zone
-       for zone in $(zones_get --all); do
-               zone_remove ${zone}
+       for zone in $(zones_get_all); do
+               zone_destroy "${zone}"
        done
 
        local port
-       for port in $(ports_get --all); do
+       for port in $(ports_get_all); do
                port_destroy "${port}"
        done
 
        # Flush all DNS servers.
        dns_server_flush
 
-       # Re-run the initialization functions
-       init_run
+       # Trigger udev to re-add all physical network devices
+       cmd_quiet udevadm trigger --action=add --subsystem-match=net
 
        exit ${EXIT_OK}
 }
@@ -1055,31 +1239,41 @@ function cli_reset() {
 # Help function: will show the default man page to the user.
 # Optionally, there are two arguments taken, the type of hook
 # and which hook should be shown.
-function cli_help() {
-       local type=${1}
-       local what=${2}
+cli_help() {
+       local cmd=${1}
+       shift
 
-       # Remove unknown types.
-       if ! listmatch ${type} zone port config; then
-               type=""
-       fi
+       case "${cmd}" in
+               zone|port|config)
+                       local type=${cmd}
+                       local hook=${1}
+
+                       # List all hooks if requested
+                       if [ "${hook}" = "list-hooks" ]; then
+                               cli_list_hooks ${type}
+                               return ${EXIT_OK}
+                       fi
 
-       # If no arguments were given, we will show the default page.
-       if [ -z "${type}" ]; then
-               cli_show_man network
-               return ${EXIT_OK}
-       fi
+                       if ! hook_exists ${type} ${hook}; then
+                               error "No hook with name '${hook}' could be found"
+                               exit "${EXIT_ERROR}"
+                       fi
 
-       if ! hook_exists ${type} ${what}; then
-               error "Hook of type '${type}' and name '${what}' could not be found."
-               exit "${EXIT_ERROR}"
-       fi
+                       hook_exec ${type} ${hook} help
+                       ;;
+
+               # In all other cases show the default man page
+               *)
+                       cli_show_man network
+                       return ${EXIT_OK}
+                       ;;
+       esac
 
-       hook_exec ${type} ${what} help
+       return ${EXIT_ERROR}
 }
 
-function cli_dns_server() {
-       if cli_help_requested $@; then
+cli_dns_server() {
+       if cli_help_requested "$@"; then
                cli_show_man network-dns-server
                exit ${EXIT_OK}
        fi
@@ -1097,7 +1291,7 @@ function cli_dns_server() {
 
        case "${cmd}" in
                list)
-                       dns_server_list
+                       dns_server_show
                        exit ${EXIT_OK}
                        ;;
                add)
@@ -1127,8 +1321,94 @@ function cli_dns_server() {
        esac
 
        # Update the local DNS configuration after changes have been made.
-       dns_generate_resolvconf
-       radvd_update
+       dns_server_update
+
+       exit ${EXIT_OK}
+}
+
+cli_raw() {
+       local cmd="${1}"
+       assert isset cmd
+       shift
+
+       case "${cmd}" in
+               db-dump)
+                       db_dump
+                       ;;
+               device-get-by-mac-address)
+                       device_get_by_mac_address "$@"
+                       ;;
+               ipsec-connection-exists)
+                       ipsec_connection_exists "$@"
+                       ;;
+               list-devices)
+                       device_list
+                       ;;
+               list-dhcpd-ranges-of-subnet)
+                       dhcpd_subnet_range_list "$@"
+                       ;;
+               list-dhcpd-settings)
+                       dhcpd_global_settings_list "$@"
+                       ;;
+               list-dhcpd-subnets)
+                       dhcpd_subnet_list "$@"
+                       ;;
+               list-dhcpd-subnet-options)
+                       dhcpd_subnet_options_list "$@"
+                       ;;
+               list-dns-servers)
+                       dns_server_list
+                       ;;
+               list-free-ports)
+                       port_list_free
+                       ;;
+               list-hooks)
+                       hook_list "$@"
+                       ;;
+               list-ipsec-connections)
+                       ipsec_list_connections
+                       ;;
+               list-ports)
+                       port_list
+                       ;;
+               list-ports-of-zone)
+                       zone_get_ports "$@"
+                       ;;
+               list-vpn-security-policies-all)
+                       vpn_security_policies_list_all
+                       ;;
+               list-settings)
+                       network_settings_list
+                       ;;
+               list-zones)
+                       zones_get_all
+                       ;;
+               list-next-free-zones)
+                       zones_get_next_free
+                       ;;
+               list-zone-config-ids)
+                       zone_config_list_ids "$@"
+                       ;;
+               list-zone-config-hids)
+                       zone_config_list_hids "$@"
+                       ;;
+               vpn-security-policy-exists)
+                       vpn_security_policy_exists "$@"
+                       ;;
+               zone-name-is-valid)
+                       zone_name_is_valid "$@"
+                       ;;
+               zone-config-id-is-valid)
+                       zone_config_id_is_valid "$@"
+                       ;;
+               zone-config-hid-is-valid)
+                       zone_config_hid_is_valid "$@"
+                       ;;
+               *)
+                       error "No such command: ${cmd}"
+                       exit ${EXIT_ERROR}
+                       ;;
+       esac
 
        exit ${EXIT_OK}
 }
@@ -1136,25 +1416,36 @@ function cli_dns_server() {
 # Process the given action
 case "${action}" in
        init)
-               init_run
+               # Update resolv.conf(5) when initializing the network
+               dns_generate_resolvconf
+
+               # Update bird configuration
+               bird_generate_config
+
+               # Also execute all triggers
+               triggers_execute_all "init"
                ;;
 
-       settings|hostname|port|device|zone|start|stop|restart|status|reset|route)
-               cli_${action} $@
+       settings|hostname|port|device|zone|start|stop|restart|status|reset|route|vpn|wireless)
+               cli_${action} "$@"
                ;;
 
        # DHCP server configuration (automatically detects which protocol to use).
        dhcpv6|dhcpv4)
-               cli_dhcpd ${action/dhcp/ip} $@
+               cli_dhcpd ${action/dhcp/ip} "$@"
                ;;
 
        # DNS server configuration.
        dns-server)
-               cli_dns_server $@
+               cli_dns_server "$@"
                ;;
 
        ""|help|--help|-h)
-               cli_help $@
+               cli_help "$@"
+               ;;
+
+       raw)
+               cli_raw "$@"
                ;;
 
        *)