create_ap

create a nat-ed wifi ap
git clone git@git.2f30.org/create_ap.git
Log | Files | Refs | README | LICENSE

create_ap (51910B)


      1 #!/bin/bash
      2 
      3 # general dependencies:
      4 #    bash (to run this script)
      5 #    util-linux (for getopt)
      6 #    procps or procps-ng
      7 #    hostapd
      8 #    iproute2
      9 #    iw
     10 #    iwconfig (you only need this if 'iw' can not recognize your adapter)
     11 #    haveged (optional)
     12 
     13 # dependencies for 'nat' or 'none' Internet sharing method
     14 #    dnsmasq
     15 #    iptables
     16 
     17 VERSION=0.2
     18 PROGNAME="$(basename $0)"
     19 
     20 # make sure that all command outputs are in english
     21 # so we can parse them correctly
     22 export LC_ALL=C
     23 
     24 # all new files and directories must be readable only by root.
     25 # in special cases we must use chmod to give any other permissions.
     26 SCRIPT_UMASK=0077
     27 umask $SCRIPT_UMASK
     28 
     29 usage() {
     30     echo "Usage: "$PROGNAME" [options] <wifi-interface> [<interface-with-internet>] [<access-point-name> [<passphrase>]]"
     31     echo
     32     echo "Options:"
     33     echo "  -h, --help              Show this help"
     34     echo "  --version               Print version number"
     35     echo "  -c <channel>            Channel number (default: 1)"
     36     echo "  -w <WPA version>        Use 1 for WPA, use 2 for WPA2, use 1+2 for both (default: 1+2)"
     37     echo "  -n                      Disable Internet sharing (if you use this, don't pass"
     38     echo "                          the <interface-with-internet> argument)"
     39     echo "  -m <method>             Method for Internet sharing."
     40     echo "                          Use: 'nat' for NAT (default)"
     41     echo "                               'bridge' for bridging"
     42     echo "                               'none' for no Internet sharing (equivalent to -n)"
     43     echo "  --psk                   Use 64 hex digits pre-shared-key instead of passphrase"
     44     echo "  --hidden                Make the Access Point hidden (do not broadcast the SSID)"
     45     echo "  --redirect-to-localhost If -n is set, redirect every web request to localhost (useful for public information networks)"
     46     echo "  --hostapd-debug <level> With level between 1 and 2, passes arguments -d or -dd to hostapd for debugging."
     47     echo "  --isolate-clients       Disable communication between clients"
     48     echo "  --ieee80211n            Enable IEEE 802.11n (HT)"
     49     echo "  --ht_capab <HT>         HT capabilities (default: [HT40+])"
     50     echo "  --country <code>        Set two-letter country code for regularity (example: US)"
     51     echo "  --freq-band <GHz>       Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)"
     52     echo "  --driver                Choose your WiFi adapter driver (default: nl80211)"
     53     echo "  --no-virt               Do not create virtual interface"
     54     echo "  --no-haveged            Do not run 'haveged' automatically when needed"
     55     echo "  --fix-unmanaged         If NetworkManager shows your interface as unmanaged after you"
     56     echo "                          close create_ap, then use this option to switch your interface"
     57     echo "                          back to managed"
     58     echo "  --mac <MAC>             Set MAC address"
     59     echo "  --dhcp-dns <IP1[,IP2]>  Set DNS returned by DHCP"
     60     echo "  --daemon                Run create_ap in the background"
     61     echo "  --stop <id>             Send stop command to an already running create_ap. For an <id>"
     62     echo "                          you can put the PID of create_ap or the WiFi interface. You can"
     63     echo "                          get them with --list-running"
     64     echo "  --list-running          Show the create_ap processes that are already running"
     65     echo "  --list-clients <id>     List the clients connected to create_ap instance associated with <id>."
     66     echo "                          For an <id> you can put the PID of create_ap or the WiFi interface."
     67     echo "                          If virtual WiFi interface was created, then use that one."
     68     echo "                          You can get them with --list-running"
     69     echo "  --mkconfig <conf_file>  Store configs in conf_file"
     70     echo "  --config <conf_file>    Load configs from conf_file"
     71     echo
     72     echo "Non-Bridging Options:"
     73     echo "  --no-dns                Disable dnsmasq DNS server"
     74     echo "  -g <gateway>            IPv4 Gateway for the Access Point (default: 192.168.12.1)"
     75     echo "  -d                      DNS server will take into account /etc/hosts"
     76     echo
     77     echo "Useful informations:"
     78     echo "  * If you're not using the --no-virt option, then you can create an AP with the same"
     79     echo "    interface you are getting your Internet connection."
     80     echo "  * You can pass your SSID and password through pipe or through arguments (see examples)."
     81     echo "  * On bridge method if the <interface-with-internet> is not a bridge interface, then"
     82     echo "    a bridge interface is created automatically."
     83     echo
     84     echo "Examples:"
     85     echo "  "$PROGNAME" wlan0 eth0 MyAccessPoint MyPassPhrase"
     86     echo "  echo -e 'MyAccessPoint\nMyPassPhrase' | "$PROGNAME" wlan0 eth0"
     87     echo "  "$PROGNAME" wlan0 eth0 MyAccessPoint"
     88     echo "  echo 'MyAccessPoint' | "$PROGNAME" wlan0 eth0"
     89     echo "  "$PROGNAME" wlan0 wlan0 MyAccessPoint MyPassPhrase"
     90     echo "  "$PROGNAME" -n wlan0 MyAccessPoint MyPassPhrase"
     91     echo "  "$PROGNAME" -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase"
     92     echo "  "$PROGNAME" -m bridge wlan0 br0 MyAccessPoint MyPassPhrase"
     93     echo "  "$PROGNAME" --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase"
     94     echo "  "$PROGNAME" --daemon wlan0 eth0 MyAccessPoint MyPassPhrase"
     95     echo "  "$PROGNAME" --stop wlan0"
     96 }
     97 
     98 # on success it echos a non-zero unused FD
     99 # on error it echos 0
    100 get_avail_fd() {
    101     local x
    102     for x in $(seq 1 $(ulimit -n)); do
    103         if [[ ! -a "/proc/$BASHPID/fd/$x" ]]; then
    104             echo $x
    105             return
    106         fi
    107     done
    108     echo 0
    109 }
    110 
    111 # lock file for the mutex counter
    112 COUNTER_LOCK_FILE=/tmp/create_ap.$$.lock
    113 
    114 cleanup_lock() {
    115     rm -f $COUNTER_LOCK_FILE
    116 }
    117 
    118 init_lock() {
    119     local LOCK_FILE=/tmp/create_ap.all.lock
    120 
    121     # we initialize only once
    122     [[ $LOCK_FD -ne 0 ]] && return 0
    123 
    124     LOCK_FD=$(get_avail_fd)
    125     [[ $LOCK_FD -eq 0 ]] && return 1
    126 
    127     # open/create lock file with write access for all users
    128     # otherwise normal users will not be able to use it.
    129     # to avoid race conditions on creation, we need to
    130     # use umask to set the permissions.
    131     umask 0555
    132     eval "exec $LOCK_FD>$LOCK_FILE" > /dev/null 2>&1 || return 1
    133     umask $SCRIPT_UMASK
    134 
    135     # there is a case where lock file was created from a normal
    136     # user. change the owner to root as soon as we can.
    137     [[ $(id -u) -eq 0 ]] && chown 0:0 $LOCK_FILE
    138 
    139     # create mutex counter lock file
    140     echo 0 > $COUNTER_LOCK_FILE
    141 
    142     return $?
    143 }
    144 
    145 # recursive mutex lock for all create_ap processes
    146 mutex_lock() {
    147     local counter_mutex_fd
    148     local counter
    149 
    150     # lock local mutex and read counter
    151     counter_mutex_fd=$(get_avail_fd)
    152     if [[ $counter_mutex_fd -ne 0 ]]; then
    153         eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE"
    154         flock $counter_mutex_fd
    155         read -u $counter_mutex_fd counter
    156     else
    157         echo "Failed to lock mutex counter" >&2
    158         return 1
    159     fi
    160 
    161     # lock global mutex and increase counter
    162     [[ $counter -eq 0 ]] && flock $LOCK_FD
    163     counter=$(( $counter + 1 ))
    164 
    165     # write counter and unlock local mutex
    166     echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd
    167     eval "exec ${counter_mutex_fd}<&-"
    168     return 0
    169 }
    170 
    171 # recursive mutex unlock for all create_ap processes
    172 mutex_unlock() {
    173     local counter_mutex_fd
    174     local counter
    175 
    176     # lock local mutex and read counter
    177     counter_mutex_fd=$(get_avail_fd)
    178     if [[ $counter_mutex_fd -ne 0 ]]; then
    179         eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE"
    180         flock $counter_mutex_fd
    181         read -u $counter_mutex_fd counter
    182     else
    183         echo "Failed to lock mutex counter" >&2
    184         return 1
    185     fi
    186 
    187     # decrease counter and unlock global mutex
    188     if [[ $counter -gt 0 ]]; then
    189         counter=$(( $counter - 1 ))
    190         [[ $counter -eq 0 ]] && flock -u $LOCK_FD
    191     fi
    192 
    193     # write counter and unlock local mutex
    194     echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd
    195     eval "exec ${counter_mutex_fd}<&-"
    196     return 0
    197 }
    198 
    199 # it takes 2 arguments
    200 # returns:
    201 #  0 if v1 (1st argument) and v2 (2nd argument) are the same
    202 #  1 if v1 is less than v2
    203 #  2 if v1 is greater than v2
    204 version_cmp() {
    205     local V1 V2 VN x
    206     [[ ! $1 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!"
    207     [[ ! $2 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!"
    208 
    209     V1=( $(echo $1 | tr '.' ' ') )
    210     V2=( $(echo $2 | tr '.' ' ') )
    211     VN=${#V1[@]}
    212     [[ $VN -lt ${#V2[@]} ]] && VN=${#V2[@]}
    213 
    214     for ((x = 0; x < $VN; x++)); do
    215         [[ ${V1[x]} -lt ${V2[x]} ]] && return 1
    216         [[ ${V1[x]} -gt ${V2[x]} ]] && return 2
    217     done
    218 
    219     return 0
    220 }
    221 
    222 USE_IWCONFIG=0
    223 
    224 is_interface() {
    225     [[ -z "$1" ]] && return 1
    226     [[ -d "/sys/class/net/${1}" ]]
    227 }
    228 
    229 is_wifi_interface() {
    230     which iw > /dev/null 2>&1 && iw dev $1 info > /dev/null 2>&1 && return 0
    231     if which iwconfig > /dev/null 2>&1 && iwconfig $1 > /dev/null 2>&1; then
    232         USE_IWCONFIG=1
    233         return 0
    234     fi
    235     return 1
    236 }
    237 
    238 is_bridge_interface() {
    239     [[ -z "$1" ]] && return 1
    240     [[ -d "/sys/class/net/${1}/bridge" ]]
    241 }
    242 
    243 get_phy_device() {
    244     local x
    245     for x in /sys/class/ieee80211/*; do
    246         [[ ! -e "$x" ]] && continue
    247         if [[ "${x##*/}" = "$1" ]]; then
    248             echo $1
    249             return 0
    250         elif [[ -e "$x/device/net/$1" ]]; then
    251             echo ${x##*/}
    252             return 0
    253         elif [[ -e "$x/device/net:$1" ]]; then
    254             echo ${x##*/}
    255             return 0
    256         fi
    257     done
    258     echo "Failed to get phy interface" >&2
    259     return 1
    260 }
    261 
    262 get_adapter_info() {
    263     local PHY
    264     PHY=$(get_phy_device "$1")
    265     [[ $? -ne 0 ]] && return 1
    266     iw phy $PHY info
    267 }
    268 
    269 get_adapter_kernel_module() {
    270     local MODULE
    271     MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module")
    272     echo ${MODULE##*/}
    273 }
    274 
    275 can_be_sta_and_ap() {
    276     # iwconfig does not provide this information, assume false
    277     [[ $USE_IWCONFIG -eq 1 ]] && return 1
    278     get_adapter_info "$1" | grep -E '{.* managed.* AP.*}' > /dev/null 2>&1 && return 0
    279     get_adapter_info "$1" | grep -E '{.* AP.* managed.*}' > /dev/null 2>&1 && return 0
    280     return 1
    281 }
    282 
    283 can_be_ap() {
    284     # iwconfig does not provide this information, assume true
    285     [[ $USE_IWCONFIG -eq 1 ]] && return 0
    286     get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 && return 0
    287     return 1
    288 }
    289 
    290 can_transmit_to_channel() {
    291     local IFACE CHANNEL_NUM CHANNEL_INFO
    292     IFACE=$1
    293     CHANNEL_NUM=$2
    294 
    295     if [[ $USE_IWCONFIG -eq 0 ]]; then
    296         if [[ $FREQ_BAND == 2.4 ]]; then
    297             CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9] MHz \[${CHANNEL_NUM}\]")
    298         else
    299             CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\) MHz \[${CHANNEL_NUM}\]")
    300         fi
    301         [[ -z "${CHANNEL_INFO}" ]] && return 1
    302         [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1
    303         [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1
    304         return 0
    305     else
    306         CHANNEL_NUM=$(printf '%02d' ${CHANNEL_NUM})
    307         CHANNEL_INFO=$(iwlist ${IFACE} channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:")
    308         [[ -z "${CHANNEL_INFO}" ]] && return 1
    309         return 0
    310     fi
    311 }
    312 
    313 # taken from iw/util.c
    314 ieee80211_frequency_to_channel() {
    315     local FREQ=$1
    316     if [[ $FREQ -eq 2484 ]]; then
    317         echo 14
    318     elif [[ $FREQ -lt 2484 ]]; then
    319         echo $(( ($FREQ - 2407) / 5 ))
    320     elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then
    321         echo $(( ($FREQ - 4000) / 5 ))
    322     elif [[ $FREQ -le 45000 ]]; then
    323         echo $(( ($FREQ - 5000) / 5 ))
    324     elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then
    325         echo $(( ($FREQ - 56160) / 2160 ))
    326     else
    327         echo 0
    328     fi
    329 }
    330 
    331 is_5ghz_frequency() {
    332     [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]]
    333 }
    334 
    335 is_wifi_connected() {
    336     if [[ $USE_IWCONFIG -eq 0 ]]; then
    337         iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 && return 0
    338     else
    339         iwconfig "$1" 2>&1 | grep -E 'Access Point: [0-9a-fA-F]{2}:' > /dev/null 2>&1 && return 0
    340     fi
    341     return 1
    342 }
    343 
    344 is_macaddr() {
    345     echo "$1" | grep -E "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$" > /dev/null 2>&1
    346 }
    347 
    348 is_unicast_macaddr() {
    349     local x
    350     is_macaddr "$1" || return 1
    351     x=$(echo "$1" | cut -d: -f1)
    352     x=$(printf '%d' "0x${x}")
    353     [[ $(expr $x % 2) -eq 0 ]]
    354 }
    355 
    356 get_macaddr() {
    357     is_interface "$1" || return
    358     cat "/sys/class/net/${1}/address"
    359 }
    360 
    361 get_mtu() {
    362     is_interface "$1" || return
    363     cat "/sys/class/net/${1}/mtu"
    364 }
    365 
    366 alloc_new_iface() {
    367     local prefix=$1
    368     local i=0
    369 
    370     mutex_lock
    371     while :; do
    372         if ! is_interface $prefix$i && [[ ! -f $COMMON_CONFDIR/ifaces/$prefix$i ]]; then
    373             mkdir -p $COMMON_CONFDIR/ifaces
    374             touch $COMMON_CONFDIR/ifaces/$prefix$i
    375             echo $prefix$i
    376             mutex_unlock
    377             return
    378         fi
    379         i=$((i + 1))
    380     done
    381     mutex_unlock
    382 }
    383 
    384 dealloc_iface() {
    385     rm -f $COMMON_CONFDIR/ifaces/$1
    386 }
    387 
    388 get_all_macaddrs() {
    389     cat /sys/class/net/*/address
    390 }
    391 
    392 get_new_macaddr() {
    393     local OLDMAC NEWMAC LAST_BYTE i
    394     OLDMAC=$(get_macaddr "$1")
    395     LAST_BYTE=$(printf %d 0x${OLDMAC##*:})
    396     mutex_lock
    397     for i in {1..255}; do
    398         NEWMAC="${OLDMAC%:*}:$(printf %02x $(( ($LAST_BYTE + $i) % 256 )))"
    399         (get_all_macaddrs | grep "$NEWMAC" > /dev/null 2>&1) || break
    400     done
    401     mutex_unlock
    402     echo $NEWMAC
    403 }
    404 
    405 # start haveged when needed
    406 haveged_watchdog() {
    407     local show_warn=1
    408     while :; do
    409         mutex_lock
    410         if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then
    411             if ! which haveged > /dev/null 2>&1; then
    412                 if [[ $show_warn -eq 1 ]]; then
    413                     echo "WARN: Low entropy detected. We recommend you to install \`haveged'"
    414                     show_warn=0
    415                 fi
    416             elif ! pidof haveged > /dev/null 2>&1; then
    417                 echo "Low entropy detected, starting haveged"
    418                 # boost low-entropy
    419                 haveged -w 1024 -p $COMMON_CONFDIR/haveged.pid
    420             fi
    421         fi
    422         mutex_unlock
    423         sleep 2
    424     done
    425 }
    426 
    427 NETWORKMANAGER_CONF=/etc/NetworkManager/NetworkManager.conf
    428 NM_OLDER_VERSION=1
    429 
    430 networkmanager_exists() {
    431     local NM_VER
    432     which nmcli > /dev/null 2>&1 || return 1
    433     NM_VER=$(nmcli -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+')
    434     version_cmp $NM_VER 0.9.9
    435     if [[ $? -eq 1 ]]; then
    436         NM_OLDER_VERSION=1
    437     else
    438         NM_OLDER_VERSION=0
    439     fi
    440     return 0
    441 }
    442 
    443 networkmanager_is_running() {
    444     local NMCLI_OUT
    445     networkmanager_exists || return 1
    446     if [[ $NM_OLDER_VERSION -eq 1 ]]; then
    447         NMCLI_OUT=$(nmcli -t -f RUNNING nm)
    448     else
    449         NMCLI_OUT=$(nmcli -t -f RUNNING g)
    450     fi
    451     [[ "$NMCLI_OUT" == "running" ]]
    452 }
    453 
    454 networkmanager_iface_is_unmanaged() {
    455     is_interface "$1" || return 2
    456     (nmcli -t -f DEVICE,STATE d | grep -E "^$1:unmanaged$" > /dev/null 2>&1) || return 1
    457 }
    458 
    459 ADDED_UNMANAGED=
    460 
    461 networkmanager_add_unmanaged() {
    462     local MAC UNMANAGED WAS_EMPTY x
    463     networkmanager_exists || return 1
    464 
    465     [[ -d ${NETWORKMANAGER_CONF%/*} ]] || mkdir -p ${NETWORKMANAGER_CONF%/*}
    466     [[ -f ${NETWORKMANAGER_CONF} ]] || touch ${NETWORKMANAGER_CONF}
    467 
    468     if [[ $NM_OLDER_VERSION -eq 1 ]]; then
    469         if [[ -z "$2" ]]; then
    470             MAC=$(get_macaddr "$1")
    471         else
    472             MAC="$2"
    473         fi
    474         [[ -z "$MAC" ]] && return 1
    475     fi
    476 
    477     mutex_lock
    478     UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf)
    479 
    480     WAS_EMPTY=0
    481     [[ -z "$UNMANAGED" ]] && WAS_EMPTY=1
    482     UNMANAGED=$(echo "$UNMANAGED" | sed 's/unmanaged-devices=//' | tr ';,' ' ')
    483 
    484     # if it exists, do nothing
    485     for x in $UNMANAGED; do
    486         if [[ $x == "mac:${MAC}" ]] ||
    487                [[ $NM_OLDER_VERSION -eq 0 && $x == "interface-name:${1}" ]]; then
    488             mutex_unlock
    489             return 2
    490         fi
    491     done
    492 
    493     if [[ $NM_OLDER_VERSION -eq 1 ]]; then
    494         UNMANAGED="${UNMANAGED} mac:${MAC}"
    495     else
    496         UNMANAGED="${UNMANAGED} interface-name:${1}"
    497     fi
    498 
    499     UNMANAGED=$(echo $UNMANAGED | sed -e 's/^ //')
    500     UNMANAGED="${UNMANAGED// /;}"
    501     UNMANAGED="unmanaged-devices=${UNMANAGED}"
    502 
    503     if ! grep -E '^\[keyfile\]' ${NETWORKMANAGER_CONF} > /dev/null 2>&1; then
    504         echo -e "\n\n[keyfile]\n${UNMANAGED}" >> ${NETWORKMANAGER_CONF}
    505     elif [[ $WAS_EMPTY -eq 1 ]]; then
    506         sed -e "s/^\(\[keyfile\].*\)$/\1\n${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
    507     else
    508         sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
    509     fi
    510 
    511     ADDED_UNMANAGED="${ADDED_UNMANAGED} ${1} "
    512     mutex_unlock
    513 
    514     return 0
    515 }
    516 
    517 networkmanager_rm_unmanaged() {
    518     local MAC UNMANAGED
    519     networkmanager_exists || return 1
    520     [[ ! -f ${NETWORKMANAGER_CONF} ]] && return 1
    521 
    522     if [[ $NM_OLDER_VERSION -eq 1 ]]; then
    523         if [[ -z "$2" ]]; then
    524             MAC=$(get_macaddr "$1")
    525         else
    526             MAC="$2"
    527         fi
    528         [[ -z "$MAC" ]] && return 1
    529     fi
    530 
    531     mutex_lock
    532     UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf | sed 's/unmanaged-devices=//' | tr ';,' ' ')
    533 
    534     if [[ -z "$UNMANAGED" ]]; then
    535         mutex_unlock
    536         return 1
    537     fi
    538 
    539     [[ -n "$MAC" ]] && UNMANAGED=$(echo $UNMANAGED | sed -e "s/mac:${MAC}\( \|$\)//g")
    540     UNMANAGED=$(echo $UNMANAGED | sed -e "s/interface-name:${1}\( \|$\)//g")
    541     UNMANAGED=$(echo $UNMANAGED | sed -e 's/ $//')
    542 
    543     if [[ -z "$UNMANAGED" ]]; then
    544         sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF}
    545     else
    546         UNMANAGED="${UNMANAGED// /;}"
    547         UNMANAGED="unmanaged-devices=${UNMANAGED}"
    548         sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
    549     fi
    550 
    551     ADDED_UNMANAGED="${ADDED_UNMANAGED/ ${1} /}"
    552     mutex_unlock
    553 
    554     return 0
    555 }
    556 
    557 networkmanager_fix_unmanaged() {
    558     [[ -f ${NETWORKMANAGER_CONF} ]] || return
    559     mutex_lock
    560     sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF}
    561     mutex_unlock
    562 }
    563 
    564 networkmanager_rm_unmanaged_if_needed() {
    565     [[ $ADDED_UNMANAGED =~ .*\ ${1}\ .* ]] && networkmanager_rm_unmanaged $1 $2
    566 }
    567 
    568 networkmanager_wait_until_unmanaged() {
    569     local RES
    570     networkmanager_is_running || return 1
    571     while :; do
    572         networkmanager_iface_is_unmanaged "$1"
    573         RES=$?
    574         [[ $RES -eq 0 ]] && break
    575         [[ $RES -eq 2 ]] && die "Interface '${1}' does not exists.
    576        It's probably renamed by a udev rule."
    577         sleep 1
    578     done
    579     sleep 2
    580     return 0
    581 }
    582 
    583 
    584 CHANNEL=default
    585 GATEWAY=192.168.12.1
    586 WPA_VERSION=1+2
    587 ETC_HOSTS=0
    588 DHCP_DNS=gateway
    589 NO_DNS=0
    590 HIDDEN=0
    591 ISOLATE_CLIENTS=0
    592 SHARE_METHOD=nat
    593 IEEE80211N=0
    594 HT_CAPAB='[HT40+]'
    595 DRIVER=nl80211
    596 NO_VIRT=0
    597 COUNTRY=
    598 FREQ_BAND=2.4
    599 NEW_MACADDR=
    600 DAEMONIZE=0
    601 NO_HAVEGED=0
    602 USE_PSK=0
    603 
    604 HOSTAPD_DEBUG_ARGS=
    605 REDIRECT_TO_LOCALHOST=0
    606 
    607 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS NO_DNS HIDDEN ISOLATE_CLIENTS SHARE_METHOD
    608              IEEE80211N HT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND
    609              NEW_MACADDR DAEMONIZE NO_HAVEGED WIFI_IFACE INTERNET_IFACE
    610              SSID PASSPHRASE USE_PSK)
    611 
    612 FIX_UNMANAGED=0
    613 LIST_RUNNING=0
    614 STOP_ID=
    615 LIST_CLIENTS_ID=
    616 
    617 STORE_CONFIG=
    618 LOAD_CONFIG=
    619 
    620 CONFDIR=
    621 WIFI_IFACE=
    622 VWIFI_IFACE=
    623 INTERNET_IFACE=
    624 BRIDGE_IFACE=
    625 OLD_MACADDR=
    626 IP_ADDRS=
    627 ROUTE_ADDRS=
    628 
    629 HAVEGED_WATCHDOG_PID=
    630 
    631 _cleanup() {
    632     local PID x
    633 
    634     trap "" SIGINT SIGUSR1 SIGUSR2 EXIT
    635     mutex_lock
    636     disown -a
    637 
    638     # kill haveged_watchdog
    639     [[ -n "$HAVEGED_WATCHDOG_PID" ]] && kill $HAVEGED_WATCHDOG_PID
    640 
    641     # kill processes
    642     for x in $CONFDIR/*.pid; do
    643         # even if the $CONFDIR is empty, the for loop will assign
    644         # a value in $x. so we need to check if the value is a file
    645         [[ -f $x ]] && kill -9 $(cat $x)
    646     done
    647 
    648     rm -rf $CONFDIR
    649 
    650     local found=0
    651     for x in $(list_running_conf); do
    652         if [[ -f $x/nat_internet_iface && $(cat $x/nat_internet_iface) == $INTERNET_IFACE ]]; then
    653             found=1
    654             break
    655         fi
    656     done
    657 
    658     if [[ $found -eq 0 ]]; then
    659         cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding \
    660            /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding
    661         rm -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding
    662     fi
    663 
    664     # if we are the last create_ap instance then set back the common values
    665     if ! has_running_instance; then
    666         # kill common processes
    667         for x in $COMMON_CONFDIR/*.pid; do
    668             [[ -f $x ]] && kill -9 $(cat $x)
    669         done
    670 
    671         # set old ip_forward
    672         if [[ -f $COMMON_CONFDIR/ip_forward ]]; then
    673             cp -f $COMMON_CONFDIR/ip_forward /proc/sys/net/ipv4
    674             rm -f $COMMON_CONFDIR/ip_forward
    675         fi
    676 
    677         # set old bridge-nf-call-iptables
    678         if [[ -f $COMMON_CONFDIR/bridge-nf-call-iptables ]]; then
    679             if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
    680                 cp -f $COMMON_CONFDIR/bridge-nf-call-iptables /proc/sys/net/bridge
    681             fi
    682             rm -f $COMMON_CONFDIR/bridge-nf-call-iptables
    683         fi
    684 
    685         rm -rf $COMMON_CONFDIR
    686     fi
    687 
    688     if [[ "$SHARE_METHOD" != "none" ]]; then
    689         if [[ "$SHARE_METHOD" == "nat" ]]; then
    690             iptables -t nat -D POSTROUTING -o ${INTERNET_IFACE} -s ${GATEWAY%.*}.0/24 -j MASQUERADE
    691             iptables -D FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT
    692             iptables -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT
    693         elif [[ "$SHARE_METHOD" == "bridge" ]]; then
    694             if ! is_bridge_interface $INTERNET_IFACE; then
    695                 ip link set dev $BRIDGE_IFACE down
    696                 ip link set dev $INTERNET_IFACE down
    697                 ip link set dev $INTERNET_IFACE promisc off
    698                 ip link set dev $INTERNET_IFACE nomaster
    699                 ip link delete $BRIDGE_IFACE type bridge
    700                 ip addr flush $INTERNET_IFACE
    701                 ip link set dev $INTERNET_IFACE up
    702                 dealloc_iface $BRIDGE_IFACE
    703 
    704                 for x in "${IP_ADDRS[@]}"; do
    705                     x="${x/inet/}"
    706                     x="${x/secondary/}"
    707                     x="${x/dynamic/}"
    708                     x=$(echo $x | sed 's/\([0-9]\)sec/\1/g')
    709                     x="${x/${INTERNET_IFACE}/}"
    710                     ip addr add $x dev $INTERNET_IFACE
    711                 done
    712 
    713                 ip route flush dev $INTERNET_IFACE
    714 
    715                 for x in "${ROUTE_ADDRS[@]}"; do
    716                     [[ -z "$x" ]] && continue
    717                     [[ "$x" == default* ]] && continue
    718                     ip route add $x dev $INTERNET_IFACE
    719                 done
    720 
    721                 for x in "${ROUTE_ADDRS[@]}"; do
    722                     [[ -z "$x" ]] && continue
    723                     [[ "$x" != default* ]] && continue
    724                     ip route add $x dev $INTERNET_IFACE
    725                 done
    726 
    727                 networkmanager_rm_unmanaged_if_needed $INTERNET_IFACE
    728             fi
    729         fi
    730     fi
    731 
    732     if [[ "$SHARE_METHOD" != "bridge" ]]; then
    733         iptables -D INPUT -p tcp -m tcp --dport 53 -j ACCEPT
    734         iptables -D INPUT -p udp -m udp --dport 53 -j ACCEPT
    735         iptables -D INPUT -p udp -m udp --dport 67 -j ACCEPT
    736     fi
    737 
    738     if [[ $NO_VIRT -eq 0 ]]; then
    739         if [[ -n "$VWIFI_IFACE" ]]; then
    740             ip link set down dev ${VWIFI_IFACE}
    741             ip addr flush ${VWIFI_IFACE}
    742             networkmanager_rm_unmanaged_if_needed ${VWIFI_IFACE} ${OLD_MACADDR}
    743             iw dev ${VWIFI_IFACE} del
    744             dealloc_iface $VWIFI_IFACE
    745         fi
    746     else
    747         ip link set down dev ${WIFI_IFACE}
    748         ip addr flush ${WIFI_IFACE}
    749         if [[ -n "$NEW_MACADDR" ]]; then
    750             ip link set dev ${WIFI_IFACE} address ${OLD_MACADDR}
    751         fi
    752         networkmanager_rm_unmanaged_if_needed ${WIFI_IFACE} ${OLD_MACADDR}
    753     fi
    754 
    755     mutex_unlock
    756     cleanup_lock
    757 }
    758 
    759 cleanup() {
    760     echo
    761     echo -n "Doing cleanup.. "
    762     _cleanup > /dev/null 2>&1
    763     echo "done"
    764 }
    765 
    766 die() {
    767     [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2
    768     # send die signal to the main process
    769     [[ $BASHPID -ne $$ ]] && kill -USR2 $$
    770     # we don't need to call cleanup because it's traped on EXIT
    771     exit 1
    772 }
    773 
    774 clean_exit() {
    775     # send clean_exit signal to the main process
    776     [[ $BASHPID -ne $$ ]] && kill -USR1 $$
    777     # we don't need to call cleanup because it's traped on EXIT
    778     exit 0
    779 }
    780 
    781 list_running_conf() {
    782     local x
    783     mutex_lock
    784     for x in /tmp/create_ap.*; do
    785         if [[ -f $x/pid && -f $x/wifi_iface && -d /proc/$(cat $x/pid) ]]; then
    786             echo $x
    787         fi
    788     done
    789     mutex_unlock
    790 }
    791 
    792 list_running() {
    793     local IFACE wifi_iface x
    794     mutex_lock
    795     for x in $(list_running_conf); do
    796         IFACE=${x#*.}
    797         IFACE=${IFACE%%.*}
    798         wifi_iface=$(cat $x/wifi_iface)
    799 
    800         if [[ $IFACE == $wifi_iface ]]; then
    801             echo $(cat $x/pid) $IFACE
    802         else
    803             echo $(cat $x/pid) $IFACE '('$(cat $x/wifi_iface)')'
    804         fi
    805     done
    806     mutex_unlock
    807 }
    808 
    809 get_wifi_iface_from_pid() {
    810     list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E "^${1} " | cut -d' ' -f2
    811 }
    812 
    813 get_pid_from_wifi_iface() {
    814     list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E " ${1}$" | cut -d' ' -f1
    815 }
    816 
    817 get_confdir_from_pid() {
    818     local IFACE x
    819     mutex_lock
    820     for x in $(list_running_conf); do
    821         if [[ $(cat $x/pid) == "$1" ]]; then
    822             echo $x
    823             break
    824         fi
    825     done
    826     mutex_unlock
    827 }
    828 
    829 print_client() {
    830     local line ipaddr hostname
    831     local mac="$1"
    832 
    833     if [[ -f $CONFDIR/dnsmasq.leases ]]; then
    834         line=$(grep " $mac " $CONFDIR/dnsmasq.leases | tail -n 1)
    835         ipaddr=$(echo $line | cut -d' ' -f3)
    836         hostname=$(echo $line | cut -d' ' -f4)
    837     fi
    838 
    839     [[ -z "$ipaddr" ]] && ipaddr="*"
    840     [[ -z "$hostname" ]] && hostname="*"
    841 
    842     printf "%-20s %-18s %s\n" "$mac" "$ipaddr" "$hostname"
    843 }
    844 
    845 list_clients() {
    846     local wifi_iface pid
    847 
    848     # If PID is given, get the associated wifi iface
    849     if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then
    850         pid="$1"
    851         wifi_iface=$(get_wifi_iface_from_pid "$pid")
    852         [[ -z "$wifi_iface" ]] && die "'$pid' is not the pid of a running $PROGNAME instance."
    853     fi
    854 
    855     [[ -z "$wifi_iface" ]] && wifi_iface="$1"
    856     is_wifi_interface "$wifi_iface" || die "'$wifi_iface' is not a WiFi interface."
    857 
    858     [[ -z "$pid" ]] && pid=$(get_pid_from_wifi_iface "$wifi_iface")
    859     [[ -z "$pid" ]] && die "'$wifi_iface' is not used from $PROGNAME instance.\n\
    860        Maybe you need to pass the virtual interface instead.\n\
    861        Use --list-running to find it out."
    862     [[ -z "$CONFDIR" ]] && CONFDIR=$(get_confdir_from_pid "$pid")
    863 
    864     if [[ $USE_IWCONFIG -eq 0 ]]; then
    865         local awk_cmd='($1 ~ /Station$/) {print $2}'
    866         local client_list=$(iw dev "$wifi_iface" station dump | awk "$awk_cmd")
    867 
    868         if [[ -z "$client_list" ]]; then
    869             echo "No clients connected"
    870             return
    871         fi
    872 
    873         printf "%-20s %-18s %s\n" "MAC" "IP" "Hostname"
    874 
    875         local mac
    876         for mac in $client_list; do
    877             print_client $mac
    878         done
    879     else
    880         die "This option is not supported for the current driver."
    881     fi
    882 }
    883 
    884 has_running_instance() {
    885     local PID x
    886 
    887     mutex_lock
    888     for x in /tmp/create_ap.*; do
    889         if [[ -f $x/pid ]]; then
    890             PID=$(cat $x/pid)
    891             if [[ -d /proc/$PID ]]; then
    892                 mutex_unlock
    893                 return 0
    894             fi
    895         fi
    896     done
    897     mutex_lock
    898 
    899     return 1
    900 }
    901 
    902 is_running_pid() {
    903     list_running | grep -E "^${1} " > /dev/null 2>&1
    904 }
    905 
    906 send_stop() {
    907     local x
    908 
    909     mutex_lock
    910     # send stop signal to specific pid
    911     if is_running_pid $1; then
    912         kill -USR1 $1
    913         mutex_unlock
    914         return
    915     fi
    916 
    917     # send stop signal to specific interface
    918     for x in $(list_running | grep -E " \(?${1}( |\)?\$)" | cut -f1 -d' '); do
    919         kill -USR1 $x
    920     done
    921     mutex_unlock
    922 }
    923 
    924 # Storing configs
    925 write_config() {
    926     local i=1
    927 
    928     if ! eval 'echo -n > "$STORE_CONFIG"' > /dev/null 2>&1; then
    929         echo "ERROR: Unable to create config file $STORE_CONFIG" >&2
    930         exit 1
    931     fi
    932 
    933     WIFI_IFACE=$1
    934     if [[ "$SHARE_METHOD" == "none" ]]; then
    935         SSID="$2"
    936         PASSPHRASE="$3"
    937     else
    938         INTERNET_IFACE="$2"
    939         SSID="$3"
    940         PASSPHRASE="$4"
    941     fi
    942 
    943     for config_opt in "${CONFIG_OPTS[@]}"; do
    944         eval echo $config_opt=\$$config_opt
    945     done >> "$STORE_CONFIG"
    946 
    947     echo -e "Config options written to '$STORE_CONFIG'"
    948     exit 0
    949 }
    950 
    951 is_config_opt() {
    952     local elem opt="$1"
    953 
    954     for elem in "${CONFIG_OPTS[@]}"; do
    955         if [[ "$elem" == "$opt" ]]; then
    956             return 0
    957         fi
    958     done
    959     return 1
    960 }
    961 
    962 # Load options from config file
    963 read_config() {
    964     local opt_name opt_val line
    965 
    966     while read line; do
    967         # Read switches and their values
    968         opt_name="${line%%=*}"
    969         opt_val="${line#*=}"
    970         if is_config_opt "$opt_name" ; then
    971             eval $opt_name="\$opt_val"
    972         else
    973             echo "WARN: Unrecognized configuration entry $opt_name" >&2
    974         fi
    975     done < "$LOAD_CONFIG"
    976 }
    977 
    978 
    979 ARGS=( "$@" )
    980 
    981 # Preprocessing for --config before option-parsing starts
    982 for ((i=0; i<$#; i++)); do
    983     if [[ "${ARGS[i]}" = "--config" ]]; then
    984         if [[ -f "${ARGS[i+1]}" ]]; then
    985             LOAD_CONFIG="${ARGS[i+1]}"
    986             read_config
    987         else
    988             echo "ERROR: No config file found at given location" >&2
    989             exit 1
    990         fi
    991         break
    992     fi
    993 done
    994 
    995 GETOPT_ARGS=$(getopt -o hc:w:g:dnm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","isolate-clients","ieee80211n","ht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","daemon","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","mkconfig:","config:" -n "$PROGNAME" -- "$@")
    996 [[ $? -ne 0 ]] && exit 1
    997 eval set -- "$GETOPT_ARGS"
    998 
    999 while :; do
   1000     case "$1" in
   1001         -h|--help)
   1002             usage
   1003             exit 0
   1004             ;;
   1005         --version)
   1006             echo $VERSION
   1007             exit 0
   1008             ;;
   1009         --hidden)
   1010             shift
   1011             HIDDEN=1
   1012             ;;
   1013         --isolate-clients)
   1014             shift
   1015             ISOLATE_CLIENTS=1
   1016             ;;
   1017         -c)
   1018             shift
   1019             CHANNEL="$1"
   1020             shift
   1021             ;;
   1022         -w)
   1023             shift
   1024             WPA_VERSION="$1"
   1025             [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2
   1026             shift
   1027             ;;
   1028         -g)
   1029             shift
   1030             GATEWAY="$1"
   1031             shift
   1032             ;;
   1033         -d)
   1034             shift
   1035             ETC_HOSTS=1
   1036             ;;
   1037         -n)
   1038             shift
   1039             SHARE_METHOD=none
   1040             ;;
   1041         -m)
   1042             shift
   1043             SHARE_METHOD="$1"
   1044             shift
   1045             ;;
   1046         --ieee80211n)
   1047             shift
   1048             IEEE80211N=1
   1049             ;;
   1050         --ht_capab)
   1051             shift
   1052             HT_CAPAB="$1"
   1053             shift
   1054             ;;
   1055         --driver)
   1056             shift
   1057             DRIVER="$1"
   1058             shift
   1059             ;;
   1060         --no-virt)
   1061             shift
   1062             NO_VIRT=1
   1063             ;;
   1064         --fix-unmanaged)
   1065             shift
   1066             FIX_UNMANAGED=1
   1067             ;;
   1068         --country)
   1069             shift
   1070             COUNTRY="$1"
   1071             shift
   1072             ;;
   1073         --freq-band)
   1074             shift
   1075             FREQ_BAND="$1"
   1076             shift
   1077             ;;
   1078         --mac)
   1079             shift
   1080             NEW_MACADDR="$1"
   1081             shift
   1082             ;;
   1083         --dhcp-dns)
   1084             shift
   1085             DHCP_DNS="$1"
   1086             shift
   1087             ;;
   1088         --daemon)
   1089             shift
   1090             DAEMONIZE=1
   1091             ;;
   1092         --stop)
   1093             shift
   1094             STOP_ID="$1"
   1095             shift
   1096             ;;
   1097         --list)
   1098             shift
   1099             LIST_RUNNING=1
   1100             echo -e "WARN: --list is deprecated, use --list-running instead.\n" >&2
   1101             ;;
   1102         --list-running)
   1103             shift
   1104             LIST_RUNNING=1
   1105             ;;
   1106         --list-clients)
   1107             shift
   1108             LIST_CLIENTS_ID="$1"
   1109             shift
   1110             ;;
   1111         --no-haveged)
   1112             shift
   1113             NO_HAVEGED=1
   1114             ;;
   1115         --psk)
   1116             shift
   1117             USE_PSK=1
   1118             ;;
   1119         --no-dns)
   1120             shift
   1121             NO_DNS=1
   1122             ;;
   1123         --redirect-to-localhost)
   1124             shift
   1125             REDIRECT_TO_LOCALHOST=1
   1126             ;;
   1127         --hostapd-debug)
   1128             shift
   1129             if [ "x$1" = "x1" ]; then
   1130                 HOSTAPD_DEBUG_ARGS="-d"
   1131             elif [ "x$1" = "x2" ]; then
   1132                 HOSTAPD_DEBUG_ARGS="-dd"
   1133             else
   1134                 printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1"
   1135                 exit 1
   1136             fi
   1137             shift
   1138             ;;
   1139         --mkconfig)
   1140             shift
   1141             STORE_CONFIG="$1"
   1142             shift
   1143             ;;
   1144         --config)
   1145             shift
   1146             shift
   1147             ;;
   1148         --)
   1149             shift
   1150             break
   1151             ;;
   1152     esac
   1153 done
   1154 
   1155 # Load positional args from config file, if needed
   1156 if [[ -n "$LOAD_CONFIG" && $# -eq 0 ]]; then
   1157     i=0
   1158     # set arguments in order
   1159     for x in WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE; do
   1160         if eval "[[ -n \"\$${x}\" ]]"; then
   1161             eval "set -- \"\${@:1:$i}\" \"\$${x}\""
   1162             ((i++))
   1163         fi
   1164         # we unset the variable to avoid any problems later
   1165         eval "unset $x"
   1166     done
   1167 fi
   1168 
   1169 # Check if required number of positional args are present
   1170 if [[ $# -lt 1 && $FIX_UNMANAGED -eq 0  && -z "$STOP_ID" &&
   1171       $LIST_RUNNING -eq 0 && -z "$LIST_CLIENTS_ID" ]]; then
   1172     usage >&2
   1173     exit 1
   1174 fi
   1175 
   1176 trap "cleanup_lock" EXIT
   1177 
   1178 if ! init_lock; then
   1179     echo "ERROR: Failed to initialize lock" >&2
   1180     exit 1
   1181 fi
   1182 
   1183 # if the user press ctrl+c or we get USR1 signal
   1184 # then run clean_exit()
   1185 trap "clean_exit" SIGINT SIGUSR1
   1186 # if we get USR2 signal then run die().
   1187 trap "die" SIGUSR2
   1188 
   1189 [[ -n "$STORE_CONFIG" ]] && write_config "$@"
   1190 
   1191 if [[ $LIST_RUNNING -eq 1 ]]; then
   1192     echo -e "List of running $PROGNAME instances:\n"
   1193     list_running
   1194     exit 0
   1195 fi
   1196 
   1197 if [[ -n "$LIST_CLIENTS_ID" ]]; then
   1198     list_clients "$LIST_CLIENTS_ID"
   1199     exit 0
   1200 fi
   1201 
   1202 if [[ $(id -u) -ne 0 ]]; then
   1203     echo "You must run it as root." >&2
   1204     exit 1
   1205 fi
   1206 
   1207 if [[ -n "$STOP_ID" ]]; then
   1208     echo "Trying to kill $PROGNAME instance associated with $STOP_ID..."
   1209     send_stop "$STOP_ID"
   1210     exit 0
   1211 fi
   1212 
   1213 if [[ $FIX_UNMANAGED -eq 1 ]]; then
   1214     echo "Trying to fix unmanaged status in NetworkManager..."
   1215     networkmanager_fix_unmanaged
   1216     exit 0
   1217 fi
   1218 
   1219 if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then
   1220     echo "Running as Daemon..."
   1221     # run a detached create_ap
   1222     RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" &
   1223     exit 0
   1224 fi
   1225 
   1226 if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then
   1227     echo "ERROR: Invalid frequency band" >&2
   1228     exit 1
   1229 fi
   1230 
   1231 if [[ $CHANNEL == default ]]; then
   1232     if [[ $FREQ_BAND == 2.4 ]]; then
   1233         CHANNEL=1
   1234     else
   1235         CHANNEL=36
   1236     fi
   1237 fi
   1238 
   1239 if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then
   1240     echo "Channel number is greater than 14, assuming 5GHz frequency band"
   1241     FREQ_BAND=5
   1242 fi
   1243 
   1244 WIFI_IFACE=$1
   1245 
   1246 if ! is_wifi_interface ${WIFI_IFACE}; then
   1247     echo "ERROR: '${WIFI_IFACE}' is not a WiFi interface" >&2
   1248     exit 1
   1249 fi
   1250 
   1251 if ! can_be_ap ${WIFI_IFACE}; then
   1252     echo "ERROR: Your adapter does not support AP (master) mode" >&2
   1253     exit 1
   1254 fi
   1255 
   1256 if ! can_be_sta_and_ap ${WIFI_IFACE}; then
   1257     if is_wifi_connected ${WIFI_IFACE}; then
   1258         echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2
   1259         exit 1
   1260     elif [[ $NO_VIRT -eq 0 ]]; then
   1261         echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2
   1262         NO_VIRT=1
   1263     fi
   1264 fi
   1265 
   1266 if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then
   1267     if ! strings $(which hostapd) | grep -m1 rtl871xdrv > /dev/null 2>&1; then
   1268         echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2
   1269         exit 1
   1270     fi
   1271 
   1272     if [[ $DRIVER != "rtl871xdrv" ]]; then
   1273         echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2
   1274         DRIVER=rtl871xdrv
   1275     fi
   1276 fi
   1277 
   1278 if [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" != "none" ]]; then
   1279     echo "ERROR: Wrong Internet sharing method" >&2
   1280     echo
   1281     usage >&2
   1282     exit 1
   1283 fi
   1284 
   1285 if [[ -n "$NEW_MACADDR" ]]; then
   1286     if ! is_macaddr "$NEW_MACADDR"; then
   1287         echo "ERROR: '${NEW_MACADDR}' is not a valid MAC address" >&2
   1288         exit 1
   1289     fi
   1290 
   1291     if ! is_unicast_macaddr "$NEW_MACADDR"; then
   1292         echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2
   1293         exit 1
   1294     fi
   1295 
   1296     if [[ $(get_all_macaddrs | grep -c ${NEW_MACADDR}) -ne 0 ]]; then
   1297         echo "WARN: MAC address '${NEW_MACADDR}' already exists. Because of this, you may encounter some problems" >&2
   1298     fi
   1299 fi
   1300 
   1301 if [[ "$SHARE_METHOD" != "none" ]]; then
   1302     MIN_REQUIRED_ARGS=2
   1303 else
   1304     MIN_REQUIRED_ARGS=1
   1305 fi
   1306 
   1307 if [[ $# -gt $MIN_REQUIRED_ARGS ]]; then
   1308     if [[ "$SHARE_METHOD" != "none" ]]; then
   1309         if [[ $# -ne 3 && $# -ne 4 ]]; then
   1310             usage >&2
   1311             exit 1
   1312         fi
   1313         INTERNET_IFACE="$2"
   1314         SSID="$3"
   1315         PASSPHRASE="$4"
   1316     else
   1317         if [[ $# -ne 2 && $# -ne 3 ]]; then
   1318             usage >&2
   1319             exit 1
   1320         fi
   1321         SSID="$2"
   1322         PASSPHRASE="$3"
   1323     fi
   1324 else
   1325     if [[ "$SHARE_METHOD" != "none" ]]; then
   1326         if [[ $# -ne 2 ]]; then
   1327             usage >&2
   1328             exit 1
   1329         fi
   1330         INTERNET_IFACE="$2"
   1331     fi
   1332     if tty -s; then
   1333         while :; do
   1334             read -p "SSID: " SSID
   1335             if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
   1336                 echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
   1337                 continue
   1338             fi
   1339             break
   1340         done
   1341         while :; do
   1342             if [[ $USE_PSK -eq 0 ]]; then
   1343                 read -p "Passphrase: " -s PASSPHRASE
   1344                 echo
   1345                 if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
   1346                     echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
   1347                     continue
   1348                 fi
   1349                 read -p "Retype passphrase: " -s PASSPHRASE2
   1350                 echo
   1351                 if [[ "$PASSPHRASE" != "$PASSPHRASE2" ]]; then
   1352                     echo "Passphrases do not match."
   1353                 else
   1354                     break
   1355                 fi
   1356             else
   1357                 read -p "PSK: " PASSPHRASE
   1358                 echo
   1359                 if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
   1360                     echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
   1361                     continue
   1362                 fi
   1363             fi
   1364         done
   1365     else
   1366         read SSID
   1367         read PASSPHRASE
   1368     fi
   1369 fi
   1370 
   1371 if [[ "$SHARE_METHOD" != "none" ]] && ! is_interface $INTERNET_IFACE; then
   1372     echo "ERROR: '${INTERNET_IFACE}' is not an interface" >&2
   1373     exit 1
   1374 fi
   1375 
   1376 if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
   1377     echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
   1378     exit 1
   1379 fi
   1380 
   1381 if [[ $USE_PSK -eq 0 ]]; then
   1382     if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
   1383         echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
   1384         exit 1
   1385     fi
   1386 elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
   1387     echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
   1388     exit 1
   1389 fi
   1390 
   1391 if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then
   1392     if [[ -n "$PASSPHRASE" ]]; then
   1393         echo "WARN: Realtek drivers usually have problems with WPA1, enabling -w 2" >&2
   1394         WPA_VERSION=2
   1395     fi
   1396     echo "WARN: If AP doesn't work, please read: howto/realtek.md" >&2
   1397 fi
   1398 
   1399 if [[ $NO_VIRT -eq 1 && "$WIFI_IFACE" == "$INTERNET_IFACE" ]]; then
   1400     echo -n "ERROR: You can not share your connection from the same" >&2
   1401     echo " interface if you are using --no-virt option." >&2
   1402     exit 1
   1403 fi
   1404 
   1405 mutex_lock
   1406 trap "cleanup" EXIT
   1407 CONFDIR=$(mktemp -d /tmp/create_ap.${WIFI_IFACE}.conf.XXXXXXXX)
   1408 echo "Config dir: $CONFDIR"
   1409 echo "PID: $$"
   1410 echo $$ > $CONFDIR/pid
   1411 
   1412 # to make --list-running work from any user, we must give read
   1413 # permissions to $CONFDIR and $CONFDIR/pid
   1414 chmod 755 $CONFDIR
   1415 chmod 444 $CONFDIR/pid
   1416 
   1417 COMMON_CONFDIR=/tmp/create_ap.common.conf
   1418 mkdir -p $COMMON_CONFDIR
   1419 
   1420 if [[ "$SHARE_METHOD" == "nat" ]]; then
   1421     echo $INTERNET_IFACE > $CONFDIR/nat_internet_iface
   1422     cp -n /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding \
   1423        $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding
   1424 fi
   1425 cp -n /proc/sys/net/ipv4/ip_forward $COMMON_CONFDIR
   1426 if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
   1427     cp -n /proc/sys/net/bridge/bridge-nf-call-iptables $COMMON_CONFDIR
   1428 fi
   1429 mutex_unlock
   1430 
   1431 if [[ "$SHARE_METHOD" == "bridge" ]]; then
   1432     if is_bridge_interface $INTERNET_IFACE; then
   1433         BRIDGE_IFACE=$INTERNET_IFACE
   1434     else
   1435         BRIDGE_IFACE=$(alloc_new_iface br)
   1436     fi
   1437 fi
   1438 
   1439 if [[ $USE_IWCONFIG -eq 0 ]]; then
   1440     iw dev ${WIFI_IFACE} set power_save off
   1441 fi
   1442 
   1443 if [[ $NO_VIRT -eq 0 ]]; then
   1444     VWIFI_IFACE=$(alloc_new_iface ap)
   1445 
   1446     # in NetworkManager 0.9.9 and above we can set the interface as unmanaged without
   1447     # the need of MAC address, so we set it before we create the virtual interface.
   1448     if networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]]; then
   1449         echo -n "Network Manager found, set ${VWIFI_IFACE} as unmanaged device... "
   1450         networkmanager_add_unmanaged ${VWIFI_IFACE}
   1451         # do not call networkmanager_wait_until_unmanaged because interface does not
   1452         # exist yet
   1453         echo "DONE"
   1454     fi
   1455 
   1456     if is_wifi_connected ${WIFI_IFACE}; then
   1457         WIFI_IFACE_FREQ=$(iw dev ${WIFI_IFACE} link | grep -i freq | awk '{print $2}')
   1458         WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel ${WIFI_IFACE_FREQ})
   1459         echo -n "${WIFI_IFACE} is already associated with channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)"
   1460         if is_5ghz_frequency $WIFI_IFACE_FREQ; then
   1461             FREQ_BAND=5
   1462         else
   1463             FREQ_BAND=2.4
   1464         fi
   1465         if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then
   1466             echo ", fallback to channel ${WIFI_IFACE_CHANNEL}"
   1467             CHANNEL=$WIFI_IFACE_CHANNEL
   1468         else
   1469             echo
   1470         fi
   1471     fi
   1472 
   1473     VIRTDIEMSG="Maybe your WiFi adapter does not fully support virtual interfaces.
   1474        Try again with --no-virt."
   1475     echo -n "Creating a virtual WiFi interface... "
   1476 
   1477     if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type managed; then
   1478         # now we can call networkmanager_wait_until_unmanaged
   1479         networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]] && networkmanager_wait_until_unmanaged ${VWIFI_IFACE}
   1480         echo "${VWIFI_IFACE} created."
   1481     else
   1482         VWIFI_IFACE=
   1483         die "$VIRTDIEMSG"
   1484     fi
   1485     OLD_MACADDR=$(get_macaddr ${VWIFI_IFACE})
   1486     if [[ -z "$NEW_MACADDR" && $(get_all_macaddrs | grep -c ${OLD_MACADDR}) -ne 1 ]]; then
   1487         NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE})
   1488     fi
   1489     WIFI_IFACE=${VWIFI_IFACE}
   1490 else
   1491     OLD_MACADDR=$(get_macaddr ${WIFI_IFACE})
   1492 fi
   1493 
   1494 mutex_lock
   1495 echo $WIFI_IFACE > $CONFDIR/wifi_iface
   1496 chmod 444 $CONFDIR/wifi_iface
   1497 mutex_unlock
   1498 
   1499 can_transmit_to_channel ${WIFI_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz."
   1500 
   1501 if networkmanager_is_running && ! networkmanager_iface_is_unmanaged ${WIFI_IFACE}; then
   1502     echo -n "Network Manager found, set ${WIFI_IFACE} as unmanaged device... "
   1503     networkmanager_add_unmanaged ${WIFI_IFACE}
   1504     networkmanager_wait_until_unmanaged ${WIFI_IFACE}
   1505     echo "DONE"
   1506 fi
   1507 
   1508 [[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!"
   1509 
   1510 [[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!"
   1511 
   1512 # hostapd config
   1513 cat << EOF > $CONFDIR/hostapd.conf
   1514 beacon_int=100
   1515 ssid=${SSID}
   1516 interface=${WIFI_IFACE}
   1517 driver=${DRIVER}
   1518 channel=${CHANNEL}
   1519 ctrl_interface=$CONFDIR/hostapd_ctrl
   1520 ctrl_interface_group=0
   1521 ignore_broadcast_ssid=$HIDDEN
   1522 ap_isolate=$ISOLATE_CLIENTS
   1523 EOF
   1524 
   1525 if [[ -n $COUNTRY ]]; then
   1526     [[ $USE_IWCONFIG -eq 0 ]] && iw reg set $COUNTRY
   1527     echo "country_code=${COUNTRY}" >> $CONFDIR/hostapd.conf
   1528 fi
   1529 
   1530 if [[ $FREQ_BAND == 2.4 ]]; then
   1531     echo "hw_mode=g" >> $CONFDIR/hostapd.conf
   1532 else
   1533     echo "hw_mode=a" >> $CONFDIR/hostapd.conf
   1534 fi
   1535 
   1536 if [[ $IEEE80211N -eq 1 ]]; then
   1537     cat << EOF >> $CONFDIR/hostapd.conf
   1538 ieee80211n=1
   1539 wmm_enabled=1
   1540 ht_capab=${HT_CAPAB}
   1541 EOF
   1542 fi
   1543 
   1544 if [[ -n "$PASSPHRASE" ]]; then
   1545     [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3
   1546     if [[ $USE_PSK -eq 0 ]]; then
   1547         WPA_KEY_TYPE=passphrase
   1548     else
   1549         WPA_KEY_TYPE=psk
   1550     fi
   1551     cat << EOF >> $CONFDIR/hostapd.conf
   1552 wpa=${WPA_VERSION}
   1553 wpa_${WPA_KEY_TYPE}=${PASSPHRASE}
   1554 wpa_key_mgmt=WPA-PSK
   1555 wpa_pairwise=TKIP CCMP
   1556 rsn_pairwise=CCMP
   1557 EOF
   1558 fi
   1559 
   1560 if [[ "$SHARE_METHOD" == "bridge" ]]; then
   1561     echo "bridge=${BRIDGE_IFACE}" >> $CONFDIR/hostapd.conf
   1562 else
   1563     # dnsmasq config (dhcp + dns)
   1564     DNSMASQ_VER=$(dnsmasq -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+')
   1565     version_cmp $DNSMASQ_VER 2.63
   1566     if [[ $? -eq 1 ]]; then
   1567         DNSMASQ_BIND=bind-interfaces
   1568     else
   1569         DNSMASQ_BIND=bind-dynamic
   1570     fi
   1571     if [[ "$DHCP_DNS" == "gateway" ]]; then
   1572         DHCP_DNS="$GATEWAY"
   1573     fi
   1574     cat << EOF > $CONFDIR/dnsmasq.conf
   1575 listen-address=${GATEWAY}
   1576 ${DNSMASQ_BIND}
   1577 dhcp-range=${GATEWAY%.*}.1,${GATEWAY%.*}.254,255.255.255.0,24h
   1578 dhcp-option-force=option:router,${GATEWAY}
   1579 dhcp-option-force=option:dns-server,${DHCP_DNS}
   1580 EOF
   1581     MTU=$(get_mtu $INTERNET_IFACE)
   1582     [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> $CONFDIR/dnsmasq.conf
   1583     [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf
   1584     if [[ "$SHARE_METHOD" == "none" && "$REDIRECT_TO_LOCALHOST" == "1" ]]; then
   1585         cat << EOF >> $CONFDIR/dnsmasq.conf
   1586 address=/#/$GATEWAY
   1587 EOF
   1588     fi
   1589 fi
   1590 
   1591 # initialize WiFi interface
   1592 if [[ $NO_VIRT -eq 0 && -n "$NEW_MACADDR" ]]; then
   1593     ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die "$VIRTDIEMSG"
   1594 fi
   1595 
   1596 ip link set down dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
   1597 ip addr flush ${WIFI_IFACE} || die "$VIRTDIEMSG"
   1598 
   1599 if [[ $NO_VIRT -eq 1 && -n "$NEW_MACADDR" ]]; then
   1600     ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die
   1601 fi
   1602 
   1603 if [[ "$SHARE_METHOD" != "bridge" ]]; then
   1604     ip link set up dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
   1605     ip addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
   1606 fi
   1607 
   1608 # enable Internet sharing
   1609 if [[ "$SHARE_METHOD" != "none" ]]; then
   1610     echo "Sharing Internet using method: $SHARE_METHOD"
   1611     if [[ "$SHARE_METHOD" == "nat" ]]; then
   1612         iptables -t nat -I POSTROUTING -o ${INTERNET_IFACE} -s ${GATEWAY%.*}.0/24 -j MASQUERADE || die
   1613         iptables -I FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT || die
   1614         iptables -I FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT || die
   1615         echo 1 > /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding || die
   1616         echo 1 > /proc/sys/net/ipv4/ip_forward || die
   1617         # to enable clients to establish PPTP connections we must
   1618         # load nf_nat_pptp module
   1619         modprobe nf_nat_pptp > /dev/null 2>&1
   1620     elif [[ "$SHARE_METHOD" == "bridge" ]]; then
   1621         # disable iptables rules for bridged interfaces
   1622         if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
   1623             echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables
   1624         fi
   1625 
   1626         # to initialize the bridge interface correctly we need to do the following:
   1627         #
   1628         # 1) save the IPs and route table of INTERNET_IFACE
   1629         # 2) if NetworkManager is running set INTERNET_IFACE as unmanaged
   1630         # 3) create BRIDGE_IFACE and attach INTERNET_IFACE to it
   1631         # 4) set the previously saved IPs and route table to BRIDGE_IFACE
   1632         #
   1633         # we need the above because BRIDGE_IFACE is the master interface from now on
   1634         # and it must know where is connected, otherwise connection is lost.
   1635         if ! is_bridge_interface $INTERNET_IFACE; then
   1636             echo -n "Create a bridge interface... "
   1637             OLD_IFS="$IFS"
   1638             IFS=$'\n'
   1639 
   1640             IP_ADDRS=( $(ip addr show $INTERNET_IFACE | grep -A 1 -E 'inet[[:blank:]]' | paste - -) )
   1641             ROUTE_ADDRS=( $(ip route show dev $INTERNET_IFACE) )
   1642 
   1643             IFS="$OLD_IFS"
   1644 
   1645             if networkmanager_is_running; then
   1646                 networkmanager_add_unmanaged $INTERNET_IFACE
   1647                 networkmanager_wait_until_unmanaged $INTERNET_IFACE
   1648             fi
   1649 
   1650             # create bridge interface
   1651             ip link add name $BRIDGE_IFACE type bridge || die
   1652             ip link set dev $BRIDGE_IFACE up || die
   1653             # set 0ms forward delay
   1654             echo 0 > /sys/class/net/$BRIDGE_IFACE/bridge/forward_delay
   1655 
   1656             # attach internet interface to bridge interface
   1657             ip link set dev $INTERNET_IFACE promisc on || die
   1658             ip link set dev $INTERNET_IFACE up || die
   1659             ip link set dev $INTERNET_IFACE master $BRIDGE_IFACE || die
   1660 
   1661             ip addr flush $INTERNET_IFACE
   1662             for x in "${IP_ADDRS[@]}"; do
   1663                 x="${x/inet/}"
   1664                 x="${x/secondary/}"
   1665                 x="${x/dynamic/}"
   1666                 x=$(echo $x | sed 's/\([0-9]\)sec/\1/g')
   1667                 x="${x/${INTERNET_IFACE}/}"
   1668                 ip addr add $x dev $BRIDGE_IFACE || die
   1669             done
   1670 
   1671             # remove any existing entries that were added from 'ip addr add'
   1672             ip route flush dev $INTERNET_IFACE
   1673             ip route flush dev $BRIDGE_IFACE
   1674 
   1675             # we must first add the entries that specify the subnets and then the
   1676             # gateway entry, otherwise 'ip addr add' will return an error
   1677             for x in "${ROUTE_ADDRS[@]}"; do
   1678                 [[ "$x" == default* ]] && continue
   1679                 ip route add $x dev $BRIDGE_IFACE || die
   1680             done
   1681 
   1682             for x in "${ROUTE_ADDRS[@]}"; do
   1683                 [[ "$x" != default* ]] && continue
   1684                 ip route add $x dev $BRIDGE_IFACE || die
   1685             done
   1686 
   1687             echo "$BRIDGE_IFACE created."
   1688         fi
   1689     fi
   1690 else
   1691     echo "No Internet sharing"
   1692 fi
   1693 
   1694 # start dhcp + dns (optional)
   1695 if [[ "$SHARE_METHOD" != "bridge" ]]; then
   1696     if [[ $NO_DNS -eq 0 ]]; then
   1697         DNS_PORT=53
   1698         iptables -I INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT || die
   1699         iptables -I INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT || die
   1700     else
   1701         DNS_PORT=0
   1702     fi
   1703     iptables -I INPUT -p udp -m udp --dport 67 -j ACCEPT || die
   1704 
   1705     if which complain > /dev/null 2>&1; then
   1706         # openSUSE's apparmor does not allow dnsmasq to read files.
   1707         # remove restriction.
   1708         complain dnsmasq
   1709     fi
   1710 
   1711     umask 0033
   1712     dnsmasq -C $CONFDIR/dnsmasq.conf -x $CONFDIR/dnsmasq.pid -l $CONFDIR/dnsmasq.leases -p $DNS_PORT || die
   1713     umask $SCRIPT_UMASK
   1714 fi
   1715 
   1716 # start access point
   1717 echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl"
   1718 
   1719 if [[ $NO_HAVEGED -eq 0 ]]; then
   1720     haveged_watchdog &
   1721     HAVEGED_WATCHDOG_PID=$!
   1722 fi
   1723 
   1724 # start hostapd (use stdbuf for no delayed output in porgrams that redirect stdout)
   1725 stdbuf -oL hostapd $HOSTAPD_DEBUG_ARGS $CONFDIR/hostapd.conf &
   1726 HOSTAPD_PID=$!
   1727 echo $HOSTAPD_PID > $CONFDIR/hostapd.pid
   1728 
   1729 if ! wait $HOSTAPD_PID; then
   1730     echo -e "\nError: Failed to run hostapd, maybe a program is interfering." >&2
   1731     if networkmanager_is_running; then
   1732         echo "If an error like 'n80211: Could not configure driver mode' was thrown" >&2
   1733         echo "try running the following before starting create_ap:" >&2
   1734         if [[ $NM_OLDER_VERSION -eq 1 ]]; then
   1735             echo "    nmcli nm wifi off" >&2
   1736         else
   1737             echo "    nmcli r wifi off" >&2
   1738         fi
   1739         echo "    rfkill unblock wlan" >&2
   1740     fi
   1741     die
   1742 fi
   1743 
   1744 clean_exit
   1745 
   1746 # Local Variables:
   1747 # tab-width: 4
   1748 # indent-tabs-mode: nil
   1749 # End:
   1750 
   1751 # vim: et sts=4 sw=4