#!/bin/bash ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2012 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 . # # # ############################################################################### # Sets the global wireless country code. Default is 00 = world. WIRELESS_REGULATORY_DOMAIN="00" NETWORK_SETTINGS_FILE_PARAMS="${NETWORK_SETTINGS_FILE_PARAMS} WIRELESS_REGULATORY_DOMAIN" WIRELESS_REGULATORY_DOMAIN_DATABASE="/usr/lib/crda/regulatory.bin" wireless_create() { local device=${1} assert isset device shift local address local channel local phy local type="managed" while [ $# -gt 0 ]; do case "${1}" in --address=*) address=$(cli_get_val ${1}) ;; --channel=*) channel=$(cli_get_val "${1}") ;; --phy=*) phy=$(cli_get_val ${1}) phy=$(phy_get ${phy}) ;; --type=*) type=$(cli_get_val ${1}) # ap --> __ap [ "${type}" = "ap" ] && type="__ap" ;; *) error "Unrecognized argument: ${1}" return ${EXIT_ERROR} ;; esac shift done case "${type}" in ibss|managed|monitor|__ap) ;; mesh-point) type="mp" ;; *) log ERROR "Unknown type: ${type}" return ${EXIT_ERROR} ;; esac assert phy_exists ${phy} isset address || address=$(mac_generate) cmd_quiet iw phy ${phy} interface add ${device} type ${type} local ret=$? if [ ${ret} -eq ${EXIT_OK} ]; then log DEBUG "created wireless device '${device}' (${type})" if isset address; then device_set_address ${device} ${address} fi else log ERROR "could not create wireless device '${device}' (${type}): ${ret}" fi # Set the channel if isset channel; then wireless_set_channel "${device}" "${channel}" || return $? fi return ${ret} } wireless_remove() { local device=${1} assert isset device if ! device_exists ${device}; then return ${EXIT_OK} fi # Tear down the device (if necessary). device_set_down ${device} # Remove it. cmd_quiet iw dev ${device} del local ret=$? if [ ${ret} -eq ${EXIT_OK} ]; then log DEBUG "removed wireless device '${device}'" else log ERROR "could not remove wireless device '${device}': ${ret}" fi return ${ret} } wireless_get_reg_domain() { # Returns the country code for the wireless device. # Defaults to 00 = world if unset. print "${WIRELESS_REGULATORY_DOMAIN:-00}" } wireless_init_reg_domain() { local country_code="$(wireless_get_reg_domain)" wireless_set_reg_domain "${country_code}" --no-reset } wireless_set_reg_domain() { local country_code local reset="true" while [ $# -gt 0 ]; do case "${1}" in --no-reset) reset="false" ;; -*) log ERROR "Ignoring invalid option: ${1}" ;; *) country_code="${1}" ;; esac shift done # Check if configuration value is valid if ! wireless_valid_reg_domain "${country_code}"; then log ERROR "Invalid wireless regulatory domain: ${country_code}" return ${EXIT_ERROR} fi # Before the wireless reg domain is set, it helps to reset to 00 first. if enabled reset; then iw reg set 00 &>/dev/null fi log INFO "Setting wireless regulatory domain country to '${country_code}'" iw reg set "${country_code}" } wireless_valid_reg_domain() { local country_code="${1}" # Empty country codes are invalid isset country_code || return ${EXIT_FALSE} local valid_country_codes="$(wireless_list_reg_domains)" if list_match "${country_code}" ${valid_country_codes}; then return ${EXIT_TRUE} fi return ${EXIT_FALSE} } wireless_list_reg_domains() { if [ ! -r "${WIRELESS_REGULATORY_DOMAIN_DATABASE}" ]; then log ERROR "Could not read ${WIRELESS_REGULATORY_DOMAIN_DATABASE}" return ${EXIT_ERROR} fi local line while read line; do # Check if line starts with "country" [ "${line:0:7}" = "country" ] || continue # Print country code print "${line:8:2}" done <<< "$(regdbdump ${WIRELESS_REGULATORY_DOMAIN_DATABASE})" } wireless_channel_to_frequency() { # http://en.wikipedia.org/wiki/List_of_WLAN_channels local channel=${1} assert isset channel # Channel number must be positive. assert [ "${channel}" -gt 0 ] # 2.4 GHz band case "${channel}" in [123456789]|1[0123]) print "$(( 2407 + (${channel} * 5)))" return ${EXIT_OK} ;; 14) print "2484" return ${EXIT_OK} ;; esac # 5 GHz band case "${channel}" in 3[68]|4[02468]|5[26]|6[04]|10[048]|11[26]|12[048]|13[26]|14[09]|15[37]|16[15]) print "$(( 5000 + (${channel} * 5)))" return ${EXIT_OK} ;; esac return ${EXIT_ERROR} } wireless_frequency_to_channel() { local frequency=${1} assert isinteger frequency # Everything that is too high if [ ${frequency} -gt 5825 ]; then return ${EXIT_ERROR} # 5 GHz Band elif [ ${frequency} -gt 5000 ]; then (( frequency = frequency - 5000 )) # Must be divisible by 5 [ "$(( frequency % 5 ))" -ne 0 ] && return ${EXIT_ERROR} print "$(( frequency / 5 ))" # 2.4 GHz Band - Channel 14 elif [ ${frequency} -eq 2484 ]; then print "14" # 2.4 GHz Band elif [ ${frequency} -gt 2407 ]; then (( frequency = frequency - 2407 )) # Must be divisible by 5 [ "$(( frequency % 5 ))" -ne 0 ] && return ${EXIT_ERROR} print "$(( frequency / 5 ))" # Everything else else return ${EXIT_ERROR} fi return ${EXIT_OK} } wireless_set_channel() { local device=${1} assert isset device local channel=${2} assert isset channel device_exists ${device} || return ${EXIT_ERROR} log DEBUG "Setting wireless channel on device '${device}' to channel '${channel}'" cmd_quiet iw dev ${device} set channel ${channel} } wireless_ibss_join() { local device=${1} assert isset device shift local bssid local essid local frequency while [ $# -gt 0 ]; do case "${1}" in --bssid=*) bssid="$(cli_get_val ${1})" ;; --essid=*) essid="$(cli_get_val ${1})" ;; --channel=*) local channel="$(cli_get_val ${1})" # Save the frequency of the channel instead # of the channel itself. if isset channel; then frequency="$(wireless_channel_to_frequency ${channel})" fi ;; esac shift done # Check input. assert ismac bssid assert isset essid assert isinteger frequency # Set device up. device_set_up "${device}" log INFO "${device} joining ibss network: ${essid} (${bssid})" cmd_quiet iw dev "${device}" ibss join "${essid}" \ "${frequency}" fixed-freq "${bssid}" } wireless_ibss_leave() { local device=${1} assert isset device log INFO "${device} leaving ibss network" cmd_quiet iw dev "${device}" ibss leave } wireless_is_radar_frequency() { local frequency="${1}" assert isset frequency [[ ${frequency} -ge 5260 ]] && [[ ${frequency} -le 5700 ]] } wireless_monitor() { local device="${1}" assert isset device shift local monitor_device="$(port_find_free "${PORT_PATTERN_WIRELESS_MONITOR}")" # Create an 802.11 monitoring device wireless_create "${monitor_device}" --phy="${device}" --type="monitor" local ret=$? case "${ret}" in 0) # Bring up the device device_set_up "${monitor_device}" # Starting tcpdump tcpdump -i "${monitor_device}" "$@" # Remove the monitoring interface. wireless_remove "${monitor_device}" ;; *) log ERROR "Could not create a monitoring interface on ${device}" return ${EXIT_ERROR} ;; esac return ${EXIT_OK} }